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:
authorColin Basnett <cmbasnett@gmail.com>2022-06-19 05:00:48 +0300
committerColin Basnett <cmbasnett@gmail.com>2022-06-19 05:00:48 +0300
commit579784eff99a57e1b827ff71d921bd07db7649fb (patch)
treefef476af48feed59a22d7113f27e0e2d44ffaea5
parenta9077cefd4482fb84093fc447f06ccbd2b0ec842 (diff)
parent600c391a6559ae3113ecbf505490ace8ef1da828 (diff)
Merge branch 'master' into feature-imformat
-rw-r--r--CMakeLists.txt3
-rw-r--r--build_files/build_environment/CMakeLists.txt2
-rw-r--r--build_files/build_environment/cmake/llvm.cmake9
-rwxr-xr-xbuild_files/build_environment/install_deps.sh225
-rw-r--r--build_files/build_environment/windows/build_deps.cmd11
-rwxr-xr-xbuild_files/cmake/cmake_netbeans_project.py2
-rwxr-xr-xbuild_files/cmake/cmake_qtcreator_project.py2
-rw-r--r--build_files/cmake/cmake_static_check_clang_array.py2
-rw-r--r--build_files/cmake/cmake_static_check_cppcheck.py2
-rw-r--r--build_files/cmake/cmake_static_check_smatch.py2
-rw-r--r--build_files/cmake/cmake_static_check_sparse.py2
-rw-r--r--build_files/cmake/cmake_static_check_splint.py2
-rw-r--r--build_files/cmake/config/blender_lite.cmake3
-rwxr-xr-xbuild_files/cmake/project_info.py2
-rw-r--r--build_files/cmake/project_source_info.py2
-rwxr-xr-xbuild_files/package_spec/build_archive.py2
-rwxr-xr-xdoc/manpage/blender.1.py2
-rw-r--r--doc/python_api/requirements.txt12
-rw-r--r--doc/python_api/rst/info_best_practice.rst9
-rw-r--r--doc/python_api/rst_from_bmesh_opdefines.py2
-rw-r--r--doc/python_api/sphinx_changelog_gen.py2
-rw-r--r--doc/python_api/sphinx_doc_gen.py2
-rw-r--r--doc/python_api/sphinx_doc_gen_monkeypatch.py2
-rw-r--r--extern/draco/README.blender4
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc95
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h31
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc113
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h38
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_transform.cc25
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_transform.h36
-rw-r--r--extern/draco/draco/src/draco/attributes/geometry_attribute.cc12
-rw-r--r--extern/draco/draco/src/draco/attributes/geometry_attribute.h42
-rw-r--r--extern/draco/draco/src/draco/attributes/point_attribute.cc43
-rw-r--r--extern/draco/draco/src/draco/attributes/point_attribute.h6
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc22
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc16
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc19
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc15
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h6
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h133
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h4
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h9
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h9
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h7
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc33
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h4
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h6
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h18
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h2
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc4
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc15
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc3
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc44
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h3
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc13
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc64
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h8
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc19
-rw-r--r--extern/draco/draco/src/draco/compression/config/compression_shared.h3
-rw-r--r--extern/draco/draco/src/draco/compression/config/draco_options.h6
-rw-r--r--extern/draco/draco/src/draco/compression/decode.cc5
-rw-r--r--extern/draco/draco/src/draco/compression/encode_base.h8
-rw-r--r--extern/draco/draco/src/draco/compression/entropy/ans.h7
-rw-r--r--extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h9
-rw-r--r--extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h4
-rw-r--r--extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc2
-rw-r--r--extern/draco/draco/src/draco/compression/expert_encode.cc2
-rw-r--r--extern/draco/draco/src/draco/compression/expert_encode.h6
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc31
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc1
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc2
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h1
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h2
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h7
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc7
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc4
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h1
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h2
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h2
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h5
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h5
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc27
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h4
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h3
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h3
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h2
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc10
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc14
-rw-r--r--extern/draco/draco/src/draco/core/bounding_box.cc13
-rw-r--r--extern/draco/draco/src/draco/core/bounding_box.h42
-rw-r--r--extern/draco/draco/src/draco/core/cycle_timer.cc14
-rw-r--r--extern/draco/draco/src/draco/core/cycle_timer.h7
-rw-r--r--extern/draco/draco/src/draco/core/data_buffer.cc2
-rw-r--r--extern/draco/draco/src/draco/core/decoder_buffer.h12
-rw-r--r--extern/draco/draco/src/draco/core/draco_index_type_vector.h3
-rw-r--r--extern/draco/draco/src/draco/core/draco_version.h2
-rw-r--r--extern/draco/draco/src/draco/core/macros.h27
-rw-r--r--extern/draco/draco/src/draco/core/options.h2
-rw-r--r--extern/draco/draco/src/draco/core/status.h4
-rw-r--r--extern/draco/draco/src/draco/core/varint_decoding.h1
-rw-r--r--extern/draco/draco/src/draco/core/vector_d.h14
-rw-r--r--extern/draco/draco/src/draco/draco_features.h2
-rw-r--r--extern/draco/draco/src/draco/mesh/corner_table.cc7
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh.h4
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h6
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh_cleanup.cc321
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh_cleanup.h27
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh_misc_functions.h1
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh_stripifier.h8
-rw-r--r--extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc2
-rw-r--r--extern/draco/draco/src/draco/metadata/geometry_metadata.cc15
-rw-r--r--extern/draco/draco/src/draco/metadata/geometry_metadata.h2
-rw-r--r--extern/draco/draco/src/draco/metadata/metadata.cc8
-rw-r--r--extern/draco/draco/src/draco/metadata/metadata.h1
-rw-r--r--extern/draco/draco/src/draco/metadata/metadata_decoder.cc10
-rw-r--r--extern/draco/draco/src/draco/point_cloud/point_cloud.cc16
-rw-r--r--extern/draco/patches/blender.patch30
-rw-r--r--extern/draco/src/common.cpp28
-rw-r--r--extern/draco/src/common.h2
-rw-r--r--extern/draco/src/decoder.cpp74
-rw-r--r--extern/draco/src/decoder.h36
-rw-r--r--extern/draco/src/encoder.cpp97
-rw-r--r--extern/draco/src/encoder.h33
-rw-r--r--intern/cycles/blender/addon/__init__.py2
-rw-r--r--intern/cycles/blender/addon/camera.py2
-rw-r--r--intern/cycles/blender/addon/engine.py2
-rw-r--r--intern/cycles/blender/addon/operators.py2
-rw-r--r--intern/cycles/blender/addon/osl.py2
-rw-r--r--intern/cycles/blender/addon/presets.py2
-rw-r--r--intern/cycles/blender/addon/properties.py2
-rw-r--r--intern/cycles/blender/addon/ui.py4
-rw-r--r--intern/cycles/blender/addon/version_update.py2
-rw-r--r--intern/cycles/blender/camera.cpp2
-rw-r--r--intern/cycles/blender/curves.cpp4
-rw-r--r--intern/cycles/blender/display_driver.cpp6
-rw-r--r--intern/cycles/blender/image.cpp163
-rw-r--r--intern/cycles/blender/mesh.cpp10
-rw-r--r--intern/cycles/blender/object.cpp2
-rw-r--r--intern/cycles/blender/session.cpp4
-rw-r--r--intern/cycles/blender/sync.cpp4
-rw-r--r--intern/cycles/bvh/build.cpp42
-rw-r--r--intern/cycles/bvh/embree.cpp6
-rw-r--r--intern/cycles/device/cpu/device_impl.cpp22
-rw-r--r--intern/cycles/device/cuda/device.cpp28
-rw-r--r--intern/cycles/device/cuda/device_impl.cpp41
-rw-r--r--intern/cycles/device/cuda/queue.cpp6
-rw-r--r--intern/cycles/device/device.cpp6
-rw-r--r--intern/cycles/device/hip/device.cpp25
-rw-r--r--intern/cycles/device/hip/device_impl.cpp36
-rw-r--r--intern/cycles/device/hip/queue.cpp6
-rw-r--r--intern/cycles/device/metal/bvh.mm2
-rw-r--r--intern/cycles/device/metal/device_impl.h2
-rw-r--r--intern/cycles/device/metal/device_impl.mm24
-rw-r--r--intern/cycles/device/metal/queue.h75
-rw-r--r--intern/cycles/device/metal/queue.mm580
-rw-r--r--intern/cycles/device/metal/util.h2
-rw-r--r--intern/cycles/device/optix/device.cpp6
-rw-r--r--intern/cycles/device/optix/device_impl.cpp14
-rw-r--r--intern/cycles/device/queue.cpp21
-rw-r--r--intern/cycles/hydra/display_driver.cpp85
-rw-r--r--intern/cycles/hydra/display_driver.h9
-rw-r--r--intern/cycles/hydra/output_driver.cpp8
-rw-r--r--intern/cycles/hydra/render_buffer.cpp18
-rw-r--r--intern/cycles/hydra/render_buffer.h4
-rw-r--r--intern/cycles/integrator/denoiser.cpp4
-rw-r--r--intern/cycles/integrator/denoiser_device.cpp2
-rw-r--r--intern/cycles/integrator/denoiser_oidn.cpp4
-rw-r--r--intern/cycles/integrator/path_trace.cpp66
-rw-r--r--intern/cycles/integrator/path_trace_work_gpu.cpp6
-rw-r--r--intern/cycles/integrator/render_scheduler.cpp21
-rw-r--r--intern/cycles/integrator/shader_eval.cpp4
-rw-r--r--intern/cycles/integrator/work_tile_scheduler.cpp6
-rw-r--r--intern/cycles/kernel/bvh/util.h12
-rw-r--r--intern/cycles/kernel/device/gpu/kernel.h4
-rw-r--r--intern/cycles/kernel/geom/attribute.h19
-rw-r--r--intern/cycles/kernel/integrator/shade_background.h2
-rw-r--r--intern/cycles/kernel/osl/services.cpp2
-rw-r--r--intern/cycles/kernel/textures.h2
-rw-r--r--intern/cycles/kernel/types.h12
-rw-r--r--intern/cycles/scene/alembic.cpp2
-rw-r--r--intern/cycles/scene/attribute.cpp52
-rw-r--r--intern/cycles/scene/attribute.h1
-rw-r--r--intern/cycles/scene/camera.cpp4
-rw-r--r--intern/cycles/scene/colorspace.cpp19
-rw-r--r--intern/cycles/scene/constant_fold.cpp13
-rw-r--r--intern/cycles/scene/film.cpp6
-rw-r--r--intern/cycles/scene/geometry.cpp48
-rw-r--r--intern/cycles/scene/image.cpp13
-rw-r--r--intern/cycles/scene/image_oiio.cpp47
-rw-r--r--intern/cycles/scene/image_vdb.cpp2
-rw-r--r--intern/cycles/scene/integrator.cpp6
-rw-r--r--intern/cycles/scene/light.cpp21
-rw-r--r--intern/cycles/scene/object.cpp2
-rw-r--r--intern/cycles/scene/osl.cpp4
-rw-r--r--intern/cycles/scene/particles.cpp2
-rw-r--r--intern/cycles/scene/scene.cpp77
-rw-r--r--intern/cycles/scene/scene.h2
-rw-r--r--intern/cycles/scene/shader_graph.cpp4
-rw-r--r--intern/cycles/scene/shader_nodes.cpp12
-rw-r--r--intern/cycles/scene/svm.cpp12
-rw-r--r--intern/cycles/scene/tables.cpp2
-rw-r--r--intern/cycles/scene/volume.cpp10
-rw-r--r--intern/cycles/session/denoising.cpp2
-rw-r--r--intern/cycles/session/session.cpp6
-rw-r--r--intern/cycles/session/tile.cpp16
-rw-r--r--intern/cycles/test/render_graph_finalize_test.cpp2
-rw-r--r--intern/cycles/util/debug.cpp2
-rw-r--r--intern/cycles/util/image.h20
-rw-r--r--intern/cycles/util/log.h19
-rw-r--r--intern/cycles/util/task.cpp2
-rw-r--r--intern/ghost/CMakeLists.txt14
-rw-r--r--intern/ghost/GHOST_C-api.h48
-rw-r--r--intern/ghost/GHOST_ISystem.h16
-rw-r--r--intern/ghost/GHOST_IWindow.h6
-rw-r--r--intern/ghost/GHOST_Rect.h36
-rw-r--r--intern/ghost/GHOST_Types.h6
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp86
-rw-r--r--intern/ghost/intern/GHOST_CallbackEventConsumer.cpp2
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.cpp10
-rw-r--r--intern/ghost/intern/GHOST_DropTargetX11.cpp19
-rw-r--r--intern/ghost/intern/GHOST_EventPrinter.cpp17
-rw-r--r--intern/ghost/intern/GHOST_ISystem.cpp12
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp11
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerUnix.cpp6
-rw-r--r--intern/ghost/intern/GHOST_System.cpp26
-rw-r--r--intern/ghost/intern/GHOST_System.h4
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp1735
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h38
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp144
-rw-r--r--intern/ghost/intern/GHOST_Window.cpp21
-rw-r--r--intern/ghost/intern/GHOST_Window.h4
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp355
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.h44
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp2
-rw-r--r--intern/ghost/intern/GHOST_Wintab.cpp19
-rw-r--r--intern/ghost/intern/GHOST_Wintab.h2
-rw-r--r--intern/ghost/intern/GHOST_XrAction.cpp37
-rw-r--r--intern/ghost/test/gears/GHOST_C-Test.c12
-rw-r--r--intern/ghost/test/multitest/MultiTest.c6
-rwxr-xr-xrelease/datafiles/alert_icons_update.py2
-rwxr-xr-xrelease/datafiles/blender_icons_geom_update.py2
-rwxr-xr-xrelease/datafiles/blender_icons_update.py2
-rw-r--r--release/datafiles/brushicons/curves_sculpt_add.pngbin0 -> 2697 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_comb.pngbin0 -> 4508 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_cut.pngbin0 -> 3212 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_delete.pngbin0 -> 2297 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_density.pngbin0 -> 2411 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_grow_shrink.pngbin0 -> 3461 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_pinch.pngbin0 -> 3836 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_puff.pngbin0 -> 2393 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_slide.pngbin0 -> 2872 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_smooth.pngbin0 -> 3006 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_snake_hook.pngbin0 -> 2944 bytes
-rw-r--r--release/datafiles/brushicons/paint_select.pngbin0 -> 2660 bytes
-rw-r--r--release/datafiles/colormanagement/config.ocio6
-rwxr-xr-xrelease/datafiles/ctodata.py2
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_density.datbin0 -> 3032 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_slide.datbin0 -> 1394 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_smooth.datbin0 -> 746 bytes
m---------release/datafiles/locale0
-rwxr-xr-xrelease/datafiles/prvicons_update.py2
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c9
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/freestyle/modules/freestyle/shaders.py10
-rw-r--r--release/scripts/freestyle/modules/freestyle/utils.py4
-rw-r--r--release/scripts/freestyle/modules/parameter_editor.py2
-rw-r--r--release/scripts/modules/addon_utils.py2
-rw-r--r--release/scripts/modules/animsys_refactor.py2
-rw-r--r--release/scripts/modules/bl_app_override/__init__.py2
-rw-r--r--release/scripts/modules/bl_app_override/helpers.py2
-rw-r--r--release/scripts/modules/bl_app_template_utils.py2
-rw-r--r--release/scripts/modules/bl_console_utils/__init__.py2
-rw-r--r--release/scripts/modules/bl_console_utils/autocomplete/__init__.py2
-rw-r--r--release/scripts/modules/bl_console_utils/autocomplete/complete_calltip.py2
-rw-r--r--release/scripts/modules/bl_console_utils/autocomplete/complete_import.py2
-rw-r--r--release/scripts/modules/bl_console_utils/autocomplete/complete_namespace.py2
-rw-r--r--release/scripts/modules/bl_console_utils/autocomplete/intellisense.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/__init__.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_extract_messages.py2
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/merge_po.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py4
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings_user.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_cli.py2
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/utils_languages_menu.py2
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/utils_rtl.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_spell_check.py2
-rw-r--r--release/scripts/modules/bl_keymap_utils/__init__.py2
-rw-r--r--release/scripts/modules/bl_keymap_utils/io.py2
-rw-r--r--release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py2
-rw-r--r--release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py6
-rw-r--r--release/scripts/modules/bl_keymap_utils/versioning.py2
-rw-r--r--release/scripts/modules/bl_previews_utils/bl_previews_render.py2
-rw-r--r--release/scripts/modules/bl_rna_utils/data_path.py2
-rw-r--r--release/scripts/modules/bl_ui_utils/bug_report_url.py2
-rwxr-xr-xrelease/scripts/modules/blend_render_info.py124
-rw-r--r--release/scripts/modules/bpy/__init__.py2
-rw-r--r--release/scripts/modules/bpy/ops.py2
-rw-r--r--release/scripts/modules/bpy/path.py2
-rw-r--r--release/scripts/modules/bpy/utils/__init__.py2
-rw-r--r--release/scripts/modules/bpy/utils/previews.py2
-rw-r--r--release/scripts/modules/bpy/utils/toolsystem.py2
-rw-r--r--release/scripts/modules/bpy_extras/__init__.py2
-rw-r--r--release/scripts/modules/bpy_extras/anim_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/asset_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/id_map_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/image_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/io_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/keyconfig_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/mesh_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/node_shader_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/node_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/object_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/view3d_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/wm_utils/progress_report.py2
-rw-r--r--release/scripts/modules/bpy_restrict_state.py2
-rw-r--r--release/scripts/modules/bpy_types.py2
-rw-r--r--release/scripts/modules/console_python.py2
-rw-r--r--release/scripts/modules/console_shell.py2
-rw-r--r--release/scripts/modules/graphviz_export.py2
-rw-r--r--release/scripts/modules/keyingsets_utils.py2
-rw-r--r--release/scripts/modules/nodeitems_utils.py2
-rw-r--r--release/scripts/modules/rna_info.py2
-rw-r--r--release/scripts/modules/rna_keymap_ui.py2
-rw-r--r--release/scripts/modules/rna_prop_ui.py2
-rw-r--r--release/scripts/modules/rna_xml.py2
-rw-r--r--release/scripts/modules/sys_info.py2
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py48
-rw-r--r--release/scripts/startup/bl_operators/__init__.py2
-rw-r--r--release/scripts/startup/bl_operators/add_mesh_torus.py2
-rw-r--r--release/scripts/startup/bl_operators/anim.py2
-rw-r--r--release/scripts/startup/bl_operators/assets.py2
-rw-r--r--release/scripts/startup/bl_operators/bmesh/find_adjacent.py2
-rw-r--r--release/scripts/startup/bl_operators/clip.py2
-rw-r--r--release/scripts/startup/bl_operators/console.py2
-rw-r--r--release/scripts/startup/bl_operators/constraint.py2
-rw-r--r--release/scripts/startup/bl_operators/file.py2
-rw-r--r--release/scripts/startup/bl_operators/freestyle.py2
-rw-r--r--release/scripts/startup/bl_operators/image.py2
-rw-r--r--release/scripts/startup/bl_operators/mesh.py2
-rw-r--r--release/scripts/startup/bl_operators/node.py11
-rw-r--r--release/scripts/startup/bl_operators/object.py44
-rw-r--r--release/scripts/startup/bl_operators/object_align.py2
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py2
-rw-r--r--release/scripts/startup/bl_operators/object_randomize_transform.py2
-rw-r--r--release/scripts/startup/bl_operators/presets.py2
-rw-r--r--release/scripts/startup/bl_operators/rigidbody.py2
-rw-r--r--release/scripts/startup/bl_operators/screen_play_rendered_anim.py2
-rw-r--r--release/scripts/startup/bl_operators/sequencer.py2
-rw-r--r--release/scripts/startup/bl_operators/userpref.py2
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_follow_active.py2
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_lightmap.py2
-rw-r--r--release/scripts/startup/bl_operators/vertexpaint_dirt.py2
-rw-r--r--release/scripts/startup/bl_operators/view3d.py2
-rw-r--r--release/scripts/startup/bl_operators/wm.py6
-rw-r--r--release/scripts/startup/bl_ui/__init__.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_animviz.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_collection.py18
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_armature.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_bone.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_camera.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curves.py7
-rw-r--r--release/scripts/startup/bl_ui/properties_data_empty.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_gpencil.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lattice.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_light.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lightprobe.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py25
-rw-r--r--release/scripts/startup/bl_ui/properties_data_metaball.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_pointcloud.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_data_shaderfx.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_speaker.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_volume.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_freestyle.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_mask_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_material_gpencil.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_object.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_output.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_cloth.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_field.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_fluid.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_rigidbody.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_softbody.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_texture.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_view_layer.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_workspace.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_world.py2
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py5
-rw-r--r--release/scripts/startup/bl_ui/space_console.py2
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py2
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py2
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py2
-rw-r--r--release/scripts/startup/bl_ui/space_image.py2
-rw-r--r--release/scripts/startup/bl_ui/space_info.py2
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py4
-rw-r--r--release/scripts/startup/bl_ui/space_node.py2
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py2
-rw-r--r--release/scripts/startup/bl_ui/space_properties.py2
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py9
-rw-r--r--release/scripts/startup/bl_ui/space_statusbar.py2
-rw-r--r--release/scripts/startup/bl_ui/space_text.py2
-rw-r--r--release/scripts/startup/bl_ui/space_time.py2
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_common.py2
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py11
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py27
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py4
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py32
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py2
-rw-r--r--release/scripts/startup/bl_ui/utils.py2
-rw-r--r--release/scripts/startup/keyingsets_builtins.py2
-rw-r--r--release/scripts/startup/nodeitems_builtins.py30
-rw-r--r--release/windows/manifest/blender.exe.manifest.in5
-rw-r--r--source/blender/blenfont/BLF_api.h15
-rw-r--r--source/blender/blenfont/intern/blf.c28
-rw-r--r--source/blender/blenfont/intern/blf_font.c20
-rw-r--r--source/blender/blenfont/intern/blf_font_default.c43
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c403
-rw-r--r--source/blender/blenfont/intern/blf_internal.h6
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h5
-rw-r--r--source/blender/blenkernel/BKE_attribute.h19
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_callbacks.h6
-rw-r--r--source/blender/blenkernel/BKE_collection.h2
-rw-r--r--source/blender/blenkernel/BKE_constraint.h19
-rw-r--r--source/blender/blenkernel/BKE_context.h7
-rw-r--r--source/blender/blenkernel/BKE_curves.h2
-rw-r--r--source/blender/blenkernel/BKE_curves.hh31
-rw-r--r--source/blender/blenkernel/BKE_curves_utils.hh58
-rw-r--r--source/blender/blenkernel/BKE_customdata.h1
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h35
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h12
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h18
-rw-r--r--source/blender/blenkernel/BKE_main.h10
-rw-r--r--source/blender/blenkernel/BKE_mesh_boolean_convert.hh5
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.hh59
-rw-r--r--source/blender/blenkernel/BKE_node.h3
-rw-r--r--source/blender/blenkernel/BKE_paint.h4
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h3
-rw-r--r--source/blender/blenkernel/BKE_pointcloud.h3
-rw-r--r--source/blender/blenkernel/BKE_subdiv_modifier.h36
-rw-r--r--source/blender/blenkernel/BKE_unit.h4
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc37
-rw-r--r--source/blender/blenkernel/intern/action.c9
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c2
-rw-r--r--source/blender/blenkernel/intern/attribute.cc130
-rw-r--r--source/blender/blenkernel/intern/constraint.c34
-rw-r--r--source/blender/blenkernel/intern/curve.cc1
-rw-r--r--source/blender/blenkernel/intern/curves.cc17
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc248
-rw-r--r--source/blender/blenkernel/intern/curves_utils.cc84
-rw-r--r--source/blender/blenkernel/intern/customdata.cc69
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c4
-rw-r--r--source/blender/blenkernel/intern/fcurve.c144
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc1
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc15
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc4
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c43
-rw-r--r--source/blender/blenkernel/intern/idprop.c2
-rw-r--r--source/blender/blenkernel/intern/image.cc6
-rw-r--r--source/blender/blenkernel/intern/image_gpu.cc38
-rw-r--r--source/blender/blenkernel/intern/image_save.cc12
-rw-r--r--source/blender/blenkernel/intern/lib_override.cc108
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c2
-rw-r--r--source/blender/blenkernel/intern/linestyle.c2
-rw-r--r--source/blender/blenkernel/intern/material.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc24
-rw-r--r--source/blender/blenkernel/intern/mesh_calc_edges.cc6
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc1
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.cc172
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.cc23
-rw-r--r--source/blender/blenkernel/intern/nla.c45
-rw-r--r--source/blender/blenkernel/intern/node.cc3
-rw-r--r--source/blender/blenkernel/intern/object.cc17
-rw-r--r--source/blender/blenkernel/intern/paint.c8
-rw-r--r--source/blender/blenkernel/intern/particle.c2
-rw-r--r--source/blender/blenkernel/intern/particle_system.c4
-rw-r--r--source/blender/blenkernel/intern/pbvh.c126
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c3
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h8
-rw-r--r--source/blender/blenkernel/intern/pointcache.c2
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc4
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c2
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c4
-rw-r--r--source/blender/blenkernel/intern/subdiv_modifier.c62
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c8
-rw-r--r--source/blender/blenkernel/intern/tracking.c10
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c2
-rw-r--r--source/blender/blenkernel/intern/unit.c21
-rw-r--r--source/blender/blenlib/BLI_assert.h2
-rw-r--r--source/blender/blenlib/BLI_bounds.hh6
-rw-r--r--source/blender/blenlib/BLI_ghash.h2
-rw-r--r--source/blender/blenlib/BLI_hash_tables.hh6
-rw-r--r--source/blender/blenlib/BLI_index_mask.hh2
-rw-r--r--source/blender/blenlib/BLI_math_color.h2
-rw-r--r--source/blender/blenlib/BLI_math_geom.h2
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h2
-rw-r--r--source/blender/blenlib/BLI_math_vector.hh33
-rw-r--r--source/blender/blenlib/BLI_utildefines_iter.h2
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh26
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.cc1
-rw-r--r--source/blender/blenlib/intern/hash_md5.c6
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c20
-rw-r--r--source/blender/blenlib/intern/math_solvers.c4
-rw-r--r--source/blender/blenlib/intern/string_utf8.c4
-rw-r--r--source/blender/blenlib/tests/BLI_bounds_test.cc7
-rw-r--r--source/blender/blenlib/tests/BLI_math_color_test.cc68
-rw-r--r--source/blender/blenlib/tests/BLI_math_vector_test.cc20
-rw-r--r--source/blender/blenloader/intern/versioning_280.c6
-rw-r--r--source/blender/blenloader/intern/versioning_290.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.c539
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c1
-rw-r--r--source/blender/blenloader/intern/writefile.c8
-rw-r--r--source/blender/blentranslation/BLT_translation.h7
-rw-r--r--source/blender/blentranslation/intern/blt_lang.c9
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c21
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h4
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.h4
-rwxr-xr-xsource/blender/datatoc/datatoc_icon.py2
-rwxr-xr-xsource/blender/datatoc/datatoc_icon_split.py2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc40
-rw-r--r--source/blender/draw/CMakeLists.txt219
-rw-r--r--source/blender/draw/DRW_engine.h9
-rw-r--r--source/blender/draw/engines/basic/basic_shader.c6
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_conservative_depth_geom.glsl (renamed from source/blender/draw/engines/basic/shaders/conservative_depth_geom.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_depth_frag.glsl (renamed from source/blender/draw/engines/basic/shaders/depth_frag.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_depth_pointcloud_vert.glsl (renamed from source/blender/draw/engines/basic/shaders/depth_pointcloud_vert.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_depth_vert.glsl (renamed from source/blender/draw/engines/basic/shaders/depth_vert.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh8
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c2
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl10
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader_shared.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_velocity.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh7
-rw-r--r--source/blender/draw/engines/external/external_engine.c4
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c10
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/antialiasing_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/armature_info.hh)44
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_background_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/background_info.hh)8
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/edit_mode_info.hh)140
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/extra_info.hh)50
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_facing_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/facing_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_grid_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/grid_info.hh)14
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/outline_info.hh)16
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_paint_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/paint_info.hh)26
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/sculpt_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_volume_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/volume_info.hh)12
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_dof_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_stick_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_stick_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_background_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/background_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_clipbound_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_common_lib.glsl (renamed from source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl6
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_particle_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_image_mask_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_image_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_facing_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/facing_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_facing_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/facing_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_grid_background_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/grid_background_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/grid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_grid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/grid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/image_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_image_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/image_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_line_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_face_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_texture_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_texture_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_weight_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/particle_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_particle_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/particle_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl23
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl27
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_volume_gridlines_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_volume_velocity_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/xray_fade_frag.glsl)0
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c5
-rw-r--r--source/blender/draw/intern/DRW_render.h4
-rw-r--r--source/blender/draw/intern/draw_attributes.cc6
-rw-r--r--source/blender/draw/intern/draw_attributes.h2
-rw-r--r--source/blender/draw/intern/draw_cache.c32
-rw-r--r--source/blender/draw/intern/draw_cache_extract.hh (renamed from source/blender/draw/intern/draw_cache_extract.h)136
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc85
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc (renamed from source/blender/draw/intern/draw_cache_extract_mesh_render_data.c)131
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h16
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc57
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.cc (renamed from source/blender/draw/intern/draw_cache_impl_mesh.c)741
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc63
-rw-r--r--source/blender/draw/intern/draw_common.h2
-rw-r--r--source/blender/draw/intern/draw_curves.cc25
-rw-r--r--source/blender/draw/intern/draw_curves_private.h26
-rw-r--r--source/blender/draw/intern/draw_manager_data.c3
-rw-r--r--source/blender/draw/intern/draw_subdivision.h3
-rw-r--r--source/blender/draw/intern/draw_volume.cc12
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.cc (renamed from source/blender/draw/intern/mesh_extractors/extract_mesh.c)6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.hh (renamed from source/blender/draw/intern/mesh_extractors/extract_mesh.h)138
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc20
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc151
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc86
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc4
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_lib.glsl14
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl4
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl19
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c10
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c74
-rw-r--r--source/blender/editors/animation/anim_markers.c2
-rw-r--r--source/blender/editors/animation/drivers.c2
-rw-r--r--source/blender/editors/animation/keyframes_keylist.cc4
-rw-r--r--source/blender/editors/animation/keyframing.c32
-rw-r--r--source/blender/editors/armature/armature_add.c11
-rw-r--r--source/blender/editors/armature/armature_naming.c9
-rw-r--r--source/blender/editors/armature/armature_relations.c27
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_select.c9
-rw-r--r--source/blender/editors/curve/editcurve.c3
-rw-r--r--source/blender/editors/curve/editcurve_paint.c8
-rw-r--r--source/blender/editors/curve/editcurve_pen.c6
-rw-r--r--source/blender/editors/curves/CMakeLists.txt1
-rw-r--r--source/blender/editors/curves/intern/curves_ops.cc111
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt17
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc80
-rw-r--r--source/blender/editors/geometry/geometry_intern.hh1
-rw-r--r--source/blender/editors/geometry/geometry_ops.cc1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c29
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c28
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c110
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c4
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h10
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c17
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c2
-rw-r--r--source/blender/editors/include/ED_clip.h2
-rw-r--r--source/blender/editors/include/ED_datafiles.h38
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h22
-rw-r--r--source/blender/editors/include/ED_gpencil.h6
-rw-r--r--source/blender/editors/include/ED_image.h11
-rw-r--r--source/blender/editors/include/ED_keyframing.h9
-rw-r--r--source/blender/editors/include/ED_sculpt.h2
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h66
-rw-r--r--source/blender/editors/include/ED_view3d.h7
-rw-r--r--source/blender/editors/include/UI_grid_view.hh264
-rw-r--r--source/blender/editors/include/UI_icons.h15
-rw-r--r--source/blender/editors/include/UI_interface.h90
-rw-r--r--source/blender/editors/include/UI_interface.hh5
-rw-r--r--source/blender/editors/include/UI_tree_view.hh6
-rw-r--r--source/blender/editors/interface/CMakeLists.txt2
-rw-r--r--source/blender/editors/interface/grid_view.cc525
-rw-r--r--source/blender/editors/interface/interface.cc161
-rw-r--r--source/blender/editors/interface/interface_anim.c2
-rw-r--r--source/blender/editors/interface/interface_drag.cc144
-rw-r--r--source/blender/editors/interface/interface_draw.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c8
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c139
-rw-r--r--source/blender/editors/interface/interface_icons.c17
-rw-r--r--source/blender/editors/interface/interface_icons_event.c6
-rw-r--r--source/blender/editors/interface/interface_intern.h22
-rw-r--r--source/blender/editors/interface/interface_ops.c24
-rw-r--r--source/blender/editors/interface/interface_query.cc19
-rw-r--r--source/blender/editors/interface/interface_region_search.cc7
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c2
-rw-r--r--source/blender/editors/interface/interface_style.cc18
-rw-r--r--source/blender/editors/interface/interface_template_list.cc9
-rw-r--r--source/blender/editors/interface/interface_templates.c2
-rw-r--r--source/blender/editors/interface/interface_view.cc89
-rw-r--r--source/blender/editors/interface/interface_widgets.c24
-rw-r--r--source/blender/editors/interface/tree_view.cc15
-rw-r--r--source/blender/editors/io/CMakeLists.txt27
-rw-r--r--source/blender/editors/io/io_alembic.c2
-rw-r--r--source/blender/editors/io/io_collada.c4
-rw-r--r--source/blender/editors/io/io_gpencil_export.c54
-rw-r--r--source/blender/editors/io/io_gpencil_import.c40
-rw-r--r--source/blender/editors/io/io_gpencil_utils.c14
-rw-r--r--source/blender/editors/io/io_obj.c86
-rw-r--r--source/blender/editors/io/io_ops.c17
-rw-r--r--source/blender/editors/io/io_stl_ops.c133
-rw-r--r--source/blender/editors/io/io_stl_ops.h12
-rw-r--r--source/blender/editors/io/io_usd.c31
-rw-r--r--source/blender/editors/mask/mask_add.c50
-rw-r--r--source/blender/editors/mask/mask_ops.c4
-rw-r--r--source/blender/editors/mask/mask_query.c2
-rw-r--r--source/blender/editors/mask/mask_select.c9
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c10
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c8
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c31
-rw-r--r--source/blender/editors/object/object_add.cc6
-rw-r--r--source/blender/editors/object/object_bake.c20
-rw-r--r--source/blender/editors/object/object_bake_api.c18
-rw-r--r--source/blender/editors/object/object_constraint.c26
-rw-r--r--source/blender/editors/object/object_modes.c10
-rw-r--r--source/blender/editors/object/object_relations.c137
-rw-r--r--source/blender/editors/object/object_remesh.cc2
-rw-r--r--source/blender/editors/object/object_vgroup.c26
-rw-r--r--source/blender/editors/screen/area.c10
-rw-r--r--source/blender/editors/screen/screen_edit.c4
-rw-r--r--source/blender/editors/screen/screen_ops.c9
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt3
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc651
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_brush.cc61
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_comb.cc97
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_delete.cc57
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc121
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_intern.hh26
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_ops.cc17
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc74
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc114
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.cc12
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_ops_paint.cc6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h1
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c148
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c25
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc42
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c105
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.cc (renamed from source/blender/editors/sculpt_paint/sculpt_automasking.c)59
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c49
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_expand.c28
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c10
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h21
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c21
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c180
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c2
-rw-r--r--source/blender/editors/space_clip/clip_editor.c2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c6
-rw-r--r--source/blender/editors/space_clip/tracking_select.c2
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc11
-rw-r--r--source/blender/editors/space_file/file_intern.h1
-rw-r--r--source/blender/editors/space_file/file_ops.c46
-rw-r--r--source/blender/editors/space_file/filelist.c4
-rw-r--r--source/blender/editors/space_file/filesel.c3
-rw-r--r--source/blender/editors/space_file/fsmenu.c2
-rw-r--r--source/blender/editors/space_file/space_file.c1
-rw-r--r--source/blender/editors/space_image/image_ops.c53
-rw-r--r--source/blender/editors/space_image/image_undo.c2
-rw-r--r--source/blender/editors/space_image/space_image.c3
-rw-r--r--source/blender/editors/space_info/info_stats.cc18
-rw-r--r--source/blender/editors/space_nla/nla_edit.c6
-rw-r--r--source/blender/editors/space_node/node_draw.cc48
-rw-r--r--source/blender/editors/space_node/node_edit.cc26
-rw-r--r--source/blender/editors/space_outliner/outliner_select.cc4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc26
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.cc7
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc14
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.hh8
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc39
-rw-r--r--source/blender/editors/space_outliner/tree/tree_iterator.cc7
-rw-r--r--source/blender/editors/space_outliner/tree/tree_iterator.hh2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c6
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c50
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c20
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc1
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc29
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc5
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_cursor_snap.c31
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_walk.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c2
-rw-r--r--source/blender/editors/transform/transform.c25
-rw-r--r--source/blender/editors/transform/transform.h33
-rw-r--r--source/blender/editors/transform/transform_convert.c3
-rw-r--r--source/blender/editors/transform/transform_convert.h2
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c2
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c5
-rw-r--r--source/blender/editors/transform/transform_convert_object.c2
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c287
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c66
-rw-r--r--source/blender/editors/transform/transform_generics.c4
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c448
-rw-r--r--source/blender/editors/transform/transform_mode.c2
-rw-r--r--source/blender/editors/transform/transform_mode.h2
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c20
-rw-r--r--source/blender/editors/transform/transform_mode_trackball.c61
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c12
-rw-r--r--source/blender/editors/transform/transform_ops.c8
-rw-r--r--source/blender/editors/transform/transform_snap.c182
-rw-r--r--source/blender/editors/transform/transform_snap.h13
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc373
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c21
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c101
-rw-r--r--source/blender/functions/FN_field.hh2
-rw-r--r--source/blender/functions/intern/field.cc8
-rw-r--r--source/blender/geometry/CMakeLists.txt4
-rw-r--r--source/blender/geometry/GEO_add_curves_on_mesh.hh54
-rw-r--r--source/blender/geometry/GEO_reverse_uv_sampler.hh42
-rw-r--r--source/blender/geometry/GEO_uv_parametrizer.h5
-rw-r--r--source/blender/geometry/intern/add_curves_on_mesh.cc354
-rw-r--r--source/blender/geometry/intern/resample_curves.cc62
-rw-r--r--source/blender/geometry/intern/reverse_uv_sampler.cc32
-rw-r--r--source/blender/geometry/intern/uv_parametrizer.c85
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencildash.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c6
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillength.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c11
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c5
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c7
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h292
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c247
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c2267
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h17
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_util.c17
-rw-r--r--source/blender/gpu/CMakeLists.txt24
-rw-r--r--source/blender/gpu/GPU_buffers.h44
-rw-r--r--source/blender/gpu/GPU_texture.h2
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c634
-rw-r--r--source/blender/gpu/intern/gpu_codegen.cc4
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c26
-rw-r--r--source/blender/gpu/intern/gpu_material.c5
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c2
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc2
-rw-r--r--source/blender/gpu/metal/mtl_backend.mm2
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc2
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl8
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h1
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h7
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h9
-rw-r--r--source/blender/imbuf/intern/cineon/cineon_dpx.c4
-rw-r--r--source/blender/imbuf/intern/colormanagement.c137
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp10
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c31
-rw-r--r--source/blender/imbuf/intern/thumbs.c5
-rw-r--r--source/blender/imbuf/intern/tiff.c22
-rw-r--r--source/blender/imbuf/intern/transform.cc23
-rw-r--r--source/blender/imbuf/intern/util_gpu.c65
-rw-r--r--source/blender/io/CMakeLists.txt19
-rw-r--r--source/blender/io/alembic/exporter/abc_custom_props.cc4
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc2
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc24
-rw-r--r--source/blender/io/avi/AVI_avi.h3
-rw-r--r--source/blender/io/collada/BCAnimationSampler.cpp12
-rw-r--r--source/blender/io/collada/BCMath.cpp6
-rw-r--r--source/blender/io/collada/MeshImporter.h4
-rw-r--r--source/blender/io/collada/SceneExporter.cpp11
-rw-r--r--source/blender/io/common/CMakeLists.txt3
-rw-r--r--source/blender/io/common/IO_abstract_hierarchy_iterator.h5
-rw-r--r--source/blender/io/common/IO_orientation.h16
-rw-r--r--source/blender/io/common/intern/abstract_hierarchy_iterator.cc5
-rw-r--r--source/blender/io/common/intern/orientation.c14
-rw-r--r--source/blender/io/stl/CMakeLists.txt44
-rw-r--r--source/blender/io/stl/IO_stl.cc16
-rw-r--r--source/blender/io/stl/IO_stl.h35
-rw-r--r--source/blender/io/stl/importer/stl_import.cc114
-rw-r--r--source/blender/io/stl/importer/stl_import.hh22
-rw-r--r--source/blender/io/stl/importer/stl_import_ascii_reader.cc160
-rw-r--r--source/blender/io/stl/importer/stl_import_ascii_reader.hh35
-rw-r--r--source/blender/io/stl/importer/stl_import_binary_reader.cc58
-rw-r--r--source/blender/io/stl/importer/stl_import_binary_reader.hh31
-rw-r--r--source/blender/io/stl/importer/stl_import_mesh.cc114
-rw-r--r--source/blender/io/stl/importer/stl_import_mesh.hh71
-rw-r--r--source/blender/io/usd/intern/usd_capi_import.cc19
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc98
-rw-r--r--source/blender/io/usd/intern/usd_reader_prim.h15
-rw-r--r--source/blender/io/usd/intern/usd_writer_material.cc3
-rw-r--r--source/blender/io/usd/tests/usd_tests_common.h2
-rw-r--r--source/blender/io/usd/usd.h8
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h28
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc37
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh6
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_io.hh4
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc15
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh7
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc7
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh2
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.cc2
-rw-r--r--source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc9
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc65
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.cc26
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.hh1
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_objects.hh3
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc58
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh5
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_importer_tests.cc137
-rw-r--r--source/blender/makesdna/DNA_ID.h2
-rw-r--r--source/blender/makesdna/DNA_anim_types.h2
-rw-r--r--source/blender/makesdna/DNA_brush_types.h2
-rw-r--r--source/blender/makesdna/DNA_cloth_types.h4
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h3
-rw-r--r--source/blender/makesdna/DNA_curves_types.h7
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h2
-rw-r--r--source/blender/makesdna/DNA_ipo_types.h2
-rw-r--r--source/blender/makesdna/DNA_light_types.h2
-rw-r--r--source/blender/makesdna/DNA_lineart_types.h10
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h21
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h7
-rw-r--r--source/blender/makesdna/DNA_node_types.h6
-rw-r--r--source/blender/makesdna/DNA_object_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h112
-rw-r--r--source/blender/makesdna/DNA_space_types.h1
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h5
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h15
-rw-r--r--source/blender/makesrna/RNA_access.h12
-rw-r--r--source/blender/makesrna/RNA_enum_items.h5
-rw-r--r--source/blender/makesrna/intern/rna_ID.c18
-rw-r--r--source/blender/makesrna/intern/rna_access.c48
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c11
-rw-r--r--source/blender/makesrna/intern/rna_brush.c14
-rw-r--r--source/blender/makesrna/intern/rna_camera.c19
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c9
-rw-r--r--source/blender/makesrna/intern/rna_curves.c16
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c4
-rw-r--r--source/blender/makesrna/intern/rna_image.c77
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_internal.h1
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_layer.c1
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c25
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c45
-rw-r--r--source/blender/makesrna/intern/rna_pose.c6
-rw-r--r--source/blender/makesrna/intern/rna_rna.c4
-rw-r--r--source/blender/makesrna/intern/rna_scene.c33
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c20
-rw-r--r--source/blender/makesrna/intern/rna_space.c6
-rw-r--r--source/blender/makesrna/intern/rna_ui.c9
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c5
-rw-r--r--source/blender/makesrna/intern/rna_wm.c20
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c1
-rw-r--r--source/blender/modifiers/intern/MOD_array.c2
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.cc40
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c3
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c6
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c3
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c3
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c42
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c3
-rw-r--r--source/blender/nodes/NOD_geometry.h3
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh41
-rw-r--r--source/blender/nodes/NOD_static_types.h3
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt3
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc810
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc338
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc59
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc65
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc64
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc197
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc4
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc131
-rw-r--r--source/blender/python/intern/CMakeLists.txt12
-rw-r--r--source/blender/python/intern/bpy_app.c54
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c21
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c6
-rw-r--r--source/blender/python/intern/bpy_traceback.c2
-rw-r--r--source/blender/python/rna_dump.py2
-rw-r--r--source/blender/render/RE_pipeline.h10
-rw-r--r--source/blender/render/intern/pipeline.c6
-rw-r--r--source/blender/render/intern/render_result.c2
-rw-r--r--source/blender/render/intern/render_result.h2
-rw-r--r--source/blender/sequencer/SEQ_transform.h2
-rw-r--r--source/blender/sequencer/intern/image_cache.c9
-rw-r--r--source/blender/sequencer/intern/strip_time.c4
-rw-r--r--source/blender/sequencer/intern/strip_transform.c303
-rw-r--r--source/blender/sequencer/intern/utils.c2
-rw-r--r--source/blender/windowmanager/CMakeLists.txt2
-rw-r--r--source/blender/windowmanager/WM_api.h16
-rw-r--r--source/blender/windowmanager/WM_types.h1
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h2
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c7
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c2
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c2
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c147
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.cc (renamed from source/blender/windowmanager/intern/wm_event_system.c)802
-rw-r--r--source/blender/windowmanager/intern/wm_files.c2
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c8
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c6
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c60
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c6
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c8
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c14
-rw-r--r--source/blender/windowmanager/intern/wm_uilist_type.c1
-rw-r--r--source/blender/windowmanager/intern/wm_window.c22
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_operators.c5
m---------source/tools0
-rw-r--r--tests/python/alembic_export_tests.py2
-rw-r--r--tests/python/batch_import.py2
-rw-r--r--tests/python/bl_alembic_io_test.py2
-rw-r--r--tests/python/bl_animation_fcurves.py2
-rw-r--r--tests/python/bl_bundled_modules.py2
-rw-r--r--tests/python/bl_keymap_completeness.py2
-rw-r--r--tests/python/bl_keymap_validate.py2
-rw-r--r--tests/python/bl_load_addons.py2
-rw-r--r--tests/python/bl_load_py_modules.py2
-rw-r--r--tests/python/bl_mesh_modifiers.py2
-rw-r--r--tests/python/bl_mesh_validate.py2
-rw-r--r--tests/python/bl_rigging_symmetrize.py2
-rw-r--r--tests/python/bl_rna_manual_reference.py2
-rw-r--r--tests/python/bl_rst_completeness.py2
-rw-r--r--tests/python/bl_run_operators.py2
-rw-r--r--tests/python/bl_run_operators_event_simulate.py2
-rw-r--r--tests/python/bl_test.py2
-rw-r--r--tests/python/bl_usd_import_test.py2
-rw-r--r--tests/python/boolean_operator.py2
-rw-r--r--tests/python/deform_modifiers.py2
-rw-r--r--tests/python/ffmpeg_tests.py2
-rw-r--r--tests/python/geo_node_test.py2
-rw-r--r--tests/python/modifiers.py19
-rw-r--r--tests/python/modules/mesh_test.py2
-rwxr-xr-xtests/python/modules/render_report.py8
-rwxr-xr-xtests/python/modules/test_utils.py2
-rw-r--r--tests/python/operators.py2
-rw-r--r--tests/python/pep8.py21
-rw-r--r--tests/python/physics_cloth.py2
-rw-r--r--tests/python/physics_dynamic_paint.py2
-rw-r--r--tests/python/physics_ocean.py2
-rw-r--r--tests/python/physics_particle_instance.py2
-rw-r--r--tests/python/physics_particle_system.py2
-rw-r--r--tests/python/physics_softbody.py2
-rw-r--r--tests/python/rna_info_dump.py2
-rw-r--r--tests/python/rst_to_doctree_mini.py2
1172 files changed, 20298 insertions, 10857 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 90baadcac8b..31608b0c1ce 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -300,6 +300,9 @@ option(WITH_USD "Enable Universal Scene Description (USD) Suppor
# 3D format support
# Disable opencollada when we don't have precompiled libs
option(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.org)" ON)
+option(WITH_IO_WAVEFRONT_OBJ "Enable Wavefront-OBJ 3D file format support (*.obj)" ON)
+option(WITH_IO_STL "Enable STL 3D file format support (*.stl)" ON)
+option(WITH_IO_GPENCIL "Enable grease-pencil file format IO (*.svg, *.pdf)" ON)
# Sound output
option(WITH_SDL "Enable SDL for sound" ON)
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index b63e86a3ac2..1cf63f2d332 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -57,7 +57,6 @@ include(cmake/alembic.cmake)
include(cmake/opensubdiv.cmake)
include(cmake/sdl.cmake)
include(cmake/opencollada.cmake)
-include(cmake/llvm.cmake)
if(APPLE)
include(cmake/openmp.cmake)
endif()
@@ -75,6 +74,7 @@ include(cmake/osl.cmake)
include(cmake/tbb.cmake)
include(cmake/openvdb.cmake)
include(cmake/python.cmake)
+include(cmake/llvm.cmake)
option(USE_PIP_NUMPY "Install NumPy using pip wheel instead of building from source" OFF)
if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64"))
set(USE_PIP_NUMPY ON)
diff --git a/build_files/build_environment/cmake/llvm.cmake b/build_files/build_environment/cmake/llvm.cmake
index cf92a5175a3..df4cd8b71e9 100644
--- a/build_files/build_environment/cmake/llvm.cmake
+++ b/build_files/build_environment/cmake/llvm.cmake
@@ -25,11 +25,14 @@ set(LLVM_EXTRA_ARGS
-DLLVM_BUILD_LLVM_C_DYLIB=OFF
-DLLVM_ENABLE_UNWIND_TABLES=OFF
-DLLVM_ENABLE_PROJECTS=clang${LLVM_BUILD_CLANG_TOOLS_EXTRA}
+ -DPython3_ROOT_DIR=${LIBDIR}/python/
+ -DPython3_EXECUTABLE=${PYTHON_BINARY}
${LLVM_XML2_ARGS}
)
if(WIN32)
set(LLVM_GENERATOR "Ninja")
+ list(APPEND LLVM_EXTRA_ARGS -DPython3_FIND_REGISTRY=NEVER)
else()
set(LLVM_GENERATOR "Unix Makefiles")
endif()
@@ -74,3 +77,9 @@ if(APPLE)
external_xml2
)
endif()
+
+add_dependencies(
+ ll
+ external_python
+)
+
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 58702f69609..81db928a477 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -36,19 +36,19 @@ getopt \
-o s:i:t:h \
--long source:,install:,tmp:,info:,threads:,help,show-deps,no-sudo,no-build,no-confirm,\
with-all,with-opencollada,with-jack,with-pulseaudio,with-embree,with-oidn,with-nanovdb,\
-ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,ver-xr-openxr:,\
+ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,ver-xr-openxr:,ver-level-zero:\
force-all,force-python,force-boost,force-tbb,\
force-ocio,force-imath,force-openexr,force-oiio,force-llvm,force-osl,force-osd,force-openvdb,\
force-ffmpeg,force-opencollada,force-alembic,force-embree,force-oidn,force-usd,\
-force-xr-openxr,\
+force-xr-openxr,force-level-zero,\
build-all,build-python,build-boost,build-tbb,\
build-ocio,build-imath,build-openexr,build-oiio,build-llvm,build-osl,build-osd,build-openvdb,\
build-ffmpeg,build-opencollada,build-alembic,build-embree,build-oidn,build-usd,\
-build-xr-openxr,\
+build-xr-openxr,build-level-zero,\
skip-python,skip-boost,skip-tbb,\
skip-ocio,skip-imath,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-osd,skip-openvdb,\
skip-ffmpeg,skip-opencollada,skip-alembic,skip-embree,skip-oidn,skip-usd,\
-skip-xr-openxr \
+skip-xr-openxr,skip-level-zero \
-- "$@" \
)
@@ -165,6 +165,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--ver-xr-openxr=<ver>
Force version of OpenXR-SDK.
+ --ver-level-zero=<ver>
+ Force version of OneAPI Level Zero library.
+
Note about the --ver-foo options:
It may not always work as expected (some libs are actually checked out from a git rev...), yet it might help
to fix some build issues (like LLVM mismatch with the version used by your graphic system).
@@ -226,6 +229,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--build-xr-openxr
Force the build of OpenXR-SDK.
+ --build-level-zero=<ver>
+ Force the build of OneAPI Level Zero library.
+
Note about the --build-foo options:
* They force the script to prefer building dependencies rather than using available packages.
This may make things simpler and allow working around some distribution bugs, but on the other hand it will
@@ -293,6 +299,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--force-xr-openxr
Force the rebuild of OpenXR-SDK.
+ --force-level-zero=<ver>
+ Force the rebuild of OneAPI Level Zero library.
+
Note about the --force-foo options:
* They obviously only have an effect if those libraries are built by this script
(i.e. if there is no available and satisfactory package)!
@@ -351,7 +360,10 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
Unconditionally skip Universal Scene Description installation/building.
--skip-xr-openxr
- Unconditionally skip OpenXR-SDK installation/building.\""
+ Unconditionally skip OpenXR-SDK installation/building.
+
+ --skip-level-zero=<ver>
+ Unconditionally skip OneAPI Level Zero installation/building.\""
# ----------------------------------------------------------------------------
# Main Vars
@@ -573,14 +585,13 @@ OIDN_SKIP=false
ISPC_VERSION="1.17.0"
-FFMPEG_VERSION="4.4"
-FFMPEG_VERSION_SHORT="4.4"
-FFMPEG_VERSION_MIN="3.0"
-FFMPEG_VERSION_MEX="5.0"
-FFMPEG_FORCE_BUILD=false
-FFMPEG_FORCE_REBUILD=false
-FFMPEG_SKIP=false
-_ffmpeg_list_sep=";"
+LEVEL_ZERO_VERSION="1.7.15"
+LEVEL_ZERO_VERSION_SHORT="1.7"
+LEVEL_ZERO_VERSION_MIN="1.7"
+LEVEL_ZERO_VERSION_MEX="2.0"
+LEVEL_ZERO_FORCE_BUILD=false
+LEVEL_ZERO_FORCE_REBUILD=false
+LEVEL_ZERO_SKIP=false
XR_OPENXR_VERSION="1.0.22"
XR_OPENXR_VERSION_SHORT="1.0"
@@ -590,6 +601,15 @@ XR_OPENXR_FORCE_BUILD=false
XR_OPENXR_FORCE_REBUILD=false
XR_OPENXR_SKIP=false
+FFMPEG_VERSION="5.0"
+FFMPEG_VERSION_SHORT="5.0"
+FFMPEG_VERSION_MIN="4.0"
+FFMPEG_VERSION_MEX="6.0"
+FFMPEG_FORCE_BUILD=false
+FFMPEG_FORCE_REBUILD=false
+FFMPEG_SKIP=false
+_ffmpeg_list_sep=";"
+
# FFMPEG optional libs.
VORBIS_USE=false
VORBIS_DEV=""
@@ -781,6 +801,12 @@ while true; do
XR_OPENXR_VERSION_SHORT=$XR_OPENXR_VERSION
shift; shift; continue
;;
+ --ver-level-zero)
+ LEVEL_ZERO_VERSION="$2"
+ LEVEL_ZERO_VERSION_MIN=$LEVEL_ZERO_VERSION
+ LEVEL_ZERO_VERSION_SHORT=$LEVEL_ZERO_VERSION
+ shift; shift; continue
+ ;;
--build-all)
PYTHON_FORCE_BUILD=true
BOOST_FORCE_BUILD=true
@@ -800,6 +826,7 @@ while true; do
ALEMBIC_FORCE_BUILD=true
USD_FORCE_BUILD=true
XR_OPENXR_FORCE_BUILD=true
+ LEVEL_ZERO_FORCE_BUILD=true
shift; continue
;;
--build-python)
@@ -857,6 +884,9 @@ while true; do
--build-xr-openxr)
XR_OPENXR_FORCE_BUILD=true; shift; continue
;;
+ --build-level-zero)
+ LEVEL_ZERO_FORCE_BUILD=true; shift; continue
+ ;;
--force-all)
PYTHON_FORCE_REBUILD=true
BOOST_FORCE_REBUILD=true
@@ -876,6 +906,7 @@ while true; do
ALEMBIC_FORCE_REBUILD=true
USD_FORCE_REBUILD=true
XR_OPENXR_FORCE_REBUILD=true
+ LEVEL_ZERO_FORCE_REBUILD=true
shift; continue
;;
--force-python)
@@ -933,6 +964,9 @@ while true; do
--force-xr-openxr)
XR_OPENXR_FORCE_REBUILD=true; shift; continue
;;
+ --force-level-zero)
+ LEVEL_ZERO_FORCE_REBUILD=true; shift; continue
+ ;;
--skip-python)
PYTHON_SKIP=true; shift; continue
;;
@@ -987,6 +1021,9 @@ while true; do
--skip-xr-openxr)
XR_OPENXR_SKIP=true; shift; continue
;;
+ --skip-level-zero)
+ LEVEL_ZERO_SKIP=true; shift; continue
+ ;;
--)
# no more arguments to parse
break
@@ -1128,14 +1165,16 @@ OIDN_SOURCE=( "https://github.com/OpenImageDenoise/oidn/releases/download/v${OID
ISPC_BINARY=( "https://github.com/ispc/ispc/releases/download/v${ISPC_VERSION}/ispc-v${ISPC_VERSION}-linux.tar.gz" )
-FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
-
XR_OPENXR_USE_REPO=false
XR_OPENXR_SOURCE=("https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_VERSION}.tar.gz")
XR_OPENXR_SOURCE_REPO=("https://github.com/KhronosGroup/OpenXR-SDK.git")
XR_OPENXR_REPO_UID="458984d7f59d1ae6dc1b597d94b02e4f7132eaba"
XR_OPENXR_REPO_BRANCH="master"
+LEVEL_ZERO_SOURCE=("https://github.com/oneapi-src/level-zero/archive/refs/tags/v${LEVEL_ZERO_VERSION}.tar.gz")
+
+FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
+
# C++11 is required now
CXXFLAGS_BACK=$CXXFLAGS
CXXFLAGS="$CXXFLAGS -std=c++11"
@@ -1187,7 +1226,8 @@ You may also want to build them yourself (optional ones are [between brackets]):
* [OpenImageDenoise $OIDN_VERSION] (from $OIDN_SOURCE).
* [Alembic $ALEMBIC_VERSION] (from $ALEMBIC_SOURCE).
* [Universal Scene Description $USD_VERSION] (from $USD_SOURCE).
- * [OpenXR-SDK $XR_OPENXR_VERSION] (from $XR_OPENXR_SOURCE).\""
+ * [OpenXR-SDK $XR_OPENXR_VERSION] (from $XR_OPENXR_SOURCE).
+ * [OneAPI Level Zero $LEVEL_ZERO_VERSION] (from $LEVEL_ZERO_SOURCE).\""
if [ "$DO_SHOW_DEPS" = true ]; then
PRINT ""
@@ -3823,6 +3863,103 @@ compile_XR_OpenXR_SDK() {
# ----------------------------------------------------------------------------
+# Build OneAPI Level Zero library.
+
+_init_level_zero() {
+ _src=$SRC/level-zero-$LEVEL_ZERO_VERSION
+ _git=false
+ _inst=$INST/level-zero-$LEVEL_ZERO_VERSION_SHORT
+ _inst_shortcut=$INST/level-zero
+}
+
+_update_deps_level_zero() {
+ :
+}
+
+clean_Level_Zero() {
+ _init_level_zero
+ if [ -d $_inst ]; then
+ # Force rebuilding the dependencies if needed.
+ _update_deps_level_zero false true
+ fi
+ _clean
+}
+
+compile_Level_Zero() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, Level Zero will not be compiled!"
+ return
+ fi
+
+ # To be changed each time we make edits that would modify the compiled result!
+ level_zero_magic=1
+ _init_level_zero
+
+ # Force having own builds for the dependencies.
+ _update_deps_level_zero true false
+
+ # Clean install if needed!
+ magic_compile_check level-zero-$LEVEL_ZERO_VERSION $level_zero_magic
+ if [ $? -eq 1 -o "$LEVEL_ZERO_FORCE_REBUILD" = true ]; then
+ clean_Level_Zero
+ fi
+
+ if [ ! -d $_inst ]; then
+ INFO "Building Level-Zero-$LEVEL_ZERO_VERSION"
+
+ # Force rebuilding the dependencies.
+ _update_deps_level_zero true true
+
+ prepare_inst
+
+ if [ ! -d $_src ]; then
+ mkdir -p $SRC
+
+ download LEVEL_ZERO_SOURCE[@] "$_src.tar.gz"
+ INFO "Unpacking Level-Zero-$LEVEL_ZERO_VERSION"
+ tar -C $SRC -xf $_src.tar.gz
+ fi
+
+ cd $_src
+
+ # Always refresh the whole build!
+ if [ -d build ]; then
+ rm -rf build
+ fi
+ mkdir build
+ cd build
+
+ # Keep flags in sync with LEVEL_ZERO_EXTRA_ARGS in level-zero.cmake!
+ cmake_d="-D CMAKE_BUILD_TYPE=Release"
+ cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
+
+ cmake $cmake_d ..
+
+ make -j$THREADS && make install
+ make clean
+
+ if [ ! -d $_inst ]; then
+ ERROR "Level-Zero-$LEVEL_ZERO_VERSION failed to compile, exiting"
+ exit 1
+ fi
+
+ magic_compile_set level-zero-$LEVEL_ZERO_VERSION $level_zero_magic
+
+ cd $CWD
+ INFO "Done compiling Level-Zero-$LEVEL_ZERO_VERSION!"
+ else
+ INFO "Own Level-Zero-$LEVEL_ZERO_VERSION is up to date, nothing to do!"
+ INFO "If you want to force rebuild of this lib, use the --force-level-zero option."
+ fi
+
+ if [ -d $_inst ]; then
+ _create_inst_shortcut
+ fi
+ run_ldconfig "level-zero"
+}
+
+
+# ----------------------------------------------------------------------------
# Install on DEB-like
get_package_version_DEB() {
@@ -4458,6 +4595,18 @@ install_DEB() {
PRINT ""
compile_XR_OpenXR_SDK
fi
+
+ PRINT ""
+ if [ "$LEVEL_ZERO_SKIP" = true ]; then
+ WARNING "Skipping Level Zero installation, as requested..."
+ elif [ "$LEVEL_ZERO_FORCE_BUILD" = true ]; then
+ INFO "Forced Level Zero building, as requested..."
+ compile_Level_Zero
+ else
+ # No package currently!
+ PRINT ""
+ compile_Level_Zero
+ fi
}
@@ -5144,6 +5293,18 @@ install_RPM() {
# No package currently!
compile_XR_OpenXR_SDK
fi
+
+ PRINT ""
+ if [ "$LEVEL_ZERO_SKIP" = true ]; then
+ WARNING "Skipping Level Zero installation, as requested..."
+ elif [ "$LEVEL_ZERO_FORCE_BUILD" = true ]; then
+ INFO "Forced Level Zero building, as requested..."
+ compile_Level_Zero
+ else
+ # No package currently!
+ PRINT ""
+ compile_Level_Zero
+ fi
}
@@ -5721,6 +5882,18 @@ install_ARCH() {
# No package currently!
compile_XR_OpenXR_SDK
fi
+
+ PRINT ""
+ if [ "$LEVEL_ZERO_SKIP" = true ]; then
+ WARNING "Skipping Level Zero installation, as requested..."
+ elif [ "$LEVEL_ZERO_FORCE_BUILD" = true ]; then
+ INFO "Forced Level Zero building, as requested..."
+ compile_Level_Zero
+ else
+ # No package currently!
+ PRINT ""
+ compile_Level_Zero
+ fi
}
@@ -5895,6 +6068,14 @@ install_OTHER() {
INFO "Forced OpenXR-SDK building, as requested..."
compile_XR_OpenXR_SDK
fi
+
+ PRINT ""
+ if [ "$LEVEL_ZERO_SKIP" = true ]; then
+ WARNING "Skipping Level Zero installation, as requested..."
+ elif [ "$LEVEL_ZERO_FORCE_BUILD" = true ]; then
+ INFO "Forced Level Zero building, as requested..."
+ compile_Level_Zero
+ fi
}
# ----------------------------------------------------------------------------
@@ -6137,6 +6318,18 @@ print_info() {
fi
fi
+ # Not yet available in Blender.
+ #~ if [ "$LEVEL_ZERO_SKIP" = false ]; then
+ #~ _1="-D WITH_LEVEL_ZERO=ON"
+ #~ PRINT " $_1"
+ #~ _buildargs="$_buildargs $_1"
+ #~ if [ -d $INST/level-zero ]; then
+ #~ _1="-D LEVEL_ZERO_ROOT_DIR=$INST/level-zero"
+ #~ PRINT " $_1"
+ #~ _buildargs="$_buildargs $_1"
+ #~ fi
+ #~ fi
+
PRINT ""
PRINT "Or even simpler, just run (in your blender-source dir):"
PRINT " make -j$THREADS BUILD_CMAKE_ARGS=\"$_buildargs\""
diff --git a/build_files/build_environment/windows/build_deps.cmd b/build_files/build_environment/windows/build_deps.cmd
index d836a6a3a50..d3879f3d6ae 100644
--- a/build_files/build_environment/windows/build_deps.cmd
+++ b/build_files/build_environment/windows/build_deps.cmd
@@ -48,10 +48,13 @@ if "%4" == "nobuild" set dobuild=0
REM If Python is be available certain deps may try to
REM to use this over the version we build, to prevent that
-REM make sure python is NOT in the path
-for %%X in (python.exe) do (set PYTHON=%%~$PATH:X)
-if EXIST "%PYTHON%" (
- echo PYTHON found at %PYTHON% dependencies cannot be build with python available in the path
+REM make sure pythonw is NOT in the path. We look for pythonw.exe
+REM since windows apparently ships a python.exe that just opens up
+REM the windows store but does not ship any actual python files that
+REM could cause issues.
+for %%X in (pythonw.exe) do (set PYTHONW=%%~$PATH:X)
+if EXIST "%PYTHONW%" (
+ echo PYTHON found at %PYTHONW% dependencies cannot be build with python available in the path
goto exit
)
diff --git a/build_files/cmake/cmake_netbeans_project.py b/build_files/cmake/cmake_netbeans_project.py
index e3fc9fd86ac..1abef605480 100755
--- a/build_files/cmake/cmake_netbeans_project.py
+++ b/build_files/cmake/cmake_netbeans_project.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Example linux usage
python3 ~/blender-git/blender/build_files/cmake/cmake_netbeans_project.py ~/blender-git/cmake
diff --git a/build_files/cmake/cmake_qtcreator_project.py b/build_files/cmake/cmake_qtcreator_project.py
index 395d24370da..45957e35817 100755
--- a/build_files/cmake/cmake_qtcreator_project.py
+++ b/build_files/cmake/cmake_qtcreator_project.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
r"""
Example Linux usage:
python ~/blender-git/blender/build_files/cmake/cmake_qtcreator_project.py --build-dir ~/blender-git/cmake
diff --git a/build_files/cmake/cmake_static_check_clang_array.py b/build_files/cmake/cmake_static_check_clang_array.py
index d98ab3d58e2..d3b6b971e05 100644
--- a/build_files/cmake/cmake_static_check_clang_array.py
+++ b/build_files/cmake/cmake_static_check_clang_array.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import project_source_info
import subprocess
import sys
diff --git a/build_files/cmake/cmake_static_check_cppcheck.py b/build_files/cmake/cmake_static_check_cppcheck.py
index 75c5ac79ff5..79f9498ce2e 100644
--- a/build_files/cmake/cmake_static_check_cppcheck.py
+++ b/build_files/cmake/cmake_static_check_cppcheck.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import project_source_info
import subprocess
import sys
diff --git a/build_files/cmake/cmake_static_check_smatch.py b/build_files/cmake/cmake_static_check_smatch.py
index b7c2e7817c6..63d8b524231 100644
--- a/build_files/cmake/cmake_static_check_smatch.py
+++ b/build_files/cmake/cmake_static_check_smatch.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
diff --git a/build_files/cmake/cmake_static_check_sparse.py b/build_files/cmake/cmake_static_check_sparse.py
index 51204e4de2e..35641f5f8d1 100644
--- a/build_files/cmake/cmake_static_check_sparse.py
+++ b/build_files/cmake/cmake_static_check_sparse.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
diff --git a/build_files/cmake/cmake_static_check_splint.py b/build_files/cmake/cmake_static_check_splint.py
index 3ee3617e7a8..238377e58cf 100644
--- a/build_files/cmake/cmake_static_check_splint.py
+++ b/build_files/cmake/cmake_static_check_splint.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 2f6057ee9c0..5ce344d39e8 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -37,6 +37,9 @@ set(WITH_IMAGE_TIFF OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_WEBP OFF CACHE BOOL "" FORCE)
set(WITH_INPUT_NDOF OFF CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE)
+set(WITH_IO_STL OFF CACHE BOOL "" FORCE)
+set(WITH_IO_WAVEFRONT_OBJ OFF CACHE BOOL "" FORCE)
+set(WITH_IO_GPENCIL OFF CACHE BOOL "" FORCE)
set(WITH_JACK OFF CACHE BOOL "" FORCE)
set(WITH_LIBMV OFF CACHE BOOL "" FORCE)
set(WITH_LLVM OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/project_info.py b/build_files/cmake/project_info.py
index 0661db3a18c..12f92235b2a 100755
--- a/build_files/cmake/project_info.py
+++ b/build_files/cmake/project_info.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Module for accessing project file data for Blender.
diff --git a/build_files/cmake/project_source_info.py b/build_files/cmake/project_source_info.py
index 7a00f756e03..a544f5733f0 100644
--- a/build_files/cmake/project_source_info.py
+++ b/build_files/cmake/project_source_info.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"build_info",
"SOURCE_DIR",
diff --git a/build_files/package_spec/build_archive.py b/build_files/package_spec/build_archive.py
index 06d11aef0e3..df7399942f3 100755
--- a/build_files/package_spec/build_archive.py
+++ b/build_files/package_spec/build_archive.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import shutil
import subprocess
diff --git a/doc/manpage/blender.1.py b/doc/manpage/blender.1.py
index 6cf2f54b26f..7d35dc0abb1 100755
--- a/doc/manpage/blender.1.py
+++ b/doc/manpage/blender.1.py
@@ -11,8 +11,6 @@ where <path-to-blender> is the path to the Blender executable,
and <output-filename> is where to write the generated man page.
'''
-# <pep8 compliant>
-
import argparse
import os
import subprocess
diff --git a/doc/python_api/requirements.txt b/doc/python_api/requirements.txt
index 51440046430..f93947c9d2d 100644
--- a/doc/python_api/requirements.txt
+++ b/doc/python_api/requirements.txt
@@ -1,12 +1,12 @@
-sphinx==4.1.1
+sphinx==5.0.1
# Sphinx dependencies that are important
-Jinja2==3.0.1
-Pygments==2.10.0
+Jinja2==3.1.2
+Pygments==2.12.0
docutils==0.17.1
-snowballstemmer==2.1.0
-babel==2.9.1
-requests==2.26.0
+snowballstemmer==2.2.0
+babel==2.10.1
+requests==2.27.1
# Only needed to match the theme used for the official documentation.
# Without this theme, the default theme will be used.
diff --git a/doc/python_api/rst/info_best_practice.rst b/doc/python_api/rst/info_best_practice.rst
index e88adcc0d70..6342680e149 100644
--- a/doc/python_api/rst/info_best_practice.rst
+++ b/doc/python_api/rst/info_best_practice.rst
@@ -40,15 +40,6 @@ As well as pep8 we have additional conventions used for Blender Python scripts:
- pep8 also defines that lines should not exceed 79 characters,
we have decided that this is too restrictive so it is optional per script.
-Periodically we run checks for pep8 compliance on Blender scripts,
-for scripts to be included in this check add this line as a comment at the top of the script:
-
-``# <pep8 compliant>``
-
-To enable line length checks use this instead:
-
-``# <pep8-80 compliant>``
-
User Interface Layout
=====================
diff --git a/doc/python_api/rst_from_bmesh_opdefines.py b/doc/python_api/rst_from_bmesh_opdefines.py
index c97b05b96b3..3d8ff1e6248 100644
--- a/doc/python_api/rst_from_bmesh_opdefines.py
+++ b/doc/python_api/rst_from_bmesh_opdefines.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This is a quite stupid script which extracts bmesh api docs from
# 'bmesh_opdefines.c' in order to avoid having to add a lot of introspection
# data access into the api.
diff --git a/doc/python_api/sphinx_changelog_gen.py b/doc/python_api/sphinx_changelog_gen.py
index 6c06178d603..a782c6483b6 100644
--- a/doc/python_api/sphinx_changelog_gen.py
+++ b/doc/python_api/sphinx_changelog_gen.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Dump the python API into a text file so we can generate changelogs.
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 66bd414f425..8d4320917fc 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
API dump in RST files
---------------------
diff --git a/doc/python_api/sphinx_doc_gen_monkeypatch.py b/doc/python_api/sphinx_doc_gen_monkeypatch.py
index 09911e9b8a1..e3fba024446 100644
--- a/doc/python_api/sphinx_doc_gen_monkeypatch.py
+++ b/doc/python_api/sphinx_doc_gen_monkeypatch.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
bpy_types_Operator_bl_property__doc__ = (
"""
The name of a property to use as this operators primary property.
diff --git a/extern/draco/README.blender b/extern/draco/README.blender
index b9c3bbb967d..a879ded978b 100644
--- a/extern/draco/README.blender
+++ b/extern/draco/README.blender
@@ -1,5 +1,5 @@
Project: Draco
URL: https://google.github.io/draco/
License: Apache 2.0
-Upstream version: 1.3.6
-Local modifications: None
+Upstream version: 1.5.2
+Local modifications: Apply patches/blender.patch
diff --git a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc
index 283a21251f4..51c3bb6c872 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc
+++ b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc
@@ -38,6 +38,46 @@ void AttributeOctahedronTransform::CopyToAttributeTransformData(
out_data->AppendParameterValue(quantization_bits_);
}
+bool AttributeOctahedronTransform::TransformAttribute(
+ const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
+ PointAttribute *target_attribute) {
+ return GeneratePortableAttribute(attribute, point_ids,
+ target_attribute->size(), target_attribute);
+}
+
+bool AttributeOctahedronTransform::InverseTransformAttribute(
+ const PointAttribute &attribute, PointAttribute *target_attribute) {
+ if (target_attribute->data_type() != DT_FLOAT32) {
+ return false;
+ }
+
+ const int num_points = target_attribute->size();
+ const int num_components = target_attribute->num_components();
+ if (num_components != 3) {
+ return false;
+ }
+ constexpr int kEntrySize = sizeof(float) * 3;
+ float att_val[3];
+ const int32_t *source_attribute_data = reinterpret_cast<const int32_t *>(
+ attribute.GetAddress(AttributeValueIndex(0)));
+ uint8_t *target_address =
+ target_attribute->GetAddress(AttributeValueIndex(0));
+ OctahedronToolBox octahedron_tool_box;
+ if (!octahedron_tool_box.SetQuantizationBits(quantization_bits_)) {
+ return false;
+ }
+ for (uint32_t i = 0; i < num_points; ++i) {
+ const int32_t s = *source_attribute_data++;
+ const int32_t t = *source_attribute_data++;
+ octahedron_tool_box.QuantizedOctahedralCoordsToUnitVector(s, t, att_val);
+
+ // Store the decoded floating point values into the attribute buffer.
+ std::memcpy(target_address, att_val, kEntrySize);
+ target_address += kEntrySize;
+ }
+ return true;
+}
+
void AttributeOctahedronTransform::SetParameters(int quantization_bits) {
quantization_bits_ = quantization_bits;
}
@@ -51,38 +91,55 @@ bool AttributeOctahedronTransform::EncodeParameters(
return false;
}
-std::unique_ptr<PointAttribute>
-AttributeOctahedronTransform::GeneratePortableAttribute(
+bool AttributeOctahedronTransform::DecodeParameters(
+ const PointAttribute &attribute, DecoderBuffer *decoder_buffer) {
+ uint8_t quantization_bits;
+ if (!decoder_buffer->Decode(&quantization_bits)) {
+ return false;
+ }
+ quantization_bits_ = quantization_bits;
+ return true;
+}
+
+bool AttributeOctahedronTransform::GeneratePortableAttribute(
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
- int num_points) const {
+ int num_points, PointAttribute *target_attribute) const {
DRACO_DCHECK(is_initialized());
- // Allocate portable attribute.
- const int num_entries = static_cast<int>(point_ids.size());
- std::unique_ptr<PointAttribute> portable_attribute =
- InitPortableAttribute(num_entries, 2, num_points, attribute, true);
-
// Quantize all values in the order given by point_ids into portable
// attribute.
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
- portable_attribute->GetAddress(AttributeValueIndex(0)));
+ target_attribute->GetAddress(AttributeValueIndex(0)));
float att_val[3];
int32_t dst_index = 0;
OctahedronToolBox converter;
if (!converter.SetQuantizationBits(quantization_bits_)) {
- return nullptr;
+ return false;
}
- for (uint32_t i = 0; i < point_ids.size(); ++i) {
- const AttributeValueIndex att_val_id = attribute.mapped_index(point_ids[i]);
- attribute.GetValue(att_val_id, att_val);
- // Encode the vector into a s and t octahedral coordinates.
- int32_t s, t;
- converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
- portable_attribute_data[dst_index++] = s;
- portable_attribute_data[dst_index++] = t;
+ if (!point_ids.empty()) {
+ for (uint32_t i = 0; i < point_ids.size(); ++i) {
+ const AttributeValueIndex att_val_id =
+ attribute.mapped_index(point_ids[i]);
+ attribute.GetValue(att_val_id, att_val);
+ // Encode the vector into a s and t octahedral coordinates.
+ int32_t s, t;
+ converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
+ portable_attribute_data[dst_index++] = s;
+ portable_attribute_data[dst_index++] = t;
+ }
+ } else {
+ for (PointIndex i(0); i < num_points; ++i) {
+ const AttributeValueIndex att_val_id = attribute.mapped_index(i);
+ attribute.GetValue(att_val_id, att_val);
+ // Encode the vector into a s and t octahedral coordinates.
+ int32_t s, t;
+ converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
+ portable_attribute_data[dst_index++] = s;
+ portable_attribute_data[dst_index++] = t;
+ }
}
- return portable_attribute;
+ return true;
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h
index 6e4e74284f0..21a1725bb52 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h
+++ b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h
@@ -37,19 +37,40 @@ class AttributeOctahedronTransform : public AttributeTransform {
void CopyToAttributeTransformData(
AttributeTransformData *out_data) const override;
+ bool TransformAttribute(const PointAttribute &attribute,
+ const std::vector<PointIndex> &point_ids,
+ PointAttribute *target_attribute) override;
+
+ bool InverseTransformAttribute(const PointAttribute &attribute,
+ PointAttribute *target_attribute) override;
+
// Set number of quantization bits.
void SetParameters(int quantization_bits);
// Encode relevant parameters into buffer.
- bool EncodeParameters(EncoderBuffer *encoder_buffer) const;
+ bool EncodeParameters(EncoderBuffer *encoder_buffer) const override;
+
+ bool DecodeParameters(const PointAttribute &attribute,
+ DecoderBuffer *decoder_buffer) override;
bool is_initialized() const { return quantization_bits_ != -1; }
int32_t quantization_bits() const { return quantization_bits_; }
- // Create portable attribute.
- std::unique_ptr<PointAttribute> GeneratePortableAttribute(
- const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
- int num_points) const;
+ protected:
+ DataType GetTransformedDataType(
+ const PointAttribute &attribute) const override {
+ return DT_UINT32;
+ }
+ int GetTransformedNumComponents(
+ const PointAttribute &attribute) const override {
+ return 2;
+ }
+
+ // Perform the actual transformation.
+ bool GeneratePortableAttribute(const PointAttribute &attribute,
+ const std::vector<PointIndex> &point_ids,
+ int num_points,
+ PointAttribute *target_attribute) const;
private:
int32_t quantization_bits_;
diff --git a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc
index daa634ed03f..a7f93a488d7 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc
+++ b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc
@@ -1,4 +1,3 @@
-
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -51,13 +50,74 @@ void AttributeQuantizationTransform::CopyToAttributeTransformData(
out_data->AppendParameterValue(range_);
}
-void AttributeQuantizationTransform::SetParameters(int quantization_bits,
+bool AttributeQuantizationTransform::TransformAttribute(
+ const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
+ PointAttribute *target_attribute) {
+ if (point_ids.empty()) {
+ GeneratePortableAttribute(attribute, target_attribute->size(),
+ target_attribute);
+ } else {
+ GeneratePortableAttribute(attribute, point_ids, target_attribute->size(),
+ target_attribute);
+ }
+ return true;
+}
+
+bool AttributeQuantizationTransform::InverseTransformAttribute(
+ const PointAttribute &attribute, PointAttribute *target_attribute) {
+ if (target_attribute->data_type() != DT_FLOAT32) {
+ return false;
+ }
+
+ // Convert all quantized values back to floats.
+ const int32_t max_quantized_value =
+ (1u << static_cast<uint32_t>(quantization_bits_)) - 1;
+ const int num_components = target_attribute->num_components();
+ const int entry_size = sizeof(float) * num_components;
+ const std::unique_ptr<float[]> att_val(new float[num_components]);
+ int quant_val_id = 0;
+ int out_byte_pos = 0;
+ Dequantizer dequantizer;
+ if (!dequantizer.Init(range_, max_quantized_value)) {
+ return false;
+ }
+ const int32_t *const source_attribute_data =
+ reinterpret_cast<const int32_t *>(
+ attribute.GetAddress(AttributeValueIndex(0)));
+
+ const int num_values = target_attribute->size();
+
+ for (uint32_t i = 0; i < num_values; ++i) {
+ for (int c = 0; c < num_components; ++c) {
+ float value =
+ dequantizer.DequantizeFloat(source_attribute_data[quant_val_id++]);
+ value = value + min_values_[c];
+ att_val[c] = value;
+ }
+ // Store the floating point value into the attribute buffer.
+ target_attribute->buffer()->Write(out_byte_pos, att_val.get(), entry_size);
+ out_byte_pos += entry_size;
+ }
+ return true;
+}
+
+bool AttributeQuantizationTransform::IsQuantizationValid(
+ int quantization_bits) {
+ // Currently we allow only up to 30 bit quantization.
+ return quantization_bits >= 1 && quantization_bits <= 30;
+}
+
+bool AttributeQuantizationTransform::SetParameters(int quantization_bits,
const float *min_values,
int num_components,
float range) {
+ if (!IsQuantizationValid(quantization_bits)) {
+ return false;
+ }
quantization_bits_ = quantization_bits;
min_values_.assign(min_values, min_values + num_components);
range_ = range;
+ return true;
}
bool AttributeQuantizationTransform::ComputeParameters(
@@ -65,6 +125,9 @@ bool AttributeQuantizationTransform::ComputeParameters(
if (quantization_bits_ != -1) {
return false; // already initialized.
}
+ if (!IsQuantizationValid(quantization_bits)) {
+ return false;
+ }
quantization_bits_ = quantization_bits;
const int num_components = attribute.num_components();
@@ -121,20 +184,37 @@ bool AttributeQuantizationTransform::EncodeParameters(
return false;
}
-std::unique_ptr<PointAttribute>
-AttributeQuantizationTransform::GeneratePortableAttribute(
- const PointAttribute &attribute, int num_points) const {
+bool AttributeQuantizationTransform::DecodeParameters(
+ const PointAttribute &attribute, DecoderBuffer *decoder_buffer) {
+ min_values_.resize(attribute.num_components());
+ if (!decoder_buffer->Decode(&min_values_[0],
+ sizeof(float) * min_values_.size())) {
+ return false;
+ }
+ if (!decoder_buffer->Decode(&range_)) {
+ return false;
+ }
+ uint8_t quantization_bits;
+ if (!decoder_buffer->Decode(&quantization_bits)) {
+ return false;
+ }
+ if (!IsQuantizationValid(quantization_bits)) {
+ return false;
+ }
+ quantization_bits_ = quantization_bits;
+ return true;
+}
+
+void AttributeQuantizationTransform::GeneratePortableAttribute(
+ const PointAttribute &attribute, int num_points,
+ PointAttribute *target_attribute) const {
DRACO_DCHECK(is_initialized());
- // Allocate portable attribute.
- const int num_entries = num_points;
const int num_components = attribute.num_components();
- std::unique_ptr<PointAttribute> portable_attribute =
- InitPortableAttribute(num_entries, num_components, 0, attribute, true);
// Quantize all values using the order given by point_ids.
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
- portable_attribute->GetAddress(AttributeValueIndex(0)));
+ target_attribute->GetAddress(AttributeValueIndex(0)));
const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1;
Quantizer quantizer;
quantizer.Init(range(), max_quantized_value);
@@ -149,24 +229,18 @@ AttributeQuantizationTransform::GeneratePortableAttribute(
portable_attribute_data[dst_index++] = q_val;
}
}
- return portable_attribute;
}
-std::unique_ptr<PointAttribute>
-AttributeQuantizationTransform::GeneratePortableAttribute(
+void AttributeQuantizationTransform::GeneratePortableAttribute(
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
- int num_points) const {
+ int num_points, PointAttribute *target_attribute) const {
DRACO_DCHECK(is_initialized());
- // Allocate portable attribute.
- const int num_entries = static_cast<int>(point_ids.size());
const int num_components = attribute.num_components();
- std::unique_ptr<PointAttribute> portable_attribute = InitPortableAttribute(
- num_entries, num_components, num_points, attribute, true);
// Quantize all values using the order given by point_ids.
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
- portable_attribute->GetAddress(AttributeValueIndex(0)));
+ target_attribute->GetAddress(AttributeValueIndex(0)));
const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1;
Quantizer quantizer;
quantizer.Init(range(), max_quantized_value);
@@ -181,7 +255,6 @@ AttributeQuantizationTransform::GeneratePortableAttribute(
portable_attribute_data[dst_index++] = q_val;
}
}
- return portable_attribute;
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h
index 934856f2db7..f1122b680ab 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h
+++ b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h
@@ -37,14 +37,24 @@ class AttributeQuantizationTransform : public AttributeTransform {
void CopyToAttributeTransformData(
AttributeTransformData *out_data) const override;
- void SetParameters(int quantization_bits, const float *min_values,
+ bool TransformAttribute(const PointAttribute &attribute,
+ const std::vector<PointIndex> &point_ids,
+ PointAttribute *target_attribute) override;
+
+ bool InverseTransformAttribute(const PointAttribute &attribute,
+ PointAttribute *target_attribute) override;
+
+ bool SetParameters(int quantization_bits, const float *min_values,
int num_components, float range);
bool ComputeParameters(const PointAttribute &attribute,
const int quantization_bits);
// Encode relevant parameters into buffer.
- bool EncodeParameters(EncoderBuffer *encoder_buffer) const;
+ bool EncodeParameters(EncoderBuffer *encoder_buffer) const override;
+
+ bool DecodeParameters(const PointAttribute &attribute,
+ DecoderBuffer *decoder_buffer) override;
int32_t quantization_bits() const { return quantization_bits_; }
float min_value(int axis) const { return min_values_[axis]; }
@@ -52,16 +62,30 @@ class AttributeQuantizationTransform : public AttributeTransform {
float range() const { return range_; }
bool is_initialized() const { return quantization_bits_ != -1; }
+ protected:
// Create portable attribute using 1:1 mapping between points in the input and
// output attribute.
- std::unique_ptr<PointAttribute> GeneratePortableAttribute(
- const PointAttribute &attribute, int num_points) const;
+ void GeneratePortableAttribute(const PointAttribute &attribute,
+ int num_points,
+ PointAttribute *target_attribute) const;
// Create portable attribute using custom mapping between input and output
// points.
- std::unique_ptr<PointAttribute> GeneratePortableAttribute(
- const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
- int num_points) const;
+ void GeneratePortableAttribute(const PointAttribute &attribute,
+ const std::vector<PointIndex> &point_ids,
+ int num_points,
+ PointAttribute *target_attribute) const;
+
+ DataType GetTransformedDataType(
+ const PointAttribute &attribute) const override {
+ return DT_UINT32;
+ }
+ int GetTransformedNumComponents(
+ const PointAttribute &attribute) const override {
+ return attribute.num_components();
+ }
+
+ static bool IsQuantizationValid(int quantization_bits);
private:
int32_t quantization_bits_;
diff --git a/extern/draco/draco/src/draco/attributes/attribute_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_transform.cc
index 55af630ac07..fb2ed18297a 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_transform.cc
+++ b/extern/draco/draco/src/draco/attributes/attribute_transform.cc
@@ -24,21 +24,18 @@ bool AttributeTransform::TransferToAttribute(PointAttribute *attribute) const {
return true;
}
-std::unique_ptr<PointAttribute> AttributeTransform::InitPortableAttribute(
- int num_entries, int num_components, int num_points,
- const PointAttribute &attribute, bool is_unsigned) const {
- const DataType dt = is_unsigned ? DT_UINT32 : DT_INT32;
- GeometryAttribute va;
- va.Init(attribute.attribute_type(), nullptr, num_components, dt, false,
+std::unique_ptr<PointAttribute> AttributeTransform::InitTransformedAttribute(
+ const PointAttribute &src_attribute, int num_entries) {
+ const int num_components = GetTransformedNumComponents(src_attribute);
+ const DataType dt = GetTransformedDataType(src_attribute);
+ GeometryAttribute ga;
+ ga.Init(src_attribute.attribute_type(), nullptr, num_components, dt, false,
num_components * DataTypeLength(dt), 0);
- std::unique_ptr<PointAttribute> portable_attribute(new PointAttribute(va));
- portable_attribute->Reset(num_entries);
- if (num_points) {
- portable_attribute->SetExplicitMapping(num_points);
- } else {
- portable_attribute->SetIdentityMapping();
- }
- return portable_attribute;
+ std::unique_ptr<PointAttribute> transformed_attribute(new PointAttribute(ga));
+ transformed_attribute->Reset(num_entries);
+ transformed_attribute->SetIdentityMapping();
+ transformed_attribute->set_unique_id(src_attribute.unique_id());
+ return transformed_attribute;
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/attributes/attribute_transform.h b/extern/draco/draco/src/draco/attributes/attribute_transform.h
index d746fbf6eea..62aad60db91 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_transform.h
+++ b/extern/draco/draco/src/draco/attributes/attribute_transform.h
@@ -17,6 +17,8 @@
#include "draco/attributes/attribute_transform_data.h"
#include "draco/attributes/point_attribute.h"
+#include "draco/core/decoder_buffer.h"
+#include "draco/core/encoder_buffer.h"
namespace draco {
@@ -35,10 +37,38 @@ class AttributeTransform {
AttributeTransformData *out_data) const = 0;
bool TransferToAttribute(PointAttribute *attribute) const;
+ // Applies the transform to |attribute| and stores the result in
+ // |target_attribute|. |point_ids| is an optional vector that can be used to
+ // remap values during the transform.
+ virtual bool TransformAttribute(const PointAttribute &attribute,
+ const std::vector<PointIndex> &point_ids,
+ PointAttribute *target_attribute) = 0;
+
+ // Applies an inverse transform to |attribute| and stores the result in
+ // |target_attribute|. In this case, |attribute| is an attribute that was
+ // already transformed (e.g. quantized) and |target_attribute| is the
+ // attribute before the transformation.
+ virtual bool InverseTransformAttribute(const PointAttribute &attribute,
+ PointAttribute *target_attribute) = 0;
+
+ // Encodes all data needed by the transformation into the |encoder_buffer|.
+ virtual bool EncodeParameters(EncoderBuffer *encoder_buffer) const = 0;
+
+ // Decodes all data needed to transform |attribute| back to the original
+ // format.
+ virtual bool DecodeParameters(const PointAttribute &attribute,
+ DecoderBuffer *decoder_buffer) = 0;
+
+ // Initializes a transformed attribute that can be used as target in the
+ // TransformAttribute() function call.
+ virtual std::unique_ptr<PointAttribute> InitTransformedAttribute(
+ const PointAttribute &src_attribute, int num_entries);
+
protected:
- std::unique_ptr<PointAttribute> InitPortableAttribute(
- int num_entries, int num_components, int num_points,
- const PointAttribute &attribute, bool is_unsigned) const;
+ virtual DataType GetTransformedDataType(
+ const PointAttribute &attribute) const = 0;
+ virtual int GetTransformedNumComponents(
+ const PointAttribute &attribute) const = 0;
};
} // namespace draco
diff --git a/extern/draco/draco/src/draco/attributes/geometry_attribute.cc b/extern/draco/draco/src/draco/attributes/geometry_attribute.cc
index f7ed6a86915..b624784261d 100644
--- a/extern/draco/draco/src/draco/attributes/geometry_attribute.cc
+++ b/extern/draco/draco/src/draco/attributes/geometry_attribute.cc
@@ -43,10 +43,6 @@ void GeometryAttribute::Init(GeometryAttribute::Type attribute_type,
}
bool GeometryAttribute::CopyFrom(const GeometryAttribute &src_att) {
- if (buffer_ == nullptr || src_att.buffer_ == nullptr) {
- return false;
- }
- buffer_->Update(src_att.buffer_->data(), src_att.buffer_->data_size());
num_components_ = src_att.num_components_;
data_type_ = src_att.data_type_;
normalized_ = src_att.normalized_;
@@ -55,6 +51,14 @@ bool GeometryAttribute::CopyFrom(const GeometryAttribute &src_att) {
attribute_type_ = src_att.attribute_type_;
buffer_descriptor_ = src_att.buffer_descriptor_;
unique_id_ = src_att.unique_id_;
+ if (src_att.buffer_ == nullptr) {
+ buffer_ = nullptr;
+ } else {
+ if (buffer_ == nullptr) {
+ return false;
+ }
+ buffer_->Update(src_att.buffer_->data(), src_att.buffer_->data_size());
+ }
return true;
}
diff --git a/extern/draco/draco/src/draco/attributes/geometry_attribute.h b/extern/draco/draco/src/draco/attributes/geometry_attribute.h
index b94ba8e22dd..c5faccc1b83 100644
--- a/extern/draco/draco/src/draco/attributes/geometry_attribute.h
+++ b/extern/draco/draco/src/draco/attributes/geometry_attribute.h
@@ -21,6 +21,7 @@
#include "draco/attributes/geometry_indices.h"
#include "draco/core/data_buffer.h"
#include "draco/core/hash_utils.h"
+#include "draco/draco_features.h"
namespace draco {
@@ -51,6 +52,16 @@ class GeometryAttribute {
// predefined use case. Such attributes are often used for a shader specific
// data.
GENERIC,
+#ifdef DRACO_TRANSCODER_SUPPORTED
+ // TODO(ostava): Adding a new attribute would be bit-stream change for GLTF.
+ // Older decoders wouldn't know what to do with this attribute type. This
+ // should be open-sourced only when we are ready to increase our bit-stream
+ // version.
+ TANGENT,
+ MATERIAL,
+ JOINTS,
+ WEIGHTS,
+#endif
// Total number of different attribute types.
// Always keep behind all named attributes.
NAMED_ATTRIBUTES_COUNT,
@@ -111,6 +122,9 @@ class GeometryAttribute {
const int64_t byte_pos = GetBytePos(att_index);
return buffer_->data() + byte_pos;
}
+ inline bool IsAddressValid(const uint8_t *address) const {
+ return ((buffer_->data() + buffer_->data_size()) > address);
+ }
// Fills out_data with the raw value of the requested attribute entry.
// out_data must be at least byte_stride_ long.
@@ -263,7 +277,35 @@ class GeometryAttribute {
// Convert all components available in both the original and output formats.
for (int i = 0; i < std::min(num_components_, out_num_components); ++i) {
+ if (!IsAddressValid(src_address)) {
+ return false;
+ }
const T in_value = *reinterpret_cast<const T *>(src_address);
+
+ // Make sure the in_value fits within the range of values that OutT
+ // is able to represent. Perform the check only for integral types.
+ if (std::is_integral<T>::value && std::is_integral<OutT>::value) {
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4804)
+#endif
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wbool-compare"
+#endif
+ static constexpr OutT kOutMin =
+ std::is_signed<T>::value ? std::numeric_limits<OutT>::lowest() : 0;
+ if (in_value < kOutMin || in_value > std::numeric_limits<OutT>::max()) {
+ return false;
+ }
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+ }
+
out_value[i] = static_cast<OutT>(in_value);
// When converting integer to floating point, normalize the value if
// necessary.
diff --git a/extern/draco/draco/src/draco/attributes/point_attribute.cc b/extern/draco/draco/src/draco/attributes/point_attribute.cc
index b28f860c15d..e54ab54278f 100644
--- a/extern/draco/draco/src/draco/attributes/point_attribute.cc
+++ b/extern/draco/draco/src/draco/attributes/point_attribute.cc
@@ -222,4 +222,47 @@ AttributeValueIndex::ValueType PointAttribute::DeduplicateFormattedValues(
}
#endif
+#ifdef DRACO_TRANSCODER_SUPPORTED
+void PointAttribute::RemoveUnusedValues() {
+ if (is_mapping_identity()) {
+ return; // For identity mapping, all values are always used.
+ }
+ // For explicit mapping we need to check if any point is mapped to a value.
+ // If not we can delete the value.
+ IndexTypeVector<AttributeValueIndex, bool> is_value_used(size(), false);
+ int num_used_values = 0;
+ for (PointIndex pi(0); pi < indices_map_.size(); ++pi) {
+ const AttributeValueIndex avi = indices_map_[pi];
+ if (!is_value_used[avi]) {
+ is_value_used[avi] = true;
+ num_used_values++;
+ }
+ }
+ if (num_used_values == size()) {
+ return; // All values are used.
+ }
+
+ // Remap the values and update the point to value mapping.
+ IndexTypeVector<AttributeValueIndex, AttributeValueIndex>
+ old_to_new_value_map(size(), kInvalidAttributeValueIndex);
+ AttributeValueIndex new_avi(0);
+ for (AttributeValueIndex avi(0); avi < size(); ++avi) {
+ if (!is_value_used[avi]) {
+ continue;
+ }
+ if (avi != new_avi) {
+ SetAttributeValue(new_avi, GetAddress(avi));
+ }
+ old_to_new_value_map[avi] = new_avi++;
+ }
+
+ // Remap all points to the new attribute values.
+ for (PointIndex pi(0); pi < indices_map_.size(); ++pi) {
+ indices_map_[pi] = old_to_new_value_map[indices_map_[pi]];
+ }
+
+ num_unique_entries_ = num_used_values;
+}
+#endif
+
} // namespace draco
diff --git a/extern/draco/draco/src/draco/attributes/point_attribute.h b/extern/draco/draco/src/draco/attributes/point_attribute.h
index ee36620313e..d55c50c8a57 100644
--- a/extern/draco/draco/src/draco/attributes/point_attribute.h
+++ b/extern/draco/draco/src/draco/attributes/point_attribute.h
@@ -133,6 +133,12 @@ class PointAttribute : public GeometryAttribute {
return attribute_transform_data_.get();
}
+#ifdef DRACO_TRANSCODER_SUPPORTED
+ // Removes unused values from the attribute. Value is unused when no point
+ // is mapped to the value. Only applicable when the mapping is not identity.
+ void RemoveUnusedValues();
+#endif
+
private:
#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
template <typename T>
diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc
index ce5b8b9c756..007dd2f4303 100644
--- a/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc
@@ -43,9 +43,18 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) {
return false;
}
}
+
+ // Check that decoded number of attributes is valid.
if (num_attributes == 0) {
return false;
}
+ if (num_attributes > 5 * in_buffer->remaining_size()) {
+ // The decoded number of attributes is unreasonably high, because at least
+ // five bytes of attribute descriptor data per attribute are expected.
+ return false;
+ }
+
+ // Decode attribute descriptor data.
point_attribute_ids_.resize(num_attributes);
PointCloud *pc = point_cloud_;
for (uint32_t i = 0; i < num_attributes; ++i) {
@@ -69,9 +78,14 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) {
if (data_type == DT_INVALID || data_type >= DT_TYPES_COUNT) {
return false;
}
- const DataType draco_dt = static_cast<DataType>(data_type);
- // Add the attribute to the point cloud
+ // Check decoded attribute descriptor data.
+ if (num_components == 0) {
+ return false;
+ }
+
+ // Add the attribute to the point cloud.
+ const DataType draco_dt = static_cast<DataType>(data_type);
GeometryAttribute ga;
ga.Init(static_cast<GeometryAttribute::Type>(att_type), nullptr,
num_components, draco_dt, normalized > 0,
@@ -90,7 +104,9 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) {
} else
#endif
{
- DecodeVarint(&unique_id, in_buffer);
+ if (!DecodeVarint(&unique_id, in_buffer)) {
+ return false;
+ }
ga.set_unique_id(unique_id);
}
const int att_id = pc->AddAttribute(
diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc
index 797c62f30aa..480e3ff3436 100644
--- a/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc
@@ -15,14 +15,16 @@
#include "draco/compression/attributes/attributes_encoder.h"
#include "draco/core/varint_encoding.h"
+#include "draco/draco_features.h"
namespace draco {
AttributesEncoder::AttributesEncoder()
: point_cloud_encoder_(nullptr), point_cloud_(nullptr) {}
-AttributesEncoder::AttributesEncoder(int att_id) : AttributesEncoder() {
- AddAttributeId(att_id);
+AttributesEncoder::AttributesEncoder(int point_attrib_id)
+ : AttributesEncoder() {
+ AddAttributeId(point_attrib_id);
}
bool AttributesEncoder::Init(PointCloudEncoder *encoder, const PointCloud *pc) {
@@ -37,7 +39,15 @@ bool AttributesEncoder::EncodeAttributesEncoderData(EncoderBuffer *out_buffer) {
for (uint32_t i = 0; i < num_attributes(); ++i) {
const int32_t att_id = point_attribute_ids_[i];
const PointAttribute *const pa = point_cloud_->attribute(att_id);
- out_buffer->Encode(static_cast<uint8_t>(pa->attribute_type()));
+ GeometryAttribute::Type type = pa->attribute_type();
+#ifdef DRACO_TRANSCODER_SUPPORTED
+ // Attribute types TANGENT, MATERIAL, JOINTS, and WEIGHTS are not supported
+ // in the official bitstream. They will be encoded as GENERIC.
+ if (type > GeometryAttribute::GENERIC) {
+ type = GeometryAttribute::GENERIC;
+ }
+#endif
+ out_buffer->Encode(static_cast<uint8_t>(type));
out_buffer->Encode(static_cast<uint8_t>(pa->data_type()));
out_buffer->Encode(static_cast<uint8_t>(pa->num_components()));
out_buffer->Encode(static_cast<uint8_t>(pa->normalized()));
diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc
index 99469f94590..c7c96d77007 100644
--- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc
@@ -72,7 +72,7 @@ class PointAttributeVectorOutputIterator {
Self &operator*() { return *this; }
// Still needed in some cases.
- // TODO(hemmer): remove.
+ // TODO(b/199760123): Remove.
// hardcoded to 3 based on legacy usage.
const Self &operator=(const VectorD<CoeffT, 3> &val) {
DRACO_DCHECK_EQ(attributes_.size(), 1); // Expect only ONE attribute.
@@ -278,8 +278,10 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
return false;
}
AttributeQuantizationTransform transform;
- transform.SetParameters(quantization_bits, min_value.data(),
- num_components, max_value_dif);
+ if (!transform.SetParameters(quantization_bits, min_value.data(),
+ num_components, max_value_dif)) {
+ return false;
+ }
const int num_transforms =
static_cast<int>(attribute_quantization_transforms_.size());
if (!transform.TransferToAttribute(
@@ -293,7 +295,9 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
// Decode transform data for signed integer attributes.
for (int i = 0; i < min_signed_values_.size(); ++i) {
int32_t val;
- DecodeVarint(&val, in_buffer);
+ if (!DecodeVarint(&val, in_buffer)) {
+ return false;
+ }
min_signed_values_[i] = val;
}
return true;
@@ -353,8 +357,9 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
return false;
}
if (6 < compression_level) {
- LOGE("KdTreeAttributesDecoder: compression level %i not supported.\n",
- compression_level);
+ DRACO_LOGE(
+ "KdTreeAttributesDecoder: compression level %i not supported.\n",
+ compression_level);
return false;
}
@@ -371,7 +376,7 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
GetDecoder()->point_cloud()->attribute(att_id);
attr->Reset(num_points);
attr->SetIdentityMapping();
- };
+ }
PointAttributeVectorOutputIterator<uint32_t> out_it(atts);
diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc
index 0f9c31565e5..b70deb9e01f 100644
--- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc
@@ -71,16 +71,21 @@ bool KdTreeAttributesEncoder::TransformAttributesToPortableFormat() {
att->num_components(), range);
} else {
// Compute quantization settings from the attribute values.
- attribute_quantization_transform.ComputeParameters(*att,
- quantization_bits);
+ if (!attribute_quantization_transform.ComputeParameters(
+ *att, quantization_bits)) {
+ return false;
+ }
}
attribute_quantization_transforms_.push_back(
attribute_quantization_transform);
// Store the quantized attribute in an array that will be used when we do
// the actual encoding of the data.
- quantized_portable_attributes_.push_back(
- attribute_quantization_transform.GeneratePortableAttribute(
- *att, static_cast<int>(num_points)));
+ auto portable_att =
+ attribute_quantization_transform.InitTransformedAttribute(*att,
+ num_points);
+ attribute_quantization_transform.TransformAttribute(*att, {},
+ portable_att.get());
+ quantized_portable_attributes_.push_back(std::move(portable_att));
} else if (att->data_type() == DT_INT32 || att->data_type() == DT_INT16 ||
att->data_type() == DT_INT8) {
// For signed types, find the minimum value for each component. These
diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h
index 8b4c4e2faab..80748e0bf5d 100644
--- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h
+++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_
-#define DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_
+#ifndef DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_
+#define DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_
#include "draco/attributes/attribute_quantization_transform.h"
#include "draco/compression/attributes/attributes_encoder.h"
@@ -48,4 +48,4 @@ class KdTreeAttributesEncoder : public AttributesEncoder {
} // namespace draco
-#endif // DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_
+#endif // DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_
diff --git a/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h b/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h
index 32e27c711e3..be5ee5b09e3 100644
--- a/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h
+++ b/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h
@@ -53,6 +53,7 @@ class OctahedronToolBox {
: quantization_bits_(-1),
max_quantized_value_(-1),
max_value_(-1),
+ dequantization_scale_(1.f),
center_value_(-1) {}
bool SetQuantizationBits(int32_t q) {
@@ -62,6 +63,7 @@ class OctahedronToolBox {
quantization_bits_ = q;
max_quantized_value_ = (1 << quantization_bits_) - 1;
max_value_ = max_quantized_value_ - 1;
+ dequantization_scale_ = 2.f / max_value_;
center_value_ = max_value_ / 2;
return true;
}
@@ -192,64 +194,11 @@ class OctahedronToolBox {
}
}
- // TODO(b/149328891): Change function to not use templates as |T| is only
- // float.
- template <typename T>
- void OctaherdalCoordsToUnitVector(T in_s, T in_t, T *out_vector) const {
- DRACO_DCHECK_GE(in_s, 0);
- DRACO_DCHECK_GE(in_t, 0);
- DRACO_DCHECK_LE(in_s, 1);
- DRACO_DCHECK_LE(in_t, 1);
- T s = in_s;
- T t = in_t;
- T spt = s + t;
- T smt = s - t;
- T x_sign = 1.0;
- if (spt >= 0.5 && spt <= 1.5 && smt >= -0.5 && smt <= 0.5) {
- // Right hemisphere. Don't do anything.
- } else {
- // Left hemisphere.
- x_sign = -1.0;
- if (spt <= 0.5) {
- s = 0.5 - in_t;
- t = 0.5 - in_s;
- } else if (spt >= 1.5) {
- s = 1.5 - in_t;
- t = 1.5 - in_s;
- } else if (smt <= -0.5) {
- s = in_t - 0.5;
- t = in_s + 0.5;
- } else {
- s = in_t + 0.5;
- t = in_s - 0.5;
- }
- spt = s + t;
- smt = s - t;
- }
- const T y = 2.0 * s - 1.0;
- const T z = 2.0 * t - 1.0;
- const T x = std::min(std::min(2.0 * spt - 1.0, 3.0 - 2.0 * spt),
- std::min(2.0 * smt + 1.0, 1.0 - 2.0 * smt)) *
- x_sign;
- // Normalize the computed vector.
- const T normSquared = x * x + y * y + z * z;
- if (normSquared < 1e-6) {
- out_vector[0] = 0;
- out_vector[1] = 0;
- out_vector[2] = 0;
- } else {
- const T d = 1.0 / std::sqrt(normSquared);
- out_vector[0] = x * d;
- out_vector[1] = y * d;
- out_vector[2] = z * d;
- }
- }
-
- template <typename T>
- void QuantizedOctaherdalCoordsToUnitVector(int32_t in_s, int32_t in_t,
- T *out_vector) const {
- T scale = 1.0 / static_cast<T>(max_value_);
- OctaherdalCoordsToUnitVector(in_s * scale, in_t * scale, out_vector);
+ inline void QuantizedOctahedralCoordsToUnitVector(int32_t in_s, int32_t in_t,
+ float *out_vector) const {
+ OctahedralCoordsToUnitVector(in_s * dequantization_scale_ - 1.f,
+ in_t * dequantization_scale_ - 1.f,
+ out_vector);
}
// |s| and |t| are expected to be signed values.
@@ -333,9 +282,77 @@ class OctahedronToolBox {
int32_t center_value() const { return center_value_; }
private:
+ inline void OctahedralCoordsToUnitVector(float in_s_scaled, float in_t_scaled,
+ float *out_vector) const {
+ // Background about the encoding:
+ // A normal is encoded in a normalized space <s, t> depicted below. The
+ // encoding correponds to an octahedron that is unwrapped to a 2D plane.
+ // During encoding, a normal is projected to the surface of the octahedron
+ // and the projection is then unwrapped to the 2D plane. Decoding is the
+ // reverse of this process.
+ // All points in the central diamond are located on triangles on the
+ // right "hemisphere" of the octahedron while all points outside of the
+ // diamond are on the left hemisphere (basically, they would have to be
+ // wrapped along the diagonal edges to form the octahedron). The central
+ // point corresponds to the right most vertex of the octahedron and all
+ // corners of the plane correspond to the left most vertex of the
+ // octahedron.
+ //
+ // t
+ // ^ *-----*-----*
+ // | | /|\ |
+ // | / | \ |
+ // | / | \ |
+ // | / | \ |
+ // *-----*---- *
+ // | \ | / |
+ // | \ | / |
+ // | \ | / |
+ // | \|/ |
+ // *-----*-----* --> s
+
+ // Note that the input |in_s_scaled| and |in_t_scaled| are already scaled to
+ // <-1, 1> range. This way, the central point is at coordinate (0, 0).
+ float y = in_s_scaled;
+ float z = in_t_scaled;
+
+ // Remaining coordinate can be computed by projecting the (y, z) values onto
+ // the surface of the octahedron.
+ const float x = 1.f - std::abs(y) - std::abs(z);
+
+ // |x| is essentially a signed distance from the diagonal edges of the
+ // diamond shown on the figure above. It is positive for all points in the
+ // diamond (right hemisphere) and negative for all points outside the
+ // diamond (left hemisphere). For all points on the left hemisphere we need
+ // to update their (y, z) coordinates to account for the wrapping along
+ // the edges of the diamond.
+ float x_offset = -x;
+ x_offset = x_offset < 0 ? 0 : x_offset;
+
+ // This will do nothing for the points on the right hemisphere but it will
+ // mirror the (y, z) location along the nearest diagonal edge of the
+ // diamond.
+ y += y < 0 ? x_offset : -x_offset;
+ z += z < 0 ? x_offset : -x_offset;
+
+ // Normalize the computed vector.
+ const float norm_squared = x * x + y * y + z * z;
+ if (norm_squared < 1e-6) {
+ out_vector[0] = 0;
+ out_vector[1] = 0;
+ out_vector[2] = 0;
+ } else {
+ const float d = 1.0f / std::sqrt(norm_squared);
+ out_vector[0] = x * d;
+ out_vector[1] = y * d;
+ out_vector[2] = z * d;
+ }
+ }
+
int32_t quantization_bits_;
int32_t max_quantized_value_;
int32_t max_value_;
+ float dequantization_scale_;
int32_t center_value_;
};
} // namespace draco
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h
index f712952556a..2960a5e71b4 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_
-#define DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_
+#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DATA_H_
+#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DATA_H_
#include "draco/mesh/corner_table.h"
#include "draco/mesh/mesh.h"
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h
index bf1a6146111..775eded6b55 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h
@@ -69,7 +69,14 @@ class MeshPredictionSchemeGeometricNormalPredictorArea
// Computing cross product.
const VectorD<int64_t, 3> cross = CrossProduct(delta_next, delta_prev);
- normal = normal + cross;
+
+ // Prevent signed integer overflows by doing math as unsigned.
+ auto normal_data = reinterpret_cast<uint64_t *>(normal.data());
+ auto cross_data = reinterpret_cast<const uint64_t *>(cross.data());
+ normal_data[0] = normal_data[0] + cross_data[0];
+ normal_data[1] = normal_data[1] + cross_data[1];
+ normal_data[2] = normal_data[2] + cross_data[2];
+
cit.Next();
}
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h
index 485d457ccf6..fd10fb524b3 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h
@@ -60,8 +60,13 @@ inline bool ComputeParallelogramPrediction(
const int v_next_off = vert_next * num_components;
const int v_prev_off = vert_prev * num_components;
for (int c = 0; c < num_components; ++c) {
- out_prediction[c] = (in_data[v_next_off + c] + in_data[v_prev_off + c]) -
- in_data[v_opp_off + c];
+ const int64_t in_data_next_off = in_data[v_next_off + c];
+ const int64_t in_data_prev_off = in_data[v_prev_off + c];
+ const int64_t in_data_opp_off = in_data[v_opp_off + c];
+ const int64_t result =
+ (in_data_next_off + in_data_prev_off) - in_data_opp_off;
+
+ out_prediction[c] = static_cast<DataTypeT>(result);
}
return true;
}
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h
index 5d8a5060133..f05e5ddd713 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h
@@ -156,6 +156,13 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
const VectorD<int64_t, 2> x_uv =
n_uv * pn_norm2_squared + (cn_dot_pn * pn_uv);
+ const int64_t pn_absmax_element =
+ std::max(std::max(std::abs(pn[0]), std::abs(pn[1])), std::abs(pn[2]));
+ if (cn_dot_pn > std::numeric_limits<int64_t>::max() / pn_absmax_element) {
+ // return false if squared length calculation would overflow.
+ return false;
+ }
+
// Compute squared length of vector CX in position coordinate system:
const VectorD<int64_t, 3> x_pos =
next_pos + (cn_dot_pn * pn) / pn_norm2_squared;
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc
index 428340da013..60429d5c779 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc
@@ -18,34 +18,51 @@ namespace draco {
PredictionSchemeMethod SelectPredictionMethod(
int att_id, const PointCloudEncoder *encoder) {
- if (encoder->options()->GetSpeed() >= 10) {
+ return SelectPredictionMethod(att_id, *encoder->options(), encoder);
+}
+
+PredictionSchemeMethod SelectPredictionMethod(
+ int att_id, const EncoderOptions &options,
+ const PointCloudEncoder *encoder) {
+ if (options.GetSpeed() >= 10) {
// Selected fastest, though still doing some compression.
return PREDICTION_DIFFERENCE;
}
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
// Use speed setting to select the best encoding method.
const PointAttribute *const att = encoder->point_cloud()->attribute(att_id);
- if (att->attribute_type() == GeometryAttribute::TEX_COORD) {
- if (encoder->options()->GetSpeed() < 4) {
+ if (att->attribute_type() == GeometryAttribute::TEX_COORD &&
+ att->num_components() == 2) {
+ if (options.GetSpeed() < 4) {
// Use texture coordinate prediction for speeds 0, 1, 2, 3.
return MESH_PREDICTION_TEX_COORDS_PORTABLE;
}
}
if (att->attribute_type() == GeometryAttribute::NORMAL) {
#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
- if (encoder->options()->GetSpeed() < 4) {
+ if (options.GetSpeed() < 4) {
// Use geometric normal prediction for speeds 0, 1, 2, 3.
- return MESH_PREDICTION_GEOMETRIC_NORMAL;
+ // For this prediction, the position attribute needs to be either
+ // integer or quantized as well.
+ const int pos_att_id = encoder->point_cloud()->GetNamedAttributeId(
+ GeometryAttribute::POSITION);
+ const PointAttribute *const pos_att =
+ encoder->point_cloud()->GetNamedAttribute(
+ GeometryAttribute::POSITION);
+ if (pos_att && (IsDataTypeIntegral(pos_att->data_type()) ||
+ options.GetAttributeInt(pos_att_id, "quantization_bits",
+ -1) > 0)) {
+ return MESH_PREDICTION_GEOMETRIC_NORMAL;
+ }
}
#endif
return PREDICTION_DIFFERENCE; // default
}
// Handle other attribute types.
- if (encoder->options()->GetSpeed() >= 8) {
+ if (options.GetSpeed() >= 8) {
return PREDICTION_DIFFERENCE;
}
- if (encoder->options()->GetSpeed() >= 2 ||
- encoder->point_cloud()->num_points() < 40) {
+ if (options.GetSpeed() >= 2 || encoder->point_cloud()->num_points() < 40) {
// Parallelogram prediction is used for speeds 2 - 7 or when the overhead
// of using constrained multi-parallelogram would be too high.
return MESH_PREDICTION_PARALLELOGRAM;
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h
index 40a7683aa0d..b7e21224fad 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h
@@ -38,6 +38,10 @@ namespace draco {
PredictionSchemeMethod SelectPredictionMethod(int att_id,
const PointCloudEncoder *encoder);
+PredictionSchemeMethod SelectPredictionMethod(int att_id,
+ const EncoderOptions &options,
+ const PointCloudEncoder *encoder);
+
// Factory class for creating mesh prediction schemes.
template <typename DataTypeT>
struct MeshPredictionSchemeEncoderFactory {
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h
index ab64bce7114..37aa9f76a9c 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_
-#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_
+#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_
+#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h"
#include "draco/core/encoder_buffer.h"
@@ -52,4 +52,4 @@ class PredictionSchemeTypedEncoderInterface
} // namespace draco
-#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_
+#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h
index 0a14d0d9ba4..e100c738a6c 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h
@@ -36,9 +36,25 @@ class PredictionSchemeWrapDecodingTransform
inline void ComputeOriginalValue(const DataTypeT *predicted_vals,
const CorrTypeT *corr_vals,
DataTypeT *out_original_vals) const {
+ // For now we assume both |DataTypeT| and |CorrTypeT| are equal.
+ static_assert(std::is_same<DataTypeT, CorrTypeT>::value,
+ "Predictions and corrections must have the same type.");
+
+ // The only valid implementation right now is for int32_t.
+ static_assert(std::is_same<DataTypeT, int32_t>::value,
+ "Only int32_t is supported for predicted values.");
+
predicted_vals = this->ClampPredictedValue(predicted_vals);
+
+ // Perform the wrapping using unsigned coordinates to avoid potential signed
+ // integer overflows caused by malformed input.
+ const uint32_t *const uint_predicted_vals =
+ reinterpret_cast<const uint32_t *>(predicted_vals);
+ const uint32_t *const uint_corr_vals =
+ reinterpret_cast<const uint32_t *>(corr_vals);
for (int i = 0; i < this->num_components(); ++i) {
- out_original_vals[i] = predicted_vals[i] + corr_vals[i];
+ out_original_vals[i] =
+ static_cast<DataTypeT>(uint_predicted_vals[i] + uint_corr_vals[i]);
if (out_original_vals[i] > this->max_value()) {
out_original_vals[i] -= this->max_dif();
} else if (out_original_vals[i] < this->min_value()) {
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h
index 26f61fbaf6a..979c63c3d11 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h
@@ -73,7 +73,7 @@ class PredictionSchemeWrapTransformBase {
return &clamped_value_[0];
}
- // TODO(hemmer): Consider refactoring to avoid this dummy.
+ // TODO(b/199760123): Consider refactoring to avoid this dummy.
int quantization_bits() const {
DRACO_DCHECK(false);
return -1;
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc
index 521935c1e99..7d5d1eeff26 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc
@@ -26,8 +26,8 @@ SequentialAttributeEncodersController::SequentialAttributeEncodersController(
: sequencer_(std::move(sequencer)) {}
SequentialAttributeEncodersController::SequentialAttributeEncodersController(
- std::unique_ptr<PointsSequencer> sequencer, int att_id)
- : AttributesEncoder(att_id), sequencer_(std::move(sequencer)) {}
+ std::unique_ptr<PointsSequencer> sequencer, int point_attrib_id)
+ : AttributesEncoder(point_attrib_id), sequencer_(std::move(sequencer)) {}
bool SequentialAttributeEncodersController::Init(PointCloudEncoder *encoder,
const PointCloud *pc) {
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc
index d01fb26aad4..17f32fc1612 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc
@@ -53,6 +53,11 @@ bool SequentialIntegerAttributeDecoder::DecodeValues(
if (!in_buffer->Decode(&prediction_transform_type)) {
return false;
}
+ // Check that decoded prediction scheme transform type is valid.
+ if (prediction_transform_type < PREDICTION_TRANSFORM_NONE ||
+ prediction_transform_type >= NUM_PREDICTION_SCHEME_TRANSFORM_TYPES) {
+ return false;
+ }
prediction_scheme_ = CreateIntPredictionScheme(
static_cast<PredictionSchemeMethod>(prediction_scheme_method),
static_cast<PredictionSchemeTransformType>(prediction_transform_type));
@@ -143,8 +148,9 @@ bool SequentialIntegerAttributeDecoder::DecodeIntegerValues(
return false;
}
for (size_t i = 0; i < num_values; ++i) {
- if (!in_buffer->Decode(portable_attribute_data + i, num_bytes))
+ if (!in_buffer->Decode(portable_attribute_data + i, num_bytes)) {
return false;
+ }
}
}
}
@@ -223,12 +229,13 @@ void SequentialIntegerAttributeDecoder::StoreTypedValues(uint32_t num_values) {
void SequentialIntegerAttributeDecoder::PreparePortableAttribute(
int num_entries, int num_components) {
- GeometryAttribute va;
- va.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32,
+ GeometryAttribute ga;
+ ga.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32,
false, num_components * DataTypeLength(DT_INT32), 0);
- std::unique_ptr<PointAttribute> port_att(new PointAttribute(va));
+ std::unique_ptr<PointAttribute> port_att(new PointAttribute(ga));
port_att->SetIdentityMapping();
port_att->Reset(num_entries);
+ port_att->set_unique_id(attribute()->unique_id());
SetPortableAttribute(std::move(port_att));
}
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc
index 2889e0521a0..e66a0a8a40a 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc
@@ -81,6 +81,9 @@ bool SequentialIntegerAttributeEncoder::TransformAttributeToPortableFormat(
value_to_value_map[orig_att->mapped_index(point_ids[i])] =
AttributeValueIndex(i);
}
+ if (portable_att->is_mapping_identity()) {
+ portable_att->SetExplicitMapping(encoder()->point_cloud()->num_points());
+ }
// Go over all points of the original attribute and update the mapping in
// the portable attribute.
for (PointIndex i(0); i < encoder()->point_cloud()->num_points(); ++i) {
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc
index 017344393dc..de36c1c36f2 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc
@@ -14,18 +14,17 @@
//
#include "draco/compression/attributes/sequential_normal_attribute_decoder.h"
-#include "draco/attributes/attribute_octahedron_transform.h"
#include "draco/compression/attributes/normal_compression_utils.h"
namespace draco {
-SequentialNormalAttributeDecoder::SequentialNormalAttributeDecoder()
- : quantization_bits_(-1) {}
+SequentialNormalAttributeDecoder::SequentialNormalAttributeDecoder() {}
bool SequentialNormalAttributeDecoder::Init(PointCloudDecoder *decoder,
int attribute_id) {
- if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id))
+ if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id)) {
return false;
+ }
// Currently, this encoder works only for 3-component normal vectors.
if (attribute()->num_components() != 3) {
return false;
@@ -41,11 +40,13 @@ bool SequentialNormalAttributeDecoder::DecodeIntegerValues(
const std::vector<PointIndex> &point_ids, DecoderBuffer *in_buffer) {
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
if (decoder()->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0)) {
- uint8_t quantization_bits;
- if (!in_buffer->Decode(&quantization_bits)) {
+ // Note: in older bitstreams, we do not have a PortableAttribute() decoded
+ // at this stage so we cannot pass it down to the DecodeParameters() call.
+ // It still works fine for octahedral transform because it does not need to
+ // use any data from the attribute.
+ if (!octahedral_transform_.DecodeParameters(*attribute(), in_buffer)) {
return false;
}
- quantization_bits_ = quantization_bits;
}
#endif
return SequentialIntegerAttributeDecoder::DecodeIntegerValues(point_ids,
@@ -56,39 +57,20 @@ bool SequentialNormalAttributeDecoder::DecodeDataNeededByPortableTransform(
const std::vector<PointIndex> &point_ids, DecoderBuffer *in_buffer) {
if (decoder()->bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 0)) {
// For newer file version, decode attribute transform data here.
- uint8_t quantization_bits;
- if (!in_buffer->Decode(&quantization_bits)) {
+ if (!octahedral_transform_.DecodeParameters(*GetPortableAttribute(),
+ in_buffer)) {
return false;
}
- quantization_bits_ = quantization_bits;
}
// Store the decoded transform data in portable attribute.
- AttributeOctahedronTransform octahedral_transform;
- octahedral_transform.SetParameters(quantization_bits_);
- return octahedral_transform.TransferToAttribute(portable_attribute());
+ return octahedral_transform_.TransferToAttribute(portable_attribute());
}
bool SequentialNormalAttributeDecoder::StoreValues(uint32_t num_points) {
// Convert all quantized values back to floats.
- const int num_components = attribute()->num_components();
- const int entry_size = sizeof(float) * num_components;
- float att_val[3];
- int quant_val_id = 0;
- int out_byte_pos = 0;
- const int32_t *const portable_attribute_data = GetPortableAttributeData();
- OctahedronToolBox octahedron_tool_box;
- if (!octahedron_tool_box.SetQuantizationBits(quantization_bits_))
- return false;
- for (uint32_t i = 0; i < num_points; ++i) {
- const int32_t s = portable_attribute_data[quant_val_id++];
- const int32_t t = portable_attribute_data[quant_val_id++];
- octahedron_tool_box.QuantizedOctaherdalCoordsToUnitVector(s, t, att_val);
- // Store the decoded floating point value into the attribute buffer.
- attribute()->buffer()->Write(out_byte_pos, att_val, entry_size);
- out_byte_pos += entry_size;
- }
- return true;
+ return octahedral_transform_.InverseTransformAttribute(
+ *GetPortableAttribute(), attribute());
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h
index 860eacb4c84..8c2d801b763 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h
@@ -15,6 +15,7 @@
#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_
#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_
+#include "draco/attributes/attribute_octahedron_transform.h"
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h"
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h"
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h"
@@ -42,7 +43,7 @@ class SequentialNormalAttributeDecoder
bool StoreValues(uint32_t num_points) override;
private:
- int32_t quantization_bits_;
+ AttributeOctahedronTransform octahedral_transform_;
std::unique_ptr<PredictionSchemeTypedDecoderInterface<int32_t>>
CreateIntPredictionScheme(
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc
index 23fa8bb7b39..3c5ef0ebcbc 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc
@@ -20,8 +20,9 @@ namespace draco {
bool SequentialNormalAttributeEncoder::Init(PointCloudEncoder *encoder,
int attribute_id) {
- if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id))
+ if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id)) {
return false;
+ }
// Currently this encoder works only for 3-component normal vectors.
if (attribute()->num_components() != 3) {
return false;
@@ -44,9 +45,13 @@ bool SequentialNormalAttributeEncoder::EncodeDataNeededByPortableTransform(
bool SequentialNormalAttributeEncoder::PrepareValues(
const std::vector<PointIndex> &point_ids, int num_points) {
- SetPortableAttribute(
- attribute_octahedron_transform_.GeneratePortableAttribute(
- *(attribute()), point_ids, num_points));
+ auto portable_att = attribute_octahedron_transform_.InitTransformedAttribute(
+ *(attribute()), point_ids.size());
+ if (!attribute_octahedron_transform_.TransformAttribute(
+ *(attribute()), point_ids, portable_att.get())) {
+ return false;
+ }
+ SetPortableAttribute(std::move(portable_att));
return true;
}
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc
index bf925c4a595..3d306e7dae6 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc
@@ -14,13 +14,12 @@
//
#include "draco/compression/attributes/sequential_quantization_attribute_decoder.h"
-#include "draco/attributes/attribute_quantization_transform.h"
#include "draco/core/quantization_utils.h"
namespace draco {
-SequentialQuantizationAttributeDecoder::SequentialQuantizationAttributeDecoder()
- : quantization_bits_(-1), max_value_dif_(0.f) {}
+SequentialQuantizationAttributeDecoder::
+ SequentialQuantizationAttributeDecoder() {}
bool SequentialQuantizationAttributeDecoder::Init(PointCloudDecoder *decoder,
int attribute_id) {
@@ -59,62 +58,31 @@ bool SequentialQuantizationAttributeDecoder::
}
// Store the decoded transform data in portable attribute;
- AttributeQuantizationTransform transform;
- transform.SetParameters(quantization_bits_, min_value_.get(),
- attribute()->num_components(), max_value_dif_);
- return transform.TransferToAttribute(portable_attribute());
+ return quantization_transform_.TransferToAttribute(portable_attribute());
}
-bool SequentialQuantizationAttributeDecoder::StoreValues(uint32_t num_values) {
- return DequantizeValues(num_values);
+bool SequentialQuantizationAttributeDecoder::StoreValues(uint32_t num_points) {
+ return DequantizeValues(num_points);
}
bool SequentialQuantizationAttributeDecoder::DecodeQuantizedDataInfo() {
- const int num_components = attribute()->num_components();
- min_value_ = std::unique_ptr<float[]>(new float[num_components]);
- if (!decoder()->buffer()->Decode(min_value_.get(),
- sizeof(float) * num_components)) {
- return false;
- }
- if (!decoder()->buffer()->Decode(&max_value_dif_)) {
- return false;
+ // Get attribute used as source for decoding.
+ auto att = GetPortableAttribute();
+ if (att == nullptr) {
+ // This should happen only in the backward compatibility mode. It will still
+ // work fine for this case because the only thing the quantization transform
+ // cares about is the number of components that is the same for both source
+ // and target attributes.
+ att = attribute();
}
- uint8_t quantization_bits;
- if (!decoder()->buffer()->Decode(&quantization_bits) ||
- quantization_bits > 31) {
- return false;
- }
- quantization_bits_ = quantization_bits;
- return true;
+ return quantization_transform_.DecodeParameters(*att, decoder()->buffer());
}
bool SequentialQuantizationAttributeDecoder::DequantizeValues(
uint32_t num_values) {
// Convert all quantized values back to floats.
- const int32_t max_quantized_value =
- (1u << static_cast<uint32_t>(quantization_bits_)) - 1;
- const int num_components = attribute()->num_components();
- const int entry_size = sizeof(float) * num_components;
- const std::unique_ptr<float[]> att_val(new float[num_components]);
- int quant_val_id = 0;
- int out_byte_pos = 0;
- Dequantizer dequantizer;
- if (!dequantizer.Init(max_value_dif_, max_quantized_value)) {
- return false;
- }
- const int32_t *const portable_attribute_data = GetPortableAttributeData();
- for (uint32_t i = 0; i < num_values; ++i) {
- for (int c = 0; c < num_components; ++c) {
- float value =
- dequantizer.DequantizeFloat(portable_attribute_data[quant_val_id++]);
- value = value + min_value_[c];
- att_val[c] = value;
- }
- // Store the floating point value into the attribute buffer.
- attribute()->buffer()->Write(out_byte_pos, att_val.get(), entry_size);
- out_byte_pos += entry_size;
- }
- return true;
+ return quantization_transform_.InverseTransformAttribute(
+ *GetPortableAttribute(), attribute());
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h
index c0b7637a750..ad372dcd8a6 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h
@@ -15,6 +15,7 @@
#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_
#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_
+#include "draco/attributes/attribute_quantization_transform.h"
#include "draco/compression/attributes/sequential_integer_attribute_decoder.h"
#include "draco/draco_features.h"
@@ -43,12 +44,7 @@ class SequentialQuantizationAttributeDecoder
virtual bool DequantizeValues(uint32_t num_values);
private:
- // Max number of quantization bits used to encode each component of the
- // attribute.
- int32_t quantization_bits_;
-
- std::unique_ptr<float[]> min_value_;
- float max_value_dif_;
+ AttributeQuantizationTransform quantization_transform_;
};
} // namespace draco
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc
index cd5b8b141e0..d3666f7a411 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc
@@ -50,9 +50,11 @@ bool SequentialQuantizationAttributeEncoder::Init(PointCloudEncoder *encoder,
&quantization_origin[0]);
const float range = encoder->options()->GetAttributeFloat(
attribute_id, "quantization_range", 1.f);
- attribute_quantization_transform_.SetParameters(
- quantization_bits, quantization_origin.data(),
- attribute->num_components(), range);
+ if (!attribute_quantization_transform_.SetParameters(
+ quantization_bits, quantization_origin.data(),
+ attribute->num_components(), range)) {
+ return false;
+ }
} else {
// Compute quantization settings from the attribute values.
if (!attribute_quantization_transform_.ComputeParameters(
@@ -70,9 +72,14 @@ bool SequentialQuantizationAttributeEncoder::
bool SequentialQuantizationAttributeEncoder::PrepareValues(
const std::vector<PointIndex> &point_ids, int num_points) {
- SetPortableAttribute(
- attribute_quantization_transform_.GeneratePortableAttribute(
- *(attribute()), point_ids, num_points));
+ auto portable_attribute =
+ attribute_quantization_transform_.InitTransformedAttribute(
+ *attribute(), point_ids.size());
+ if (!attribute_quantization_transform_.TransformAttribute(
+ *(attribute()), point_ids, portable_attribute.get())) {
+ return false;
+ }
+ SetPortableAttribute(std::move(portable_attribute));
return true;
}
diff --git a/extern/draco/draco/src/draco/compression/config/compression_shared.h b/extern/draco/draco/src/draco/compression/config/compression_shared.h
index 40061d3cd48..c43f303bd15 100644
--- a/extern/draco/draco/src/draco/compression/config/compression_shared.h
+++ b/extern/draco/draco/src/draco/compression/config/compression_shared.h
@@ -42,6 +42,7 @@ enum EncodedGeometryType {
INVALID_GEOMETRY_TYPE = -1,
POINT_CLOUD = 0,
TRIANGULAR_MESH,
+ NUM_ENCODED_GEOMETRY_TYPES
};
// List of encoding methods for point clouds.
@@ -105,6 +106,8 @@ enum PredictionSchemeTransformType {
// Specialized transform for normal coordinates using canonicalized inverted
// tiles.
PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED = 3,
+ // The number of valid (non-negative) prediction scheme transform types.
+ NUM_PREDICTION_SCHEME_TRANSFORM_TYPES
};
// List of all mesh traversal methods supported by Draco framework.
diff --git a/extern/draco/draco/src/draco/compression/config/draco_options.h b/extern/draco/draco/src/draco/compression/config/draco_options.h
index 0d1247b2ad1..2bd4a3b6761 100644
--- a/extern/draco/draco/src/draco/compression/config/draco_options.h
+++ b/extern/draco/draco/src/draco/compression/config/draco_options.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
-#define DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
+#ifndef DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
+#define DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
#include <map>
#include <memory>
@@ -246,4 +246,4 @@ void DracoOptions<AttributeKeyT>::SetAttributeOptions(
} // namespace draco
-#endif // DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
+#endif // DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
diff --git a/extern/draco/draco/src/draco/compression/decode.cc b/extern/draco/draco/src/draco/compression/decode.cc
index ab70ef1ec60..92ae4ff66f9 100644
--- a/extern/draco/draco/src/draco/compression/decode.cc
+++ b/extern/draco/draco/src/draco/compression/decode.cc
@@ -56,7 +56,10 @@ StatusOr<EncodedGeometryType> Decoder::GetEncodedGeometryType(
DecoderBuffer *in_buffer) {
DecoderBuffer temp_buffer(*in_buffer);
DracoHeader header;
- DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header))
+ DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header));
+ if (header.encoder_type >= NUM_ENCODED_GEOMETRY_TYPES) {
+ return Status(Status::DRACO_ERROR, "Unsupported geometry type.");
+ }
return static_cast<EncodedGeometryType>(header.encoder_type);
}
diff --git a/extern/draco/draco/src/draco/compression/encode_base.h b/extern/draco/draco/src/draco/compression/encode_base.h
index 0c63a972bf4..6211efc221b 100644
--- a/extern/draco/draco/src/draco/compression/encode_base.h
+++ b/extern/draco/draco/src/draco/compression/encode_base.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_
-#define DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_
+#ifndef DRACO_COMPRESSION_ENCODE_BASE_H_
+#define DRACO_COMPRESSION_ENCODE_BASE_H_
#include "draco/attributes/geometry_attribute.h"
#include "draco/compression/config/compression_shared.h"
@@ -98,7 +98,7 @@ class EncoderBase {
"Invalid prediction scheme for attribute type.");
}
}
- // TODO(hemmer): Try to enable more prediction schemes for normals.
+ // TODO(b/199760123): Try to enable more prediction schemes for normals.
if (att_type == GeometryAttribute::NORMAL) {
if (!(prediction_scheme == PREDICTION_DIFFERENCE ||
prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL)) {
@@ -128,4 +128,4 @@ void EncoderBase<EncoderOptionsT>::SetTrackEncodedProperties(bool flag) {
} // namespace draco
-#endif // DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_
+#endif // DRACO_COMPRESSION_ENCODE_BASE_H_
diff --git a/extern/draco/draco/src/draco/compression/entropy/ans.h b/extern/draco/draco/src/draco/compression/entropy/ans.h
index c765256b96e..313546fee20 100644
--- a/extern/draco/draco/src/draco/compression/entropy/ans.h
+++ b/extern/draco/draco/src/draco/compression/entropy/ans.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_CORE_ANS_H_
-#define DRACO_CORE_ANS_H_
+#ifndef DRACO_COMPRESSION_ENTROPY_ANS_H_
+#define DRACO_COMPRESSION_ENTROPY_ANS_H_
// An implementation of Asymmetric Numeral Systems (rANS).
// See http://arxiv.org/abs/1311.2540v2 for more information on rANS.
// This file is based off libvpx's ans.h.
@@ -391,7 +391,6 @@ class RAnsEncoder {
ans_.buf[ans_.buf_offset++] = ans_.state % DRACO_ANS_IO_BASE;
ans_.state /= DRACO_ANS_IO_BASE;
}
- // TODO(ostava): The division and multiplication should be optimized.
ans_.state =
(ans_.state / p) * rans_precision + ans_.state % p + sym->cum_prob;
}
@@ -524,4 +523,4 @@ class RAnsDecoder {
} // namespace draco
-#endif // DRACO_CORE_ANS_H_
+#endif // DRACO_COMPRESSION_ENTROPY_ANS_H_
diff --git a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h
index 0a68e29fe26..cd4271193bf 100644
--- a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h
+++ b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h
@@ -31,11 +31,10 @@ constexpr int ComputeRAnsUnclampedPrecision(int symbols_bit_length) {
// our rANS library (which is between 12 to 20 bits).
constexpr int ComputeRAnsPrecisionFromUniqueSymbolsBitLength(
int symbols_bit_length) {
- return ComputeRAnsUnclampedPrecision(symbols_bit_length) < 12
- ? 12
- : ComputeRAnsUnclampedPrecision(symbols_bit_length) > 20
- ? 20
- : ComputeRAnsUnclampedPrecision(symbols_bit_length);
+ return ComputeRAnsUnclampedPrecision(symbols_bit_length) < 12 ? 12
+ : ComputeRAnsUnclampedPrecision(symbols_bit_length) > 20
+ ? 20
+ : ComputeRAnsUnclampedPrecision(symbols_bit_length);
}
// Compute approximate frequency table size needed for storing the provided
diff --git a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h
index 4e07ec87123..4b738b50a9d 100644
--- a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h
+++ b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h
@@ -125,8 +125,8 @@ bool RAnsSymbolEncoder<unique_symbols_bit_length_t>::Create(
for (int i = 0; i < num_symbols; ++i) {
sorted_probabilities[i] = i;
}
- std::sort(sorted_probabilities.begin(), sorted_probabilities.end(),
- ProbabilityLess(&probability_table_));
+ std::stable_sort(sorted_probabilities.begin(), sorted_probabilities.end(),
+ ProbabilityLess(&probability_table_));
if (total_rans_prob < rans_precision_) {
// This happens rather infrequently, just add the extra needed precision
// to the most frequent symbol.
diff --git a/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc b/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc
index 93d29971c89..79e81181830 100644
--- a/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc
+++ b/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc
@@ -72,7 +72,7 @@ bool DecodeTaggedSymbols(uint32_t num_values, int num_components,
int value_id = 0;
for (uint32_t i = 0; i < num_values; i += num_components) {
// Decode the tag.
- const int bit_length = tag_decoder.DecodeSymbol();
+ const uint32_t bit_length = tag_decoder.DecodeSymbol();
// Decode the actual value.
for (int j = 0; j < num_components; ++j) {
uint32_t val;
diff --git a/extern/draco/draco/src/draco/compression/expert_encode.cc b/extern/draco/draco/src/draco/compression/expert_encode.cc
index 4c70a72a765..f9aec15eb27 100644
--- a/extern/draco/draco/src/draco/compression/expert_encode.cc
+++ b/extern/draco/draco/src/draco/compression/expert_encode.cc
@@ -67,7 +67,7 @@ Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc,
kd_tree_possible = false;
}
if (kd_tree_possible && att->data_type() == DT_FLOAT32 &&
- options().GetAttributeInt(0, "quantization_bits", -1) <= 0) {
+ options().GetAttributeInt(i, "quantization_bits", -1) <= 0) {
kd_tree_possible = false; // Quantization not enabled.
}
if (!kd_tree_possible) {
diff --git a/extern/draco/draco/src/draco/compression/expert_encode.h b/extern/draco/draco/src/draco/compression/expert_encode.h
index a1aa7b8b3a8..ea59393d3d2 100644
--- a/extern/draco/draco/src/draco/compression/expert_encode.h
+++ b/extern/draco/draco/src/draco/compression/expert_encode.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_
-#define DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_
+#ifndef DRACO_COMPRESSION_EXPERT_ENCODE_H_
+#define DRACO_COMPRESSION_EXPERT_ENCODE_H_
#include "draco/compression/config/compression_shared.h"
#include "draco/compression/config/encoder_options.h"
@@ -144,4 +144,4 @@ class ExpertEncoder : public EncoderBase<EncoderOptions> {
} // namespace draco
-#endif // DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_
+#endif // DRACO_COMPRESSION_EXPERT_ENCODE_H_
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc
index 50d1971c15b..6d22e2f2a32 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc
@@ -162,6 +162,10 @@ bool MeshEdgebreakerDecoderImpl<TraversalDecoder>::CreateAttributesDecoder(
if (!decoder_->buffer()->Decode(&traversal_method_encoded)) {
return false;
}
+ // Check that decoded traversal method is valid.
+ if (traversal_method_encoded >= NUM_TRAVERSAL_METHODS) {
+ return false;
+ }
traversal_method =
static_cast<MeshTraversalMethod>(traversal_method_encoded);
}
@@ -450,7 +454,7 @@ bool MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity() {
#endif
// Decode connectivity of non-position attributes.
- if (attribute_data_.size() > 0) {
+ if (!attribute_data_.empty()) {
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
if (decoder_->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 1)) {
for (CornerIndex ci(0); ci < corner_table_->num_corners(); ci += 3) {
@@ -577,11 +581,16 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
SetOppositeCorners(corner_b, corner + 2);
// Update vertex mapping.
- corner_table_->MapCornerToVertex(corner, vertex_x);
- corner_table_->MapCornerToVertex(
- corner + 1, corner_table_->Vertex(corner_table_->Next(corner_b)));
const VertexIndex vert_a_prev =
corner_table_->Vertex(corner_table_->Previous(corner_a));
+ const VertexIndex vert_b_next =
+ corner_table_->Vertex(corner_table_->Next(corner_b));
+ if (vertex_x == vert_a_prev || vertex_x == vert_b_next) {
+ // Encoding is invalid, because face vertices are degenerate.
+ return -1;
+ }
+ corner_table_->MapCornerToVertex(corner, vertex_x);
+ corner_table_->MapCornerToVertex(corner + 1, vert_b_next);
corner_table_->MapCornerToVertex(corner + 2, vert_a_prev);
corner_table_->SetLeftMostCorner(vert_a_prev, corner + 2);
// Mark the vertex |x| as interior.
@@ -791,7 +800,7 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
return -1; // Unexpected number of decoded vertices.
}
// Decode start faces and connect them to the faces from the active stack.
- while (active_corner_stack.size() > 0) {
+ while (!active_corner_stack.empty()) {
const CornerIndex corner = active_corner_stack.back();
active_corner_stack.pop_back();
const bool interior_face =
@@ -952,9 +961,13 @@ MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeHoleAndTopologySplitEvents(
for (uint32_t i = 0; i < num_topology_splits; ++i) {
TopologySplitEventData event_data;
uint32_t delta;
- DecodeVarint<uint32_t>(&delta, decoder_buffer);
+ if (!DecodeVarint<uint32_t>(&delta, decoder_buffer)) {
+ return -1;
+ }
event_data.source_symbol_id = delta + last_source_symbol_id;
- DecodeVarint<uint32_t>(&delta, decoder_buffer);
+ if (!DecodeVarint<uint32_t>(&delta, decoder_buffer)) {
+ return -1;
+ }
if (delta > event_data.source_symbol_id) {
return -1;
}
@@ -1009,7 +1022,9 @@ MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeHoleAndTopologySplitEvents(
for (uint32_t i = 0; i < num_hole_events; ++i) {
HoleEventData event_data;
uint32_t delta;
- DecodeVarint<uint32_t>(&delta, decoder_buffer);
+ if (!DecodeVarint<uint32_t>(&delta, decoder_buffer)) {
+ return -1;
+ }
event_data.symbol_id = delta + last_symbol_id;
last_symbol_id = event_data.symbol_id;
hole_event_data_.push_back(event_data);
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc
index 5aff5d8cc10..a7f381480f1 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc
@@ -31,7 +31,6 @@ bool MeshEdgebreakerEncoder::InitializeEncoder() {
impl_ = nullptr;
// For tiny meshes it's usually better to use the basic edgebreaker as the
// overhead of the predictive one may turn out to be too big.
- // TODO(b/111065939): Check if this can be improved.
const bool is_tiny_mesh = mesh()->num_faces() < 1000;
int selected_edgebreaker_method =
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc
index 0791dc6705a..4bf6aa92070 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc
@@ -408,7 +408,7 @@ Status MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
init_face_connectivity_corners.begin(),
init_face_connectivity_corners.end());
// Encode connectivity for all non-position attributes.
- if (attribute_data_.size() > 0) {
+ if (!attribute_data_.empty()) {
// Use the same order of corner that will be used by the decoder.
visited_faces_.assign(mesh_->num_faces(), false);
for (CornerIndex ci : processed_connectivity_corners_) {
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h
index fb33771637e..979e1d373d8 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h
@@ -177,7 +177,6 @@ class MeshEdgebreakerEncoderImpl : public MeshEdgebreakerEncoderImplInterface {
uint32_t num_split_symbols_;
// Struct holding data used for encoding each non-position attribute.
- // TODO(ostava): This should be probably renamed to something better.
struct AttributeData {
AttributeData() : attribute_index(-1), is_connectivity_used(true) {}
int attribute_index;
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h
index cb3c29dd669..c650bc35210 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h
@@ -50,8 +50,6 @@ namespace draco {
// \ / S \ / / E \
// *-------* *-------*
//
-// TODO(ostava): Get rid of the topology bit pattern. It's important only for
-// encoding but the algorithms should use EdgebreakerSymbol instead.
enum EdgebreakerTopologyBitPattern {
TOPOLOGY_C = 0x0, // 0
TOPOLOGY_S = 0x1, // 1 0 0
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h
index 621883a5f1f..c00373727df 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h
@@ -106,7 +106,12 @@ class MeshEdgebreakerTraversalValenceDecoder
context_counters_.resize(context_symbols_.size());
for (int i = 0; i < context_symbols_.size(); ++i) {
uint32_t num_symbols;
- DecodeVarint<uint32_t>(&num_symbols, out_buffer);
+ if (!DecodeVarint<uint32_t>(&num_symbols, out_buffer)) {
+ return false;
+ }
+ if (num_symbols > static_cast<uint32_t>(corner_table_->num_faces())) {
+ return false;
+ }
if (num_symbols > 0) {
context_symbols_[i].resize(num_symbols);
DecodeSymbols(num_symbols, 1, out_buffer, context_symbols_[i].data());
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc
index 53f5e8651b8..fbc7383eef1 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc
@@ -53,6 +53,11 @@ bool MeshSequentialDecoder::DecodeConnectivity() {
if (faces_64 > 0xffffffff / 3) {
return false;
}
+ if (faces_64 > buffer()->remaining_size() / 3) {
+ // The number of faces is unreasonably high, because face indices do not
+ // fit in the remaining size of the buffer.
+ return false;
+ }
if (points_64 > faces_64 * 3) {
return false;
}
@@ -91,7 +96,7 @@ bool MeshSequentialDecoder::DecodeConnectivity() {
}
mesh()->AddFace(face);
}
- } else if (mesh()->num_points() < (1 << 21) &&
+ } else if (num_points < (1 << 21) &&
bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 2)) {
// Decode indices as uint32_t.
for (uint32_t i = 0; i < num_faces; ++i) {
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc
index 02ac7779ea3..fd8b1139253 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc
@@ -32,8 +32,6 @@ Status MeshSequentialEncoder::EncodeConnectivity() {
EncodeVarint(static_cast<uint32_t>(mesh()->num_points()), buffer());
// We encode all attributes in the original (possibly duplicated) format.
- // TODO(ostava): This may not be optimal if we have only one attribute or if
- // all attributes share the same index mapping.
if (options()->GetGlobalBool("compress_connectivity", false)) {
// 0 = Encode compressed indices.
buffer()->Encode(static_cast<uint8_t>(0));
@@ -44,8 +42,6 @@ Status MeshSequentialEncoder::EncodeConnectivity() {
// 1 = Encode indices directly.
buffer()->Encode(static_cast<uint8_t>(1));
// Store vertex indices using a smallest data type that fits their range.
- // TODO(ostava): This can be potentially improved by using a tighter
- // fit that is not bound by a bit-length of any particular data type.
if (mesh()->num_points() < 256) {
// Serialize indices as uint8_t.
for (FaceIndex i(0); i < num_faces; ++i) {
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h
index 672609642b0..6e2b05877ab 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h
@@ -33,7 +33,6 @@ namespace draco {
// Class that encodes mesh data using a simple binary representation of mesh's
// connectivity and geometry.
-// TODO(ostava): Use a better name.
class MeshSequentialEncoder : public MeshEncoder {
public:
MeshSequentialEncoder();
diff --git a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h
index e66dd14b238..dd9738ba2d5 100644
--- a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h
+++ b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h
@@ -25,7 +25,7 @@ namespace draco {
// values based on the traversal of the encoded mesh. The class should be used
// as the TraversalObserverT member of a Traverser class such as the
// DepthFirstTraverser (depth_first_traverser.h).
-// TODO(hemmer): rename to AttributeIndicesCodingTraverserObserver
+// TODO(b/199760123): Rename to AttributeIndicesCodingTraverserObserver.
template <class CornerTableT>
class MeshAttributeIndicesEncodingObserver {
public:
diff --git a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h
index ebe1d5f7a9e..e55c93a7969 100644
--- a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h
+++ b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h
@@ -25,7 +25,7 @@ namespace draco {
// Sequencer that generates point sequence in an order given by a deterministic
// traversal on the mesh surface. Note that all attributes encoded with this
// sequence must share the same connectivity.
-// TODO(hemmer): Consider refactoring such that this is an observer.
+// TODO(b/199760123): Consider refactoring such that this is an observer.
template <class TraverserT>
class MeshTraversalSequencer : public PointsSequencer {
public:
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h
index 87bc2b7ef3e..fa1b1e203e5 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h
@@ -227,7 +227,7 @@ bool DynamicIntegerPointsKdTreeDecoder<compression_level_t>::DecodeInternal(
std::stack<Status> status_stack;
status_stack.push(init_status);
- // TODO(hemmer): use preallocated vector instead of stack.
+ // TODO(b/199760123): Use preallocated vector instead of stack.
while (!status_stack.empty()) {
const DecodingStatus status = status_stack.top();
status_stack.pop();
@@ -263,7 +263,8 @@ bool DynamicIntegerPointsKdTreeDecoder<compression_level_t>::DecodeInternal(
// Fast decoding of remaining bits if number of points is 1 or 2.
if (num_remaining_points <= 2) {
- // TODO(hemmer): axes_ not necessary, remove would change bitstream!
+ // TODO(b/199760123): |axes_| not necessary, remove would change
+ // bitstream!
axes_[0] = axis;
for (uint32_t i = 1; i < dimension_; i++) {
axes_[i] = DRACO_INCREMENT_MOD(axes_[i - 1], dimension_);
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h
index 14fa32d7083..65b3d07a6ad 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h
@@ -280,7 +280,7 @@ void DynamicIntegerPointsKdTreeEncoder<compression_level_t>::EncodeInternal(
std::stack<Status> status_stack;
status_stack.push(init_status);
- // TODO(hemmer): use preallocated vector instead of stack.
+ // TODO(b/199760123): Use preallocated vector instead of stack.
while (!status_stack.empty()) {
Status status = status_stack.top();
status_stack.pop();
@@ -305,7 +305,8 @@ void DynamicIntegerPointsKdTreeEncoder<compression_level_t>::EncodeInternal(
// Fast encoding of remaining bits if number of points is 1 or 2.
// Doing this also for 2 gives a slight additional speed up.
if (num_remaining_points <= 2) {
- // TODO(hemmer): axes_ not necessary, remove would change bitstream!
+ // TODO(b/199760123): |axes_| not necessary, remove would change
+ // bitstream!
axes_[0] = axis;
for (uint32_t i = 1; i < dimension_; i++) {
axes_[i] = DRACO_INCREMENT_MOD(axes_[i - 1], dimension_);
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc
index 9e8d895f176..dffaa4c8d20 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc
@@ -69,18 +69,29 @@ FloatPointsTreeDecoder::FloatPointsTreeDecoder()
bool FloatPointsTreeDecoder::DecodePointCloudKdTreeInternal(
DecoderBuffer *buffer, std::vector<Point3ui> *qpoints) {
- if (!buffer->Decode(&qinfo_.quantization_bits)) return false;
- if (qinfo_.quantization_bits > 31) return false;
- if (!buffer->Decode(&qinfo_.range)) return false;
- if (!buffer->Decode(&num_points_)) return false;
- if (num_points_from_header_ > 0 && num_points_ != num_points_from_header_)
+ if (!buffer->Decode(&qinfo_.quantization_bits)) {
return false;
- if (!buffer->Decode(&compression_level_)) return false;
+ }
+ if (qinfo_.quantization_bits > 31) {
+ return false;
+ }
+ if (!buffer->Decode(&qinfo_.range)) {
+ return false;
+ }
+ if (!buffer->Decode(&num_points_)) {
+ return false;
+ }
+ if (num_points_from_header_ > 0 && num_points_ != num_points_from_header_) {
+ return false;
+ }
+ if (!buffer->Decode(&compression_level_)) {
+ return false;
+ }
// Only allow compression level in [0..6].
if (6 < compression_level_) {
- LOGE("FloatPointsTreeDecoder: compression level %i not supported.\n",
- compression_level_);
+ DRACO_LOGE("FloatPointsTreeDecoder: compression level %i not supported.\n",
+ compression_level_);
return false;
}
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h
index 26ba94f1f59..44c1b3d3a97 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h
@@ -44,7 +44,7 @@ namespace draco {
// there are more leading zeros, which is then compressed better by the
// arithmetic encoding.
-// TODO(hemmer): Remove class because it duplicates quantization code.
+// TODO(b/199760123): Remove class because it duplicates quantization code.
class FloatPointsTreeEncoder {
public:
explicit FloatPointsTreeEncoder(PointCloudCompressionMethod method);
@@ -91,7 +91,7 @@ bool FloatPointsTreeEncoder::EncodePointCloud(InputIteratorT points_begin,
// Collect necessary data for encoding.
num_points_ = std::distance(points_begin, points_end);
- // TODO(hemmer): Extend quantization tools to make this more automatic.
+ // TODO(b/199760123): Extend quantization tools to make this more automatic.
// Compute range of points for quantization
std::vector<Point3ui> qpoints;
qpoints.reserve(num_points_);
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h
index 94e523cadaf..bc31af58613 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-// TODO(hemmer): Make this a wrapper using DynamicIntegerPointsKdTreeDecoder.
+// TODO(b/199760123): Make this a wrapper using
+// DynamicIntegerPointsKdTreeDecoder.
//
// See integer_points_kd_tree_encoder.h for documentation.
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h
index b8811092ed7..654f14a7866 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-// TODO(hemmer): Make this a wrapper using DynamicIntegerPointsKdTreeEncoder.
+// TODO(b/199760123): Make this a wrapper using
+// DynamicIntegerPointsKdTreeEncoder.
#ifndef DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_INTEGER_POINTS_KD_TREE_ENCODER_H_
#define DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_INTEGER_POINTS_KD_TREE_ENCODER_H_
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h
index 01943ad9e6c..04aa1d95e11 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h
@@ -22,7 +22,7 @@
namespace draco {
-// TODO(hemmer): Make this a stable bounding box.
+// TODO(b/199760123): Make this a stable bounding box.
struct QuantizationInfo {
uint32_t quantization_bits;
float range;
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc
index 5196edf960c..85f7bc94e33 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc
@@ -88,7 +88,9 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options,
const uint8_t max_supported_minor_version =
header.encoder_type == POINT_CLOUD ? kDracoPointCloudBitstreamVersionMinor
: kDracoMeshBitstreamVersionMinor;
+
// Check for version compatibility.
+#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
if (version_major_ < 1 || version_major_ > max_supported_major_version) {
return Status(Status::UNKNOWN_VERSION, "Unknown major version.");
}
@@ -96,6 +98,14 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options,
version_minor_ > max_supported_minor_version) {
return Status(Status::UNKNOWN_VERSION, "Unknown minor version.");
}
+#else
+ if (version_major_ != max_supported_major_version) {
+ return Status(Status::UNKNOWN_VERSION, "Unsupported major version.");
+ }
+ if (version_minor_ != max_supported_minor_version) {
+ return Status(Status::UNKNOWN_VERSION, "Unsupported minor version.");
+ }
+#endif
buffer_->set_bitstream_version(
DRACO_BITSTREAM_VERSION(version_major_, version_minor_));
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc
index b4b0ee94093..a1fda8d5a50 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc
@@ -62,12 +62,14 @@ Status PointCloudEncoder::EncodeHeader() {
buffer_->Encode("DRACO", 5);
// Version (major, minor).
const uint8_t encoder_type = GetGeometryType();
- const uint8_t version_major = encoder_type == POINT_CLOUD
- ? kDracoPointCloudBitstreamVersionMajor
- : kDracoMeshBitstreamVersionMajor;
- const uint8_t version_minor = encoder_type == POINT_CLOUD
- ? kDracoPointCloudBitstreamVersionMinor
- : kDracoMeshBitstreamVersionMinor;
+ uint8_t version_major, version_minor;
+ version_major = encoder_type == POINT_CLOUD
+ ? kDracoPointCloudBitstreamVersionMajor
+ : kDracoMeshBitstreamVersionMajor;
+ version_minor = encoder_type == POINT_CLOUD
+ ? kDracoPointCloudBitstreamVersionMinor
+ : kDracoMeshBitstreamVersionMinor;
+
buffer_->Encode(version_major);
buffer_->Encode(version_minor);
// Type of the encoder (point cloud, mesh, ...).
diff --git a/extern/draco/draco/src/draco/core/bounding_box.cc b/extern/draco/draco/src/draco/core/bounding_box.cc
index d95b1e90759..be0d209d857 100644
--- a/extern/draco/draco/src/draco/core/bounding_box.cc
+++ b/extern/draco/draco/src/draco/core/bounding_box.cc
@@ -16,8 +16,15 @@
namespace draco {
-BoundingBox::BoundingBox(const Vector3f &min_point_in,
- const Vector3f &max_point_in)
- : min_point_(min_point_in), max_point_(max_point_in) {}
+BoundingBox::BoundingBox()
+ : BoundingBox(Vector3f(std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max()),
+ Vector3f(std::numeric_limits<float>::lowest(),
+ std::numeric_limits<float>::lowest(),
+ std::numeric_limits<float>::lowest())) {}
+
+BoundingBox::BoundingBox(const Vector3f &min_point, const Vector3f &max_point)
+ : min_point_(min_point), max_point_(max_point) {}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/core/bounding_box.h b/extern/draco/draco/src/draco/core/bounding_box.h
index 1c20fad8bf2..31ba2d68340 100644
--- a/extern/draco/draco/src/draco/core/bounding_box.h
+++ b/extern/draco/draco/src/draco/core/bounding_box.h
@@ -19,22 +19,27 @@
namespace draco {
-// Class for detecting the bounding box of a point_cloud or mesh.
-// Use the minimum point and the maximum point to define the bounding box.
-// TODO(xiaoxumeng): Change the class of BoundingBox to a template, similar to
-// draco/src/draco/core/vector_d.h
+// Class for computing the bounding box of points in 3D space.
class BoundingBox {
public:
- // Initialization
- BoundingBox(const Vector3f &min_point_in, const Vector3f &max_point_in);
+ // Creates bounding box object with minimum and maximum points initialized to
+ // the largest positive and the smallest negative values, respectively. The
+ // resulting abstract bounding box effectively has no points and can be
+ // updated by providing any point to Update() method.
+ BoundingBox();
- inline const Vector3f &min_point() const { return min_point_; }
- inline const Vector3f &max_point() const { return max_point_; }
+ // Creates bounding box object with minimum and maximum points initialized to
+ // |min_point| and |max_point|, respectively.
+ BoundingBox(const Vector3f &min_point, const Vector3f &max_point);
- // Conditionally updates the bounding box.
- // TODO(xiaoxumeng): Change the function to a template function and change the
- // argument to an iterator.
- inline void update_bounding_box(const Vector3f &new_point) {
+ // Returns the minimum point of the bounding box.
+ inline const Vector3f &GetMinPoint() const { return min_point_; }
+
+ // Returns the maximum point of the bounding box.
+ inline const Vector3f &GetMaxPoint() const { return max_point_; }
+
+ // Conditionally updates the bounding box with a given |new_point|.
+ void Update(const Vector3f &new_point) {
for (int i = 0; i < 3; i++) {
if (new_point[i] < min_point_[i]) {
min_point_[i] = new_point[i];
@@ -45,6 +50,19 @@ class BoundingBox {
}
}
+ // Updates bounding box with minimum and maximum points of the |other|
+ // bounding box.
+ void Update(const BoundingBox &other) {
+ Update(other.GetMinPoint());
+ Update(other.GetMaxPoint());
+ }
+
+ // Returns the size of the bounding box along each axis.
+ Vector3f Size() const { return max_point_ - min_point_; }
+
+ // Returns the center of the bounding box.
+ Vector3f Center() const { return (min_point_ + max_point_) / 2; }
+
private:
Vector3f min_point_;
Vector3f max_point_;
diff --git a/extern/draco/draco/src/draco/core/cycle_timer.cc b/extern/draco/draco/src/draco/core/cycle_timer.cc
index 94b4b28b2f9..58df4df77de 100644
--- a/extern/draco/draco/src/draco/core/cycle_timer.cc
+++ b/extern/draco/draco/src/draco/core/cycle_timer.cc
@@ -17,31 +17,31 @@
namespace draco {
void DracoTimer::Start() {
#ifdef _WIN32
- QueryPerformanceCounter(&tv_start);
+ QueryPerformanceCounter(&tv_start_);
#else
- gettimeofday(&tv_start, nullptr);
+ gettimeofday(&tv_start_, nullptr);
#endif
}
void DracoTimer::Stop() {
#ifdef _WIN32
- QueryPerformanceCounter(&tv_end);
+ QueryPerformanceCounter(&tv_end_);
#else
- gettimeofday(&tv_end, nullptr);
+ gettimeofday(&tv_end_, nullptr);
#endif
}
int64_t DracoTimer::GetInMs() {
#ifdef _WIN32
LARGE_INTEGER elapsed = {0};
- elapsed.QuadPart = tv_end.QuadPart - tv_start.QuadPart;
+ elapsed.QuadPart = tv_end_.QuadPart - tv_start_.QuadPart;
LARGE_INTEGER frequency = {0};
QueryPerformanceFrequency(&frequency);
return elapsed.QuadPart * 1000 / frequency.QuadPart;
#else
- const int64_t seconds = (tv_end.tv_sec - tv_start.tv_sec) * 1000;
- const int64_t milliseconds = (tv_end.tv_usec - tv_start.tv_usec) / 1000;
+ const int64_t seconds = (tv_end_.tv_sec - tv_start_.tv_sec) * 1000;
+ const int64_t milliseconds = (tv_end_.tv_usec - tv_start_.tv_usec) / 1000;
return seconds + milliseconds;
#endif
}
diff --git a/extern/draco/draco/src/draco/core/cycle_timer.h b/extern/draco/draco/src/draco/core/cycle_timer.h
index 172f1c2e9b5..f480cc9d389 100644
--- a/extern/draco/draco/src/draco/core/cycle_timer.h
+++ b/extern/draco/draco/src/draco/core/cycle_timer.h
@@ -20,9 +20,10 @@
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
-typedef LARGE_INTEGER timeval;
+typedef LARGE_INTEGER DracoTimeVal;
#else
#include <sys/time.h>
+typedef timeval DracoTimeVal;
#endif
#include <cinttypes>
@@ -39,8 +40,8 @@ class DracoTimer {
int64_t GetInMs();
private:
- timeval tv_start;
- timeval tv_end;
+ DracoTimeVal tv_start_;
+ DracoTimeVal tv_end_;
};
typedef DracoTimer CycleTimer;
diff --git a/extern/draco/draco/src/draco/core/data_buffer.cc b/extern/draco/draco/src/draco/core/data_buffer.cc
index f0b43d67dbd..96a3787987c 100644
--- a/extern/draco/draco/src/draco/core/data_buffer.cc
+++ b/extern/draco/draco/src/draco/core/data_buffer.cc
@@ -52,7 +52,7 @@ void DataBuffer::Resize(int64_t size) {
}
void DataBuffer::WriteDataToStream(std::ostream &stream) {
- if (data_.size() == 0) {
+ if (data_.empty()) {
return;
}
stream.write(reinterpret_cast<char *>(data_.data()), data_.size());
diff --git a/extern/draco/draco/src/draco/core/decoder_buffer.h b/extern/draco/draco/src/draco/core/decoder_buffer.h
index 0559abbe415..be98e52d60e 100644
--- a/extern/draco/draco/src/draco/core/decoder_buffer.h
+++ b/extern/draco/draco/src/draco/core/decoder_buffer.h
@@ -54,12 +54,11 @@ class DecoderBuffer {
// Decodes up to 32 bits into out_val. Can be called only in between
// StartBitDecoding and EndBitDecoding. Otherwise returns false.
- bool DecodeLeastSignificantBits32(int nbits, uint32_t *out_value) {
+ bool DecodeLeastSignificantBits32(uint32_t nbits, uint32_t *out_value) {
if (!bit_decoder_active()) {
return false;
}
- bit_decoder_.GetBits(nbits, out_value);
- return true;
+ return bit_decoder_.GetBits(nbits, out_value);
}
// Decodes an arbitrary data type.
@@ -158,9 +157,10 @@ class DecoderBuffer {
inline void ConsumeBits(int k) { bit_offset_ += k; }
// Returns |nbits| bits in |x|.
- inline bool GetBits(int32_t nbits, uint32_t *x) {
- DRACO_DCHECK_GE(nbits, 0);
- DRACO_DCHECK_LE(nbits, 32);
+ inline bool GetBits(uint32_t nbits, uint32_t *x) {
+ if (nbits > 32) {
+ return false;
+ }
uint32_t value = 0;
for (int32_t bit = 0; bit < nbits; ++bit) {
value |= GetBit() << bit;
diff --git a/extern/draco/draco/src/draco/core/draco_index_type_vector.h b/extern/draco/draco/src/draco/core/draco_index_type_vector.h
index d47ab3b04eb..0fefc43b23d 100644
--- a/extern/draco/draco/src/draco/core/draco_index_type_vector.h
+++ b/extern/draco/draco/src/draco/core/draco_index_type_vector.h
@@ -28,7 +28,6 @@ namespace draco {
// draco_index_type.h .
// TODO(ostava): Make the interface more complete. It's currently missing
// features such as iterators.
-// TODO(vytyaz): Add more unit tests for this class.
template <class IndexTypeT, class ValueTypeT>
class IndexTypeVector {
public:
@@ -56,7 +55,7 @@ class IndexTypeVector {
void push_back(ValueTypeT &&val) { vector_.push_back(std::move(val)); }
template <typename... Args>
- void emplace_back(Args &&... args) {
+ void emplace_back(Args &&...args) {
vector_.emplace_back(std::forward<Args>(args)...);
}
diff --git a/extern/draco/draco/src/draco/core/draco_version.h b/extern/draco/draco/src/draco/core/draco_version.h
index ffd7948c64d..5f2676ad7e9 100644
--- a/extern/draco/draco/src/draco/core/draco_version.h
+++ b/extern/draco/draco/src/draco/core/draco_version.h
@@ -18,7 +18,7 @@
namespace draco {
// Draco version is comprised of <major>.<minor>.<revision>.
-static const char kDracoVersion[] = "1.3.6";
+static const char kDracoVersion[] = "1.5.2";
const char *Version() { return kDracoVersion; }
diff --git a/extern/draco/draco/src/draco/core/macros.h b/extern/draco/draco/src/draco/core/macros.h
index 89b706e53a5..64647d129d5 100644
--- a/extern/draco/draco/src/draco/core/macros.h
+++ b/extern/draco/draco/src/draco/core/macros.h
@@ -21,11 +21,13 @@
#ifdef ANDROID_LOGGING
#include <android/log.h>
#define LOG_TAG "draco"
-#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
-#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+#define DRACO_LOGI(...) \
+ __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define DRACO_LOGE(...) \
+ __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#else
-#define LOGI printf
-#define LOGE printf
+#define DRACO_LOGI printf
+#define DRACO_LOGE printf
#endif
#include <iostream>
@@ -88,6 +90,10 @@ namespace draco {
#define DRACO_MACROS_IMPL_CONCAT_INNER_(x, y) x##y
#define DRACO_MACROS_IMPL_CONCAT_(x, y) DRACO_MACROS_IMPL_CONCAT_INNER_(x, y)
+#define DRACO_MACROS_IMPL_CONCAT_INNER_3_(x, y, z) x##y##z
+#define DRACO_MACROS_IMPL_CONCAT_3_(x, y, z) \
+ DRACO_MACROS_IMPL_CONCAT_INNER_3_(x, y, z)
+
// Expand the n-th argument of the macro. Used to select an argument based on
// the number of entries in a variadic macro argument. Example usage:
//
@@ -98,13 +104,20 @@ namespace draco {
// #define VARIADIC_MACRO(...)
// DRACO_SELECT_NTH_FROM_3(__VA_ARGS__, FUNC_3, FUNC_2, FUNC_1) __VA_ARGS__
//
-#define DRACO_SELECT_NTH_FROM_2(_1, _2, NAME) NAME
-#define DRACO_SELECT_NTH_FROM_3(_1, _2, _3, NAME) NAME
-#define DRACO_SELECT_NTH_FROM_4(_1, _2, _3, _4, NAME) NAME
+#define DRACO_SELECT_NTH_FROM_2(_1, _2, NAME, ...) NAME
+#define DRACO_SELECT_NTH_FROM_3(_1, _2, _3, NAME, ...) NAME
+#define DRACO_SELECT_NTH_FROM_4(_1, _2, _3, _4, NAME, ...) NAME
// Macro that converts the Draco bit-stream into one uint16_t number.
// Useful mostly when checking version numbers.
#define DRACO_BITSTREAM_VERSION(MAJOR, MINOR) \
((static_cast<uint16_t>(MAJOR) << 8) | MINOR)
+// Macro that converts the uint16_t Draco bit-stream number into the major
+// and minor components respectively.
+#define DRACO_BISTREAM_VERSION_MAJOR(VERSION) \
+ (static_cast<uint8_t>(VERSION >> 8))
+#define DRACO_BISTREAM_VERSION_MINOR(VERSION) \
+ (static_cast<uint8_t>(VERSION & 0xFF))
+
#endif // DRACO_CORE_MACROS_H_
diff --git a/extern/draco/draco/src/draco/core/options.h b/extern/draco/draco/src/draco/core/options.h
index 1bc4dc0fb7b..9dc22ce16c2 100644
--- a/extern/draco/draco/src/draco/core/options.h
+++ b/extern/draco/draco/src/draco/core/options.h
@@ -71,8 +71,6 @@ class Options {
private:
// All entries are internally stored as strings and converted to the desired
// return type based on the used Get* method.
- // TODO(ostava): Consider adding type safety mechanism that would prevent
- // unsafe operations such as a conversion from vector to int.
std::map<std::string, std::string> options_;
};
diff --git a/extern/draco/draco/src/draco/core/status.h b/extern/draco/draco/src/draco/core/status.h
index 449ad8566de..ee7f43ee59c 100644
--- a/extern/draco/draco/src/draco/core/status.h
+++ b/extern/draco/draco/src/draco/core/status.h
@@ -15,6 +15,7 @@
#ifndef DRACO_CORE_STATUS_H_
#define DRACO_CORE_STATUS_H_
+#include <ostream>
#include <string>
namespace draco {
@@ -61,6 +62,9 @@ inline std::ostream &operator<<(std::ostream &os, const Status &status) {
}
inline Status OkStatus() { return Status(Status::OK); }
+inline Status ErrorStatus(const std::string &msg) {
+ return Status(Status::DRACO_ERROR, msg);
+}
// Evaluates an expression that returns draco::Status. If the status is not OK,
// the macro returns the status object.
diff --git a/extern/draco/draco/src/draco/core/varint_decoding.h b/extern/draco/draco/src/draco/core/varint_decoding.h
index 4e86df732e0..cff47e930b4 100644
--- a/extern/draco/draco/src/draco/core/varint_decoding.h
+++ b/extern/draco/draco/src/draco/core/varint_decoding.h
@@ -58,6 +58,7 @@ bool DecodeVarintUnsigned(int depth, IntTypeT *out_val, DecoderBuffer *buffer) {
// Decodes a specified integer as varint. Note that the IntTypeT must be the
// same as the one used in the corresponding EncodeVarint() call.
+// out_val is undefined if this returns false.
template <typename IntTypeT>
bool DecodeVarint(IntTypeT *out_val, DecoderBuffer *buffer) {
if (std::is_unsigned<IntTypeT>::value) {
diff --git a/extern/draco/draco/src/draco/core/vector_d.h b/extern/draco/draco/src/draco/core/vector_d.h
index bed97304feb..a0ec2dedf2e 100644
--- a/extern/draco/draco/src/draco/core/vector_d.h
+++ b/extern/draco/draco/src/draco/core/vector_d.h
@@ -20,6 +20,7 @@
#include <algorithm>
#include <array>
#include <cmath>
+#include <limits>
#include "draco/core/macros.h"
@@ -33,7 +34,7 @@ class VectorD {
typedef ScalarT Scalar;
typedef VectorD<Scalar, dimension_t> Self;
- // TODO(hemmer): Deprecate.
+ // TODO(b/199760123): Deprecate.
typedef ScalarT CoefficientType;
VectorD() {
@@ -44,7 +45,7 @@ class VectorD {
// The following constructor does not compile in opt mode, which for now led
// to the constructors further down, which is not ideal.
- // TODO(hemmer): fix constructor below and remove others.
+ // TODO(b/199760123): Fix constructor below and remove others.
// template <typename... Args>
// explicit VectorD(Args... args) : v_({args...}) {}
@@ -110,7 +111,7 @@ class VectorD {
Scalar &operator[](int i) { return v_[i]; }
const Scalar &operator[](int i) const { return v_[i]; }
- // TODO(hemmer): remove.
+ // TODO(b/199760123): Remove.
// Similar to interface of Eigen library.
Scalar &operator()(int i) { return v_[i]; }
const Scalar &operator()(int i) const { return v_[i]; }
@@ -236,7 +237,12 @@ class VectorD {
Scalar AbsSum() const {
Scalar result(0);
for (int i = 0; i < dimension; ++i) {
- result += std::abs(v_[i]);
+ Scalar next_value = std::abs(v_[i]);
+ if (result > std::numeric_limits<Scalar>::max() - next_value) {
+ // Return the max if adding would have caused an overflow.
+ return std::numeric_limits<Scalar>::max();
+ }
+ result += next_value;
}
return result;
}
diff --git a/extern/draco/draco/src/draco/draco_features.h b/extern/draco/draco/src/draco/draco_features.h
index 27e3d7f136a..d0a630e5465 100644
--- a/extern/draco/draco/src/draco/draco_features.h
+++ b/extern/draco/draco/src/draco/draco_features.h
@@ -4,7 +4,5 @@
#define DRACO_MESH_COMPRESSION_SUPPORTED
#define DRACO_NORMAL_ENCODING_SUPPORTED
#define DRACO_STANDARD_EDGEBREAKER_SUPPORTED
-#define DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
-#define DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
#endif // DRACO_FEATURES_H_
diff --git a/extern/draco/draco/src/draco/mesh/corner_table.cc b/extern/draco/draco/src/draco/mesh/corner_table.cc
index 6066e58bd8b..3f92f651ab6 100644
--- a/extern/draco/draco/src/draco/mesh/corner_table.cc
+++ b/extern/draco/draco/src/draco/mesh/corner_table.cc
@@ -66,12 +66,13 @@ bool CornerTable::Reset(int num_faces, int num_vertices) {
if (num_faces < 0 || num_vertices < 0) {
return false;
}
- if (static_cast<unsigned int>(num_faces) >
+ const unsigned int num_faces_unsigned = num_faces;
+ if (num_faces_unsigned >
std::numeric_limits<CornerIndex::ValueType>::max() / 3) {
return false;
}
- corner_to_vertex_map_.assign(num_faces * 3, kInvalidVertexIndex);
- opposite_corners_.assign(num_faces * 3, kInvalidCornerIndex);
+ corner_to_vertex_map_.assign(num_faces_unsigned * 3, kInvalidVertexIndex);
+ opposite_corners_.assign(num_faces_unsigned * 3, kInvalidCornerIndex);
vertex_corners_.reserve(num_vertices);
valence_cache_.ClearValenceCache();
valence_cache_.ClearValenceCacheInaccurate();
diff --git a/extern/draco/draco/src/draco/mesh/mesh.h b/extern/draco/draco/src/draco/mesh/mesh.h
index f4506da81c9..b1577c03986 100644
--- a/extern/draco/draco/src/draco/mesh/mesh.h
+++ b/extern/draco/draco/src/draco/mesh/mesh.h
@@ -119,6 +119,10 @@ class Mesh : public PointCloud {
const std::vector<PointIndex> &unique_point_ids) override;
#endif
+ // Exposes |faces_|. Use |faces_| at your own risk. DO NOT store the
+ // reference: the |faces_| object is destroyed with the mesh.
+ IndexTypeVector<FaceIndex, Face> &faces() { return faces_; }
+
private:
// Mesh specific per-attribute data.
std::vector<AttributeData> attribute_data_;
diff --git a/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h b/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h
index 7dad25cf1d2..6f02453d2d4 100644
--- a/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h
+++ b/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h
@@ -130,6 +130,12 @@ class MeshAttributeCornerTable {
return false;
}
+ bool IsDegenerated(FaceIndex face) const {
+ // Introducing seams can't change the degeneracy of the individual faces,
+ // therefore we can delegate the check to the original |corner_table_|.
+ return corner_table_->IsDegenerated(face);
+ }
+
bool no_interior_seams() const { return no_interior_seams_; }
const CornerTable *corner_table() const { return corner_table_; }
diff --git a/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc b/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc
index 773c1e18fe6..bc44c831c4e 100644
--- a/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc
+++ b/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc
@@ -14,25 +14,42 @@
//
#include "draco/mesh/mesh_cleanup.h"
+#include <unordered_set>
+
+#include "draco/core/hash_utils.h"
+
namespace draco {
-bool MeshCleanup::operator()(Mesh *mesh, const MeshCleanupOptions &options) {
- if (!options.remove_degenerated_faces && !options.remove_unused_attributes) {
- return true; // Nothing to cleanup.
+Status MeshCleanup::Cleanup(Mesh *mesh, const MeshCleanupOptions &options) {
+ if (!options.remove_degenerated_faces && !options.remove_unused_attributes &&
+ !options.remove_duplicate_faces && !options.make_geometry_manifold) {
+ return OkStatus(); // Nothing to cleanup.
}
const PointAttribute *const pos_att =
mesh->GetNamedAttribute(GeometryAttribute::POSITION);
if (pos_att == nullptr) {
- return false;
+ return Status(Status::DRACO_ERROR, "Missing position attribute.");
}
- // Array that is going to store whether a corresponding point is used.
- std::vector<bool> is_point_used;
+
+ if (options.remove_degenerated_faces) {
+ RemoveDegeneratedFaces(mesh);
+ }
+
+ if (options.remove_duplicate_faces) {
+ RemoveDuplicateFaces(mesh);
+ }
+
if (options.remove_unused_attributes) {
- is_point_used.resize(mesh->num_points(), false);
+ RemoveUnusedAttributes(mesh);
}
+ return OkStatus();
+}
+
+void MeshCleanup::RemoveDegeneratedFaces(Mesh *mesh) {
+ const PointAttribute *const pos_att =
+ mesh->GetNamedAttribute(GeometryAttribute::POSITION);
FaceIndex::ValueType num_degenerated_faces = 0;
- PointIndex::ValueType num_new_points = 0;
// Array for storing position indices on a face.
std::array<AttributeValueIndex, 3> pos_indices;
for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
@@ -40,149 +57,195 @@ bool MeshCleanup::operator()(Mesh *mesh, const MeshCleanupOptions &options) {
for (int p = 0; p < 3; ++p) {
pos_indices[p] = pos_att->mapped_index(face[p]);
}
- bool is_face_valid = true;
- if (options.remove_degenerated_faces) {
- if (pos_indices[0] == pos_indices[1] ||
- pos_indices[0] == pos_indices[2] ||
- pos_indices[1] == pos_indices[2]) {
- ++num_degenerated_faces;
- is_face_valid = false;
- } else if (num_degenerated_faces > 0) {
- // Copy the face to its new location.
- mesh->SetFace(f - num_degenerated_faces, face);
- }
- }
- if (options.remove_unused_attributes && is_face_valid) {
- for (int p = 0; p < 3; ++p) {
- if (!is_point_used[face[p].value()]) {
- is_point_used[face[p].value()] = true;
- ++num_new_points;
- }
- }
+ if (pos_indices[0] == pos_indices[1] || pos_indices[0] == pos_indices[2] ||
+ pos_indices[1] == pos_indices[2]) {
+ ++num_degenerated_faces;
+ } else if (num_degenerated_faces > 0) {
+ // Copy the face to its new location.
+ mesh->SetFace(f - num_degenerated_faces, face);
}
}
if (num_degenerated_faces > 0) {
mesh->SetNumFaces(mesh->num_faces() - num_degenerated_faces);
}
- if (options.remove_unused_attributes) {
- bool points_changed = false;
- const PointIndex::ValueType num_original_points = mesh->num_points();
- // Map from old points to the new ones.
- IndexTypeVector<PointIndex, PointIndex> point_map(num_original_points);
- if (num_new_points < static_cast<int>(mesh->num_points())) {
- // Some of the points were removed. We need to remap the old points to the
- // new ones.
- num_new_points = 0;
- for (PointIndex i(0); i < num_original_points; ++i) {
- if (is_point_used[i.value()]) {
- point_map[i] = num_new_points++;
- } else {
- point_map[i] = kInvalidPointIndex;
- }
+}
+
+void MeshCleanup::RemoveDuplicateFaces(Mesh *mesh) {
+ const PointAttribute *const pos_att =
+ mesh->GetNamedAttribute(GeometryAttribute::POSITION);
+
+ typedef std::array<AttributeValueIndex::ValueType, 3> PosTriplet;
+ PosTriplet pos_indices;
+ std::unordered_set<PosTriplet, HashArray<PosTriplet>> is_face_used;
+
+ uint32_t num_duplicate_faces = 0;
+ for (FaceIndex fi(0); fi < mesh->num_faces(); ++fi) {
+ const auto f = mesh->face(fi);
+ for (int c = 0; c < 3; ++c) {
+ pos_indices[c] = pos_att->mapped_index(f[c]).value();
+ }
+ // Shift the position indices until the smallest index is the first one.
+ while (pos_indices[0] > pos_indices[1] || pos_indices[0] > pos_indices[2]) {
+ // Shift to the left.
+ std::swap(pos_indices[0], pos_indices[1]);
+ std::swap(pos_indices[1], pos_indices[2]);
+ }
+ // Check if have encountered the same position triplet on a different face.
+ if (is_face_used.find(pos_indices) != is_face_used.end()) {
+ // Duplicate face. Ignore it.
+ num_duplicate_faces++;
+ } else {
+ // Insert new face to the set.
+ is_face_used.insert(pos_indices);
+ if (num_duplicate_faces > 0) {
+ // Copy the face to its new location.
+ mesh->SetFace(fi - num_duplicate_faces, f);
}
- // Go over faces and update their points.
- for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
- Mesh::Face face = mesh->face(f);
- for (int p = 0; p < 3; ++p) {
- face[p] = point_map[face[p]];
- }
- mesh->SetFace(f, face);
+ }
+ }
+ if (num_duplicate_faces > 0) {
+ mesh->SetNumFaces(mesh->num_faces() - num_duplicate_faces);
+ }
+}
+
+void MeshCleanup::RemoveUnusedAttributes(Mesh *mesh) {
+ // Array that is going to store whether a corresponding point is used.
+ std::vector<bool> is_point_used;
+ PointIndex::ValueType num_new_points = 0;
+ is_point_used.resize(mesh->num_points(), false);
+ for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
+ const Mesh::Face &face = mesh->face(f);
+ for (int p = 0; p < 3; ++p) {
+ if (!is_point_used[face[p].value()]) {
+ is_point_used[face[p].value()] = true;
+ ++num_new_points;
}
- // Set the new number of points.
- mesh->set_num_points(num_new_points);
- points_changed = true;
- } else {
- // No points were removed. Initialize identity map between the old and new
- // points.
- for (PointIndex i(0); i < num_original_points; ++i) {
- point_map[i] = i;
+ }
+ }
+
+ bool points_changed = false;
+ const PointIndex::ValueType num_original_points = mesh->num_points();
+ // Map from old points to the new ones.
+ IndexTypeVector<PointIndex, PointIndex> point_map(num_original_points);
+ if (num_new_points < static_cast<int>(mesh->num_points())) {
+ // Some of the points were removed. We need to remap the old points to the
+ // new ones.
+ num_new_points = 0;
+ for (PointIndex i(0); i < num_original_points; ++i) {
+ if (is_point_used[i.value()]) {
+ point_map[i] = num_new_points++;
+ } else {
+ point_map[i] = kInvalidPointIndex;
+ }
+ }
+ // Go over faces and update their points.
+ for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
+ Mesh::Face face = mesh->face(f);
+ for (int p = 0; p < 3; ++p) {
+ face[p] = point_map[face[p]];
}
+ mesh->SetFace(f, face);
}
+ // Set the new number of points.
+ mesh->set_num_points(num_new_points);
+ points_changed = true;
+ } else {
+ // No points were removed. Initialize identity map between the old and new
+ // points.
+ for (PointIndex i(0); i < num_original_points; ++i) {
+ point_map[i] = i;
+ }
+ }
- // Update index mapping for attributes.
- IndexTypeVector<AttributeValueIndex, uint8_t> is_att_index_used;
- IndexTypeVector<AttributeValueIndex, AttributeValueIndex> att_index_map;
- for (int a = 0; a < mesh->num_attributes(); ++a) {
- PointAttribute *const att = mesh->attribute(a);
- // First detect which attribute entries are used (included in a point).
- is_att_index_used.assign(att->size(), 0);
- att_index_map.clear();
- AttributeValueIndex::ValueType num_used_entries = 0;
- for (PointIndex i(0); i < num_original_points; ++i) {
- if (point_map[i] != kInvalidPointIndex) {
- const AttributeValueIndex entry_id = att->mapped_index(i);
- if (!is_att_index_used[entry_id]) {
- is_att_index_used[entry_id] = 1;
- ++num_used_entries;
- }
+ // Update index mapping for attributes.
+ IndexTypeVector<AttributeValueIndex, uint8_t> is_att_index_used;
+ IndexTypeVector<AttributeValueIndex, AttributeValueIndex> att_index_map;
+ for (int a = 0; a < mesh->num_attributes(); ++a) {
+ PointAttribute *const att = mesh->attribute(a);
+ // First detect which attribute entries are used (included in a point).
+ is_att_index_used.assign(att->size(), 0);
+ att_index_map.clear();
+ AttributeValueIndex::ValueType num_used_entries = 0;
+ for (PointIndex i(0); i < num_original_points; ++i) {
+ if (point_map[i] != kInvalidPointIndex) {
+ const AttributeValueIndex entry_id = att->mapped_index(i);
+ if (!is_att_index_used[entry_id]) {
+ is_att_index_used[entry_id] = 1;
+ ++num_used_entries;
}
}
- bool att_indices_changed = false;
- // If there are some unused attribute entries, remap the attribute values
- // in the attribute buffer.
- if (num_used_entries < static_cast<int>(att->size())) {
- att_index_map.resize(att->size());
- num_used_entries = 0;
- for (AttributeValueIndex i(0); i < static_cast<uint32_t>(att->size());
- ++i) {
- if (is_att_index_used[i]) {
- att_index_map[i] = num_used_entries;
- if (i > num_used_entries) {
- const uint8_t *const src_add = att->GetAddress(i);
- att->buffer()->Write(
- att->GetBytePos(AttributeValueIndex(num_used_entries)),
- src_add, att->byte_stride());
- }
- ++num_used_entries;
+ }
+ bool att_indices_changed = false;
+ // If there are some unused attribute entries, remap the attribute values
+ // in the attribute buffer.
+ if (num_used_entries < static_cast<int>(att->size())) {
+ att_index_map.resize(att->size());
+ num_used_entries = 0;
+ for (AttributeValueIndex i(0); i < static_cast<uint32_t>(att->size());
+ ++i) {
+ if (is_att_index_used[i]) {
+ att_index_map[i] = num_used_entries;
+ if (i > num_used_entries) {
+ const uint8_t *const src_add = att->GetAddress(i);
+ att->buffer()->Write(
+ att->GetBytePos(AttributeValueIndex(num_used_entries)), src_add,
+ att->byte_stride());
}
+ ++num_used_entries;
}
- // Update the number of unique entries in the vertex buffer.
- att->Resize(num_used_entries);
- att_indices_changed = true;
}
- // If either the points or attribute indices have changed, we need to
- // update the attribute index mapping.
- if (points_changed || att_indices_changed) {
- if (att->is_mapping_identity()) {
- // The mapping was identity. It'll remain identity only if the
- // number of point and attribute indices is still the same.
- if (num_used_entries != static_cast<int>(mesh->num_points())) {
- // We need to create an explicit mapping.
- // First we need to initialize the explicit map to the original
- // number of points to recreate the original identity map.
- att->SetExplicitMapping(num_original_points);
- // Set the entries of the explicit map to identity.
- for (PointIndex::ValueType i = 0; i < num_original_points; ++i) {
- att->SetPointMapEntry(PointIndex(i), AttributeValueIndex(i));
- }
+ // Update the number of unique entries in the vertex buffer.
+ att->Resize(num_used_entries);
+ att_indices_changed = true;
+ }
+ // If either the points or attribute indices have changed, we need to
+ // update the attribute index mapping.
+ if (points_changed || att_indices_changed) {
+ if (att->is_mapping_identity()) {
+ // The mapping was identity. It'll remain identity only if the
+ // number of point and attribute indices is still the same.
+ if (num_used_entries != static_cast<int>(mesh->num_points())) {
+ // We need to create an explicit mapping.
+ // First we need to initialize the explicit map to the original
+ // number of points to recreate the original identity map.
+ att->SetExplicitMapping(num_original_points);
+ // Set the entries of the explicit map to identity.
+ for (PointIndex::ValueType i = 0; i < num_original_points; ++i) {
+ att->SetPointMapEntry(PointIndex(i), AttributeValueIndex(i));
}
}
- if (!att->is_mapping_identity()) {
- // Explicit mapping between points and local attribute indices.
- for (PointIndex i(0); i < num_original_points; ++i) {
- // The new point id that maps to the currently processed attribute
- // entry.
- const PointIndex new_point_id = point_map[i];
- if (new_point_id == kInvalidPointIndex) {
- continue;
- }
- // Index of the currently processed attribute entry in the original
- // mesh.
- const AttributeValueIndex original_entry_index =
- att->mapped_index(i);
- // New index of the same entry after unused entries were removed.
- const AttributeValueIndex new_entry_index =
- att_index_map[original_entry_index];
- att->SetPointMapEntry(new_point_id, new_entry_index);
+ }
+ if (!att->is_mapping_identity()) {
+ // Explicit mapping between points and local attribute indices.
+ for (PointIndex i(0); i < num_original_points; ++i) {
+ // The new point id that maps to the currently processed attribute
+ // entry.
+ const PointIndex new_point_id = point_map[i];
+ if (new_point_id == kInvalidPointIndex) {
+ continue;
}
- // If the number of points changed, we need to set a new explicit map
- // size.
- att->SetExplicitMapping(mesh->num_points());
+ // Index of the currently processed attribute entry in the original
+ // mesh.
+ const AttributeValueIndex original_entry_index = att->mapped_index(i);
+ // New index of the same entry after unused entries were removed.
+ const AttributeValueIndex new_entry_index =
+ att_indices_changed ? att_index_map[original_entry_index]
+ : original_entry_index;
+
+ // Update the mapping. Note that the new point index is always smaller
+ // than the processed index |i|, making this operation safe.
+ att->SetPointMapEntry(new_point_id, new_entry_index);
}
+ // If the number of points changed, we need to set a new explicit map
+ // size.
+ att->SetExplicitMapping(mesh->num_points());
}
}
}
- return true;
+}
+
+Status MeshCleanup::MakeGeometryManifold(Mesh *mesh) {
+ return Status(Status::DRACO_ERROR, "Unsupported function.");
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/mesh/mesh_cleanup.h b/extern/draco/draco/src/draco/mesh/mesh_cleanup.h
index b56129dce58..0acdc2ae5b8 100644
--- a/extern/draco/draco/src/draco/mesh/mesh_cleanup.h
+++ b/extern/draco/draco/src/draco/mesh/mesh_cleanup.h
@@ -15,27 +15,44 @@
#ifndef DRACO_MESH_MESH_CLEANUP_H_
#define DRACO_MESH_MESH_CLEANUP_H_
+#include "draco/core/status.h"
#include "draco/mesh/mesh.h"
namespace draco {
// Options used by the MeshCleanup class.
struct MeshCleanupOptions {
- MeshCleanupOptions()
- : remove_degenerated_faces(true), remove_unused_attributes(true) {}
// If true, the cleanup tool removes any face where two or more vertices
// share the same position index.
- bool remove_degenerated_faces;
+ bool remove_degenerated_faces = true;
+
+ // If true, the cleanup tool removes all duplicate faces. A pair of faces is
+ // duplicate if both faces share the same position indices on all vertices
+ // (that is, position values have to be duduplicated). Note that all
+ // non-position properties are currently ignored.
+ bool remove_duplicate_faces = true;
+
// If true, the cleanup tool removes any unused attribute value or unused
// point id. For example, it can be used to remove isolated vertices.
- bool remove_unused_attributes;
+ bool remove_unused_attributes = true;
+
+ // If true, the cleanup tool splits vertices along non-manifold edges and
+ // vertices. This ensures that the connectivity defined by position indices
+ // is manifold.
+ bool make_geometry_manifold = false;
};
// Tool that can be used for removing bad or unused data from draco::Meshes.
class MeshCleanup {
public:
// Performs in-place cleanup of the input mesh according to the input options.
- bool operator()(Mesh *mesh, const MeshCleanupOptions &options);
+ static Status Cleanup(Mesh *mesh, const MeshCleanupOptions &options);
+
+ private:
+ static void RemoveDegeneratedFaces(Mesh *mesh);
+ static void RemoveDuplicateFaces(Mesh *mesh);
+ static void RemoveUnusedAttributes(Mesh *mesh);
+ static Status MakeGeometryManifold(Mesh *mesh);
};
} // namespace draco
diff --git a/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h b/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h
index b450bc80cd8..0a3bcf49782 100644
--- a/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h
+++ b/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h
@@ -67,7 +67,6 @@ inline bool IsCornerOppositeToAttributeSeam(CornerIndex ci,
// Interpolates an attribute value on a face using given barycentric
// coordinates. InterpolatedVectorT should be a VectorD that corresponds to the
// values stored in the attribute.
-// TODO(ostava): Find a better place for this.
template <typename InterpolatedVectorT>
InterpolatedVectorT ComputeInterpolatedAttributeValueOnMeshFace(
const Mesh &mesh, const PointAttribute &attribute, FaceIndex fi,
diff --git a/extern/draco/draco/src/draco/mesh/mesh_stripifier.h b/extern/draco/draco/src/draco/mesh/mesh_stripifier.h
index 0c298f48e86..8e8d8d9f21f 100644
--- a/extern/draco/draco/src/draco/mesh/mesh_stripifier.h
+++ b/extern/draco/draco/src/draco/mesh/mesh_stripifier.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_
-#define DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_
+#ifndef DRACO_MESH_MESH_STRIPIFIER_H_
+#define DRACO_MESH_MESH_STRIPIFIER_H_
#include "draco/mesh/mesh_misc_functions.h"
@@ -71,8 +71,6 @@ class MeshStripifier {
mesh_ = &mesh;
num_strips_ = 0;
num_encoded_faces_ = 0;
- // TODO(ostava): We may be able to avoid computing the corner table if we
- // already have it stored somewhere.
corner_table_ = CreateCornerTableFromPositionAttribute(mesh_);
if (corner_table_ == nullptr) {
return false;
@@ -257,4 +255,4 @@ bool MeshStripifier::GenerateTriangleStripsWithDegenerateTriangles(
} // namespace draco
-#endif // DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_
+#endif // DRACO_MESH_MESH_STRIPIFIER_H_
diff --git a/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc b/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc
index 60b0c50b8d5..cb767f871a9 100644
--- a/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc
+++ b/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc
@@ -41,8 +41,6 @@ void TriangleSoupMeshBuilder::SetAttributeValuesForFace(
att->SetAttributeValue(AttributeValueIndex(start_index), corner_value_0);
att->SetAttributeValue(AttributeValueIndex(start_index + 1), corner_value_1);
att->SetAttributeValue(AttributeValueIndex(start_index + 2), corner_value_2);
- // TODO(ostava): The below code should be called only for one attribute.
- // It will work OK even for multiple attributes, but it's redundant.
mesh_->SetFace(face_id,
{{PointIndex(start_index), PointIndex(start_index + 1),
PointIndex(start_index + 2)}});
diff --git a/extern/draco/draco/src/draco/metadata/geometry_metadata.cc b/extern/draco/draco/src/draco/metadata/geometry_metadata.cc
index b83898140ae..b6a882c0b1b 100644
--- a/extern/draco/draco/src/draco/metadata/geometry_metadata.cc
+++ b/extern/draco/draco/src/draco/metadata/geometry_metadata.cc
@@ -18,6 +18,19 @@
namespace draco {
+AttributeMetadata::AttributeMetadata(const AttributeMetadata &metadata)
+ : Metadata(metadata) {
+ att_unique_id_ = metadata.att_unique_id_;
+}
+
+GeometryMetadata::GeometryMetadata(const GeometryMetadata &metadata)
+ : Metadata(metadata) {
+ for (size_t i = 0; i < metadata.att_metadatas_.size(); ++i) {
+ att_metadatas_.push_back(std::unique_ptr<AttributeMetadata>(
+ new AttributeMetadata(*metadata.att_metadatas_[i])));
+ }
+}
+
const AttributeMetadata *GeometryMetadata::GetAttributeMetadataByStringEntry(
const std::string &entry_name, const std::string &entry_value) const {
for (auto &&att_metadata : att_metadatas_) {
@@ -35,7 +48,7 @@ const AttributeMetadata *GeometryMetadata::GetAttributeMetadataByStringEntry(
bool GeometryMetadata::AddAttributeMetadata(
std::unique_ptr<AttributeMetadata> att_metadata) {
- if (!att_metadata.get()) {
+ if (!att_metadata) {
return false;
}
att_metadatas_.push_back(std::move(att_metadata));
diff --git a/extern/draco/draco/src/draco/metadata/geometry_metadata.h b/extern/draco/draco/src/draco/metadata/geometry_metadata.h
index ec7ecb9ee68..531bdef2540 100644
--- a/extern/draco/draco/src/draco/metadata/geometry_metadata.h
+++ b/extern/draco/draco/src/draco/metadata/geometry_metadata.h
@@ -25,6 +25,7 @@ namespace draco {
class AttributeMetadata : public Metadata {
public:
AttributeMetadata() : att_unique_id_(0) {}
+ AttributeMetadata(const AttributeMetadata &metadata);
explicit AttributeMetadata(const Metadata &metadata)
: Metadata(metadata), att_unique_id_(0) {}
@@ -57,6 +58,7 @@ struct AttributeMetadataHasher {
class GeometryMetadata : public Metadata {
public:
GeometryMetadata() {}
+ GeometryMetadata(const GeometryMetadata &metadata);
explicit GeometryMetadata(const Metadata &metadata) : Metadata(metadata) {}
const AttributeMetadata *GetAttributeMetadataByStringEntry(
diff --git a/extern/draco/draco/src/draco/metadata/metadata.cc b/extern/draco/draco/src/draco/metadata/metadata.cc
index 9141907ed71..51b4e93a328 100644
--- a/extern/draco/draco/src/draco/metadata/metadata.cc
+++ b/extern/draco/draco/src/draco/metadata/metadata.cc
@@ -122,6 +122,14 @@ const Metadata *Metadata::GetSubMetadata(const std::string &name) const {
return sub_ptr->second.get();
}
+Metadata *Metadata::sub_metadata(const std::string &name) {
+ auto sub_ptr = sub_metadatas_.find(name);
+ if (sub_ptr == sub_metadatas_.end()) {
+ return nullptr;
+ }
+ return sub_ptr->second.get();
+}
+
void Metadata::RemoveEntry(const std::string &name) {
// Actually just remove "name", no need to check if it exists.
auto entry_ptr = entries_.find(name);
diff --git a/extern/draco/draco/src/draco/metadata/metadata.h b/extern/draco/draco/src/draco/metadata/metadata.h
index 56d05e46a3e..12c1ba97439 100644
--- a/extern/draco/draco/src/draco/metadata/metadata.h
+++ b/extern/draco/draco/src/draco/metadata/metadata.h
@@ -147,6 +147,7 @@ class Metadata {
bool AddSubMetadata(const std::string &name,
std::unique_ptr<Metadata> sub_metadata);
const Metadata *GetSubMetadata(const std::string &name) const;
+ Metadata *sub_metadata(const std::string &name);
void RemoveEntry(const std::string &name);
diff --git a/extern/draco/draco/src/draco/metadata/metadata_decoder.cc b/extern/draco/draco/src/draco/metadata/metadata_decoder.cc
index e664e4fa524..a8e66f854cf 100644
--- a/extern/draco/draco/src/draco/metadata/metadata_decoder.cc
+++ b/extern/draco/draco/src/draco/metadata/metadata_decoder.cc
@@ -78,8 +78,10 @@ bool MetadataDecoder::DecodeMetadata(Metadata *metadata) {
std::unique_ptr<Metadata> sub_metadata =
std::unique_ptr<Metadata>(new Metadata());
metadata = sub_metadata.get();
- mp.parent_metadata->AddSubMetadata(sub_metadata_name,
- std::move(sub_metadata));
+ if (!mp.parent_metadata->AddSubMetadata(sub_metadata_name,
+ std::move(sub_metadata))) {
+ return false;
+ }
}
if (metadata == nullptr) {
return false;
@@ -98,6 +100,10 @@ bool MetadataDecoder::DecodeMetadata(Metadata *metadata) {
if (!DecodeVarint(&num_sub_metadata, buffer_)) {
return false;
}
+ if (num_sub_metadata > buffer_->remaining_size()) {
+ // The decoded number of metadata items is unreasonably high.
+ return false;
+ }
for (uint32_t i = 0; i < num_sub_metadata; ++i) {
metadata_stack.push_back({metadata, nullptr});
}
diff --git a/extern/draco/draco/src/draco/point_cloud/point_cloud.cc b/extern/draco/draco/src/draco/point_cloud/point_cloud.cc
index 8eb638f80d4..55ad6670da5 100644
--- a/extern/draco/draco/src/draco/point_cloud/point_cloud.cc
+++ b/extern/draco/draco/src/draco/point_cloud/point_cloud.cc
@@ -241,7 +241,7 @@ void PointCloud::ApplyPointIdDeduplication(
bool PointCloud::DeduplicateAttributeValues() {
// Go over all attributes and create mapping between duplicate entries.
if (num_points() == 0) {
- return false; // Unexpected attribute size.
+ return true; // Nothing to deduplicate.
}
// Deduplicate all attributes.
for (int32_t att_id = 0; att_id < num_attributes(); ++att_id) {
@@ -253,17 +253,11 @@ bool PointCloud::DeduplicateAttributeValues() {
}
#endif
-// TODO(xiaoxumeng): Consider to cash the BBox.
+// TODO(b/199760503): Consider to cache the BBox.
BoundingBox PointCloud::ComputeBoundingBox() const {
- BoundingBox bounding_box =
- BoundingBox(Vector3f(std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max()),
- Vector3f(-std::numeric_limits<float>::max(),
- -std::numeric_limits<float>::max(),
- -std::numeric_limits<float>::max()));
+ BoundingBox bounding_box;
auto pc_att = GetNamedAttribute(GeometryAttribute::POSITION);
- // TODO(xiaoxumeng): Make the BoundingBox a template type, it may not be easy
+ // TODO(b/199760503): Make the BoundingBox a template type, it may not be easy
// because PointCloud is not a template.
// Or simply add some preconditioning here to make sure the position attribute
// is valid, because the current code works only if the position attribute is
@@ -274,7 +268,7 @@ BoundingBox PointCloud::ComputeBoundingBox() const {
for (AttributeValueIndex i(0); i < static_cast<uint32_t>(pc_att->size());
++i) {
pc_att->GetValue(i, &p[0]);
- bounding_box.update_bounding_box(p);
+ bounding_box.Update(p);
}
return bounding_box;
}
diff --git a/extern/draco/patches/blender.patch b/extern/draco/patches/blender.patch
new file mode 100644
index 00000000000..de39260367b
--- /dev/null
+++ b/extern/draco/patches/blender.patch
@@ -0,0 +1,30 @@
+diff --git a/draco/src/draco/attributes/geometry_attribute.h b/draco/src/draco/attributes/geometry_attribute.h
+index fd478a4..c1c0148 100644
+--- a/draco/src/draco/attributes/geometry_attribute.h
++++ b/draco/src/draco/attributes/geometry_attribute.h
+@@ -285,11 +285,25 @@ class GeometryAttribute {
+ // Make sure the in_value fits within the range of values that OutT
+ // is able to represent. Perform the check only for integral types.
+ if (std::is_integral<T>::value && std::is_integral<OutT>::value) {
++#ifdef _MSC_VER
++# pragma warning(push)
++# pragma warning(disable:4804)
++#endif
++#if defined(__GNUC__) && !defined(__clang__)
++# pragma GCC diagnostic push
++# pragma GCC diagnostic ignored "-Wbool-compare"
++#endif
+ static constexpr OutT kOutMin =
+ std::is_signed<T>::value ? std::numeric_limits<OutT>::lowest() : 0;
+ if (in_value < kOutMin || in_value > std::numeric_limits<OutT>::max()) {
+ return false;
+ }
++#ifdef __GNUC__
++# pragma GCC diagnostic pop
++#endif
++#ifdef _MSC_VER
++# pragma warning(pop)
++#endif
+ }
+
+ out_value[i] = static_cast<OutT>(in_value);
diff --git a/extern/draco/src/common.cpp b/extern/draco/src/common.cpp
index 6f98d8db7ef..3a11c126ece 100644
--- a/extern/draco/src/common.cpp
+++ b/extern/draco/src/common.cpp
@@ -54,20 +54,20 @@ size_t getComponentByteLength(size_t componentType)
{
switch (componentType)
{
- case ComponentType::Byte:
- case ComponentType::UnsignedByte:
- return 1;
-
- case ComponentType::Short:
- case ComponentType::UnsignedShort:
- return 2;
-
- case ComponentType::UnsignedInt:
- case ComponentType::Float:
- return 4;
-
- default:
- return 0;
+ case ComponentType::Byte:
+ case ComponentType::UnsignedByte:
+ return 1;
+
+ case ComponentType::Short:
+ case ComponentType::UnsignedShort:
+ return 2;
+
+ case ComponentType::UnsignedInt:
+ case ComponentType::Float:
+ return 4;
+
+ default:
+ return 0;
}
}
diff --git a/extern/draco/src/common.h b/extern/draco/src/common.h
index beaf7d91adb..eef50596350 100644
--- a/extern/draco/src/common.h
+++ b/extern/draco/src/common.h
@@ -33,7 +33,7 @@
#define API(returnType) extern "C" returnType
#endif
-enum ComponentType: size_t
+enum ComponentType : size_t
{
Byte = 5120,
UnsignedByte = 5121,
diff --git a/extern/draco/src/decoder.cpp b/extern/draco/src/decoder.cpp
index 3f3e03bd9f2..e5ec2b65e6c 100644
--- a/extern/draco/src/decoder.cpp
+++ b/extern/draco/src/decoder.cpp
@@ -17,7 +17,6 @@
* @date 2020-11-18
*/
-
#include "decoder.h"
#include <memory>
@@ -30,7 +29,8 @@
#define LOG_PREFIX "DracoDecoder | "
-struct Decoder {
+struct Decoder
+{
std::unique_ptr<draco::Mesh> mesh;
std::vector<uint8_t> indexBuffer;
std::map<uint32_t, std::vector<uint8_t>> buffers;
@@ -54,20 +54,20 @@ bool decoderDecode(Decoder *decoder, void *data, size_t byteLength)
draco::Decoder dracoDecoder;
draco::DecoderBuffer dracoDecoderBuffer;
dracoDecoderBuffer.Init(reinterpret_cast<char *>(data), byteLength);
-
+
auto decoderStatus = dracoDecoder.DecodeMeshFromBuffer(&dracoDecoderBuffer);
if (!decoderStatus.ok())
{
printf(LOG_PREFIX "Error during Draco decoding: %s\n", decoderStatus.status().error_msg());
return false;
}
-
+
decoder->mesh = std::move(decoderStatus).value();
decoder->vertexCount = decoder->mesh->num_points();
decoder->indexCount = decoder->mesh->num_faces() * 3;
-
+
printf(LOG_PREFIX "Decoded %" PRIu32 " vertices, %" PRIu32 " indices\n", decoder->vertexCount, decoder->indexCount);
-
+
return true;
}
@@ -83,32 +83,32 @@ uint32_t decoderGetIndexCount(Decoder *decoder)
bool decoderAttributeIsNormalized(Decoder *decoder, uint32_t id)
{
- const draco::PointAttribute* attribute = decoder->mesh->GetAttributeByUniqueId(id);
+ const draco::PointAttribute *attribute = decoder->mesh->GetAttributeByUniqueId(id);
return attribute != nullptr && attribute->normalized();
}
bool decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType)
{
- const draco::PointAttribute* attribute = decoder->mesh->GetAttributeByUniqueId(id);
-
+ const draco::PointAttribute *attribute = decoder->mesh->GetAttributeByUniqueId(id);
+
if (attribute == nullptr)
{
printf(LOG_PREFIX "Attribute with id=%" PRIu32 " does not exist in Draco data\n", id);
return false;
}
-
+
size_t stride = getAttributeStride(componentType, dataType);
-
+
std::vector<uint8_t> decodedData;
decodedData.resize(stride * decoder->vertexCount);
-
+
for (uint32_t i = 0; i < decoder->vertexCount; ++i)
{
auto index = attribute->mapped_index(draco::PointIndex(i));
uint8_t *value = decodedData.data() + i * stride;
-
+
bool converted = false;
-
+
switch (componentType)
{
case ComponentType::Byte:
@@ -139,7 +139,7 @@ bool decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, c
return false;
}
}
-
+
decoder->buffers[id] = decodedData;
return true;
}
@@ -166,13 +166,13 @@ void decoderCopyAttribute(Decoder *decoder, size_t id, void *output)
}
}
-template<class T>
+template <class T>
void decodeIndices(Decoder *decoder)
{
std::vector<uint8_t> decodedIndices;
decodedIndices.resize(decoder->indexCount * sizeof(T));
T *typedView = reinterpret_cast<T *>(decodedIndices.data());
-
+
for (uint32_t faceIndex = 0; faceIndex < decoder->mesh->num_faces(); ++faceIndex)
{
const draco::Mesh::Face &face = decoder->mesh->face(draco::FaceIndex(faceIndex));
@@ -180,7 +180,7 @@ void decodeIndices(Decoder *decoder)
typedView[faceIndex * 3 + 1] = face[1].value();
typedView[faceIndex * 3 + 2] = face[2].value();
}
-
+
decoder->indexBuffer = decodedIndices;
}
@@ -188,26 +188,26 @@ bool decoderReadIndices(Decoder *decoder, size_t indexComponentType)
{
switch (indexComponentType)
{
- case ComponentType::Byte:
- decodeIndices<int8_t>(decoder);
- break;
- case ComponentType::UnsignedByte:
- decodeIndices<uint8_t>(decoder);
- break;
- case ComponentType::Short:
- decodeIndices<int16_t>(decoder);
- break;
- case ComponentType::UnsignedShort:
- decodeIndices<uint16_t>(decoder);
- break;
- case ComponentType::UnsignedInt:
- decodeIndices<uint32_t>(decoder);
- break;
- default:
- printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
- return false;
+ case ComponentType::Byte:
+ decodeIndices<int8_t>(decoder);
+ break;
+ case ComponentType::UnsignedByte:
+ decodeIndices<uint8_t>(decoder);
+ break;
+ case ComponentType::Short:
+ decodeIndices<int16_t>(decoder);
+ break;
+ case ComponentType::UnsignedShort:
+ decodeIndices<uint16_t>(decoder);
+ break;
+ case ComponentType::UnsignedInt:
+ decodeIndices<uint32_t>(decoder);
+ break;
+ default:
+ printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
+ return false;
}
-
+
return true;
}
diff --git a/extern/draco/src/decoder.h b/extern/draco/src/decoder.h
index 914eb776e8f..c154b426c59 100644
--- a/extern/draco/src/decoder.h
+++ b/extern/draco/src/decoder.h
@@ -28,26 +28,38 @@
struct Decoder;
-API(Decoder *) decoderCreate();
+API(Decoder *)
+decoderCreate();
-API(void) decoderRelease(Decoder *decoder);
+API(void)
+decoderRelease(Decoder *decoder);
-API(bool) decoderDecode(Decoder *decoder, void *data, size_t byteLength);
+API(bool)
+decoderDecode(Decoder *decoder, void *data, size_t byteLength);
-API(uint32_t) decoderGetVertexCount(Decoder *decoder);
+API(uint32_t)
+decoderGetVertexCount(Decoder *decoder);
-API(uint32_t) decoderGetIndexCount(Decoder *decoder);
+API(uint32_t)
+decoderGetIndexCount(Decoder *decoder);
-API(bool) decoderAttributeIsNormalized(Decoder *decoder, uint32_t id);
+API(bool)
+decoderAttributeIsNormalized(Decoder *decoder, uint32_t id);
-API(bool) decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType);
+API(bool)
+decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType);
-API(size_t) decoderGetAttributeByteLength(Decoder *decoder, size_t id);
+API(size_t)
+decoderGetAttributeByteLength(Decoder *decoder, size_t id);
-API(void) decoderCopyAttribute(Decoder *decoder, size_t id, void *output);
+API(void)
+decoderCopyAttribute(Decoder *decoder, size_t id, void *output);
-API(bool) decoderReadIndices(Decoder *decoder, size_t indexComponentType);
+API(bool)
+decoderReadIndices(Decoder *decoder, size_t indexComponentType);
-API(size_t) decoderGetIndicesByteLength(Decoder *decoder);
+API(size_t)
+decoderGetIndicesByteLength(Decoder *decoder);
-API(void) decoderCopyIndices(Decoder *decoder, void *output);
+API(void)
+decoderCopyIndices(Decoder *decoder, void *output);
diff --git a/extern/draco/src/encoder.cpp b/extern/draco/src/encoder.cpp
index ff7570ecfcd..34282ced8c6 100644
--- a/extern/draco/src/encoder.cpp
+++ b/extern/draco/src/encoder.cpp
@@ -59,7 +59,8 @@ void encoderRelease(Encoder *encoder)
delete encoder;
}
-void encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel) {
+void encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel)
+{
encoder->compressionLevel = compressionLevel;
}
@@ -75,7 +76,7 @@ void encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t no
bool encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder)
{
printf(LOG_PREFIX "Preserve triangle order: %s\n", preserveTriangleOrder ? "yes" : "no");
-
+
draco::Encoder dracoEncoder;
int speed = 10 - static_cast<int>(encoder->compressionLevel);
@@ -87,12 +88,12 @@ bool encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder)
dracoEncoder.SetAttributeQuantization(draco::GeometryAttribute::COLOR, encoder->quantization.color);
dracoEncoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, encoder->quantization.generic);
dracoEncoder.SetTrackEncodedProperties(true);
-
+
if (preserveTriangleOrder)
{
dracoEncoder.SetEncodingMethod(draco::MESH_SEQUENTIAL_ENCODING);
}
-
+
auto encoderStatus = dracoEncoder.EncodeMeshToBuffer(encoder->mesh, &encoder->encoderBuffer);
if (encoderStatus.ok())
{
@@ -130,20 +131,19 @@ void encoderCopy(Encoder *encoder, uint8_t *data)
memcpy(data, encoder->encoderBuffer.data(), encoder->encoderBuffer.size());
}
-template<class T>
+template <class T>
void encodeIndices(Encoder *encoder, uint32_t indexCount, T *indices)
{
int face_count = indexCount / 3;
encoder->mesh.SetNumFaces(static_cast<size_t>(face_count));
encoder->rawSize += indexCount * sizeof(T);
-
+
for (int i = 0; i < face_count; ++i)
{
draco::Mesh::Face face = {
draco::PointIndex(indices[3 * i + 0]),
draco::PointIndex(indices[3 * i + 1]),
- draco::PointIndex(indices[3 * i + 2])
- };
+ draco::PointIndex(indices[3 * i + 2])};
encoder->mesh.SetFace(draco::FaceIndex(static_cast<uint32_t>(i)), face);
}
}
@@ -152,23 +152,23 @@ void encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t ind
{
switch (indexComponentType)
{
- case ComponentType::Byte:
- encodeIndices(encoder, indexCount, reinterpret_cast<int8_t *>(indices));
- break;
- case ComponentType::UnsignedByte:
- encodeIndices(encoder, indexCount, reinterpret_cast<uint8_t *>(indices));
- break;
- case ComponentType::Short:
- encodeIndices(encoder, indexCount, reinterpret_cast<int16_t *>(indices));
- break;
- case ComponentType::UnsignedShort:
- encodeIndices(encoder, indexCount, reinterpret_cast<uint16_t *>(indices));
- break;
- case ComponentType::UnsignedInt:
- encodeIndices(encoder, indexCount, reinterpret_cast<uint32_t *>(indices));
- break;
- default:
- printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
+ case ComponentType::Byte:
+ encodeIndices(encoder, indexCount, reinterpret_cast<int8_t *>(indices));
+ break;
+ case ComponentType::UnsignedByte:
+ encodeIndices(encoder, indexCount, reinterpret_cast<uint8_t *>(indices));
+ break;
+ case ComponentType::Short:
+ encodeIndices(encoder, indexCount, reinterpret_cast<int16_t *>(indices));
+ break;
+ case ComponentType::UnsignedShort:
+ encodeIndices(encoder, indexCount, reinterpret_cast<uint16_t *>(indices));
+ break;
+ case ComponentType::UnsignedInt:
+ encodeIndices(encoder, indexCount, reinterpret_cast<uint32_t *>(indices));
+ break;
+ default:
+ printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
}
}
@@ -190,7 +190,7 @@ draco::GeometryAttribute::Type getAttributeSemantics(char *attribute)
{
return draco::GeometryAttribute::COLOR;
}
-
+
return draco::GeometryAttribute::GENERIC;
}
@@ -198,37 +198,38 @@ draco::DataType getDataType(size_t componentType)
{
switch (componentType)
{
- case ComponentType::Byte:
- return draco::DataType::DT_INT8;
-
- case ComponentType::UnsignedByte:
- return draco::DataType::DT_UINT8;
-
- case ComponentType::Short:
- return draco::DataType::DT_INT16;
-
- case ComponentType::UnsignedShort:
- return draco::DataType::DT_UINT16;
-
- case ComponentType::UnsignedInt:
- return draco::DataType::DT_UINT32;
-
- case ComponentType::Float:
- return draco::DataType::DT_FLOAT32;
-
- default:
- return draco::DataType::DT_INVALID;
+ case ComponentType::Byte:
+ return draco::DataType::DT_INT8;
+
+ case ComponentType::UnsignedByte:
+ return draco::DataType::DT_UINT8;
+
+ case ComponentType::Short:
+ return draco::DataType::DT_INT16;
+
+ case ComponentType::UnsignedShort:
+ return draco::DataType::DT_UINT16;
+
+ case ComponentType::UnsignedInt:
+ return draco::DataType::DT_UINT32;
+
+ case ComponentType::Float:
+ return draco::DataType::DT_FLOAT32;
+
+ default:
+ return draco::DataType::DT_INVALID;
}
}
-API(uint32_t) encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data)
+API(uint32_t)
+encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data)
{
auto buffer = std::make_unique<draco::DataBuffer>();
uint32_t count = encoder->mesh.num_points();
size_t componentCount = getNumberOfComponents(dataType);
size_t stride = getAttributeStride(componentType, dataType);
draco::DataType dracoDataType = getDataType(componentType);
-
+
draco::GeometryAttribute::Type semantics = getAttributeSemantics(attributeName);
draco::GeometryAttribute attribute;
attribute.Init(semantics, &*buffer, componentCount, getDataType(componentType), false, stride, 0);
diff --git a/extern/draco/src/encoder.h b/extern/draco/src/encoder.h
index 2f7f21a469b..c6fdc30295b 100644
--- a/extern/draco/src/encoder.h
+++ b/extern/draco/src/encoder.h
@@ -28,24 +28,35 @@
struct Encoder;
-API(Encoder *) encoderCreate(uint32_t vertexCount);
+API(Encoder *)
+encoderCreate(uint32_t vertexCount);
-API(void) encoderRelease(Encoder *encoder);
+API(void)
+encoderRelease(Encoder *encoder);
-API(void) encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel);
+API(void)
+encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel);
-API(void) encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t normal, uint32_t uv, uint32_t color, uint32_t generic);
+API(void)
+encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t normal, uint32_t uv, uint32_t color, uint32_t generic);
-API(bool) encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder);
+API(bool)
+encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder);
-API(uint64_t) encoderGetByteLength(Encoder *encoder);
+API(uint64_t)
+encoderGetByteLength(Encoder *encoder);
-API(void) encoderCopy(Encoder *encoder, uint8_t *data);
+API(void)
+encoderCopy(Encoder *encoder, uint8_t *data);
-API(void) encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t indexCount, void *indices);
+API(void)
+encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t indexCount, void *indices);
-API(uint32_t) encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data);
+API(uint32_t)
+encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data);
-API(uint32_t) encoderGetEncodedVertexCount(Encoder *encoder);
+API(uint32_t)
+encoderGetEncodedVertexCount(Encoder *encoder);
-API(uint32_t) encoderGetEncodedIndexCount(Encoder *encoder);
+API(uint32_t)
+encoderGetEncodedIndexCount(Encoder *encoder);
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 74b28b8ea21..05f27bdbd4d 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
bl_info = {
diff --git a/intern/cycles/blender/addon/camera.py b/intern/cycles/blender/addon/camera.py
index 0e78112699e..3c821c98128 100644
--- a/intern/cycles/blender/addon/camera.py
+++ b/intern/cycles/blender/addon/camera.py
@@ -1,8 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-# <pep8 compliant>
-
# Fit to match default projective camera with focal_length 50 and sensor_width 36.
default_fisheye_polynomial = [
-1.1735143712967577e-05,
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 724e1b8f727..e211f53cf31 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
diff --git a/intern/cycles/blender/addon/operators.py b/intern/cycles/blender/addon/operators.py
index e5d7f00a381..ab474cda0ab 100644
--- a/intern/cycles/blender/addon/operators.py
+++ b/intern/cycles/blender/addon/operators.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/intern/cycles/blender/addon/osl.py b/intern/cycles/blender/addon/osl.py
index 9430dc5d115..1ee7ae421e3 100644
--- a/intern/cycles/blender/addon/osl.py
+++ b/intern/cycles/blender/addon/osl.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/intern/cycles/blender/addon/presets.py b/intern/cycles/blender/addon/presets.py
index 5eaa592a9de..cc6d574da99 100644
--- a/intern/cycles/blender/addon/presets.py
+++ b/intern/cycles/blender/addon/presets.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
from bl_operators.presets import AddPresetBase
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 9acc9e99ad0..b444a806f8d 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 9d2dbdf6732..88be546746d 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
@@ -756,8 +754,6 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
layout.use_property_split = True
layout.use_property_decorate = False
- with_freestyle = bpy.app.build_options.freestyle
-
scene = context.scene
rd = scene.render
view_layer = context.view_layer
diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py
index 531ecc177da..12880496dfd 100644
--- a/intern/cycles/blender/addon/version_update.py
+++ b/intern/cycles/blender/addon/version_update.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/intern/cycles/blender/camera.cpp b/intern/cycles/blender/camera.cpp
index 402fd7c4ec6..2ab5f02a337 100644
--- a/intern/cycles/blender/camera.cpp
+++ b/intern/cycles/blender/camera.cpp
@@ -643,7 +643,7 @@ void BlenderSync::sync_camera_motion(
/* TODO(sergey): De-duplicate calculation with camera sync. */
float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio);
if (fov != cam->get_fov()) {
- VLOG(3) << "Camera " << b_ob.name() << " FOV change detected.";
+ VLOG_WORK << "Camera " << b_ob.name() << " FOV change detected.";
if (motion_time == 0.0f) {
cam->set_fov(fov);
}
diff --git a/intern/cycles/blender/curves.cpp b/intern/cycles/blender/curves.cpp
index 4e9f4f62087..b01cb85711a 100644
--- a/intern/cycles/blender/curves.cpp
+++ b/intern/cycles/blender/curves.cpp
@@ -341,7 +341,7 @@ static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CDa
/* check allocation */
if ((hair->get_curve_keys().size() != num_keys) || (hair->num_curves() != num_curves)) {
- VLOG(1) << "Hair memory allocation failed, clearing data.";
+ VLOG_WARNING << "Hair memory allocation failed, clearing data.";
hair->clear(true);
}
}
@@ -397,7 +397,7 @@ static void export_hair_motion_validate_attribute(Hair *hair,
if (num_motion_keys != num_keys || !have_motion) {
/* No motion or hair "topology" changed, remove attributes again. */
if (num_motion_keys != num_keys) {
- VLOG(1) << "Hair topology changed, removing motion attribute.";
+ VLOG_WORK << "Hair topology changed, removing motion attribute.";
}
hair->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
}
diff --git a/intern/cycles/blender/display_driver.cpp b/intern/cycles/blender/display_driver.cpp
index ee67073a9a4..a1bc064be68 100644
--- a/intern/cycles/blender/display_driver.cpp
+++ b/intern/cycles/blender/display_driver.cpp
@@ -982,10 +982,8 @@ void BlenderDisplayDriver::draw(const Params &params)
gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush();
- if (VLOG_IS_ON(5)) {
- VLOG(5) << "Number of textures: " << GLTexture::num_used;
- VLOG(5) << "Number of PBOs: " << GLPixelBufferObject::num_used;
- }
+ VLOG_DEVICE_STATS << "Display driver number of textures: " << GLTexture::num_used;
+ VLOG_DEVICE_STATS << "Display driver number of PBOs: " << GLPixelBufferObject::num_used;
if (use_gl_context_) {
gl_context_mutex_.unlock();
diff --git a/intern/cycles/blender/image.cpp b/intern/cycles/blender/image.cpp
index e802fd39335..aea79ad60ad 100644
--- a/intern/cycles/blender/image.cpp
+++ b/intern/cycles/blender/image.cpp
@@ -7,6 +7,8 @@
#include "blender/session.h"
#include "blender/util.h"
+#include "util/half.h"
+
CCL_NAMESPACE_BEGIN
/* Packed Images */
@@ -26,10 +28,33 @@ BlenderImageLoader::BlenderImageLoader(BL::Image b_image,
bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
{
- metadata.width = b_image.size()[0];
- metadata.height = b_image.size()[1];
+ if (b_image.source() != BL::Image::source_TILED) {
+ /* Image sequence might have different dimensions, and hence needs to be handled in a special
+ * manner.
+ * NOTE: Currently the sequences are not handled by this image loader. */
+ assert(b_image.source() != BL::Image::source_SEQUENCE);
+
+ metadata.width = b_image.size()[0];
+ metadata.height = b_image.size()[1];
+ metadata.channels = b_image.channels();
+ }
+ else {
+ /* Different UDIM tiles might have different resolutions, so get resolution from the actual
+ * tile. */
+ BL::UDIMTile b_udim_tile = b_image.tiles.get(tile_number);
+ if (b_udim_tile) {
+ metadata.width = b_udim_tile.size()[0];
+ metadata.height = b_udim_tile.size()[1];
+ metadata.channels = b_udim_tile.channels();
+ }
+ else {
+ metadata.width = 0;
+ metadata.height = 0;
+ metadata.channels = 0;
+ }
+ }
+
metadata.depth = 1;
- metadata.channels = b_image.channels();
if (b_image.is_float()) {
if (metadata.channels == 1) {
@@ -62,80 +87,134 @@ bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaDat
}
bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t pixels_size,
+ void *out_pixels,
+ const size_t out_pixels_size,
const bool associate_alpha)
{
const size_t num_pixels = ((size_t)metadata.width) * metadata.height;
const int channels = metadata.channels;
- if (b_image.is_float()) {
- /* image data */
- float *image_pixels;
- image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile_number);
+ if (metadata.type == IMAGE_DATA_TYPE_FLOAT || metadata.type == IMAGE_DATA_TYPE_FLOAT4) {
+ /* Float. */
+ float *in_pixels = image_get_float_pixels_for_frame(b_image, frame, tile_number);
- if (image_pixels && num_pixels * channels == pixels_size) {
- memcpy(pixels, image_pixels, pixels_size * sizeof(float));
+ if (in_pixels && num_pixels * channels == out_pixels_size) {
+ /* Straight copy pixel data. */
+ memcpy(out_pixels, in_pixels, out_pixels_size * sizeof(float));
}
else {
+ /* Missing or invalid pixel data. */
if (channels == 1) {
- memset(pixels, 0, num_pixels * sizeof(float));
+ memset(out_pixels, 0, num_pixels * sizeof(float));
}
else {
- const size_t num_pixels_safe = pixels_size / channels;
- float *fp = (float *)pixels;
- for (int i = 0; i < num_pixels_safe; i++, fp += channels) {
- fp[0] = 1.0f;
- fp[1] = 0.0f;
- fp[2] = 1.0f;
+ const size_t num_pixels_safe = out_pixels_size / channels;
+ float *out_pixel = (float *)out_pixels;
+ for (int i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
+ out_pixel[0] = 1.0f;
+ out_pixel[1] = 0.0f;
+ out_pixel[2] = 1.0f;
if (channels == 4) {
- fp[3] = 1.0f;
+ out_pixel[3] = 1.0f;
}
}
}
}
- if (image_pixels) {
- MEM_freeN(image_pixels);
+ if (in_pixels) {
+ MEM_freeN(in_pixels);
}
}
- else {
- unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile_number);
+ else if (metadata.type == IMAGE_DATA_TYPE_HALF || metadata.type == IMAGE_DATA_TYPE_HALF4) {
+ /* Half float. Blender does not have a half type, but in some cases
+ * we up-sample byte to half to avoid precision loss for colorspace
+ * conversion. */
+ unsigned char *in_pixels = image_get_pixels_for_frame(b_image, frame, tile_number);
- if (image_pixels && num_pixels * channels == pixels_size) {
- memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char));
+ if (in_pixels && num_pixels * channels == out_pixels_size) {
+ /* Convert uchar to half. */
+ const uchar *in_pixel = in_pixels;
+ half *out_pixel = (half *)out_pixels;
+ if (associate_alpha && channels == 4) {
+ for (size_t i = 0; i < num_pixels; i++, in_pixel += 4, out_pixel += 4) {
+ const float alpha = util_image_cast_to_float(in_pixel[3]);
+ out_pixel[0] = float_to_half_image(util_image_cast_to_float(in_pixel[0]) * alpha);
+ out_pixel[1] = float_to_half_image(util_image_cast_to_float(in_pixel[1]) * alpha);
+ out_pixel[2] = float_to_half_image(util_image_cast_to_float(in_pixel[2]) * alpha);
+ out_pixel[3] = float_to_half_image(alpha);
+ }
+ }
+ else {
+ for (size_t i = 0; i < num_pixels; i++) {
+ for (int c = 0; c < channels; c++, in_pixel++, out_pixel++) {
+ *out_pixel = float_to_half_image(util_image_cast_to_float(*in_pixel));
+ }
+ }
+ }
}
else {
+ /* Missing or invalid pixel data. */
if (channels == 1) {
- memset(pixels, 0, pixels_size * sizeof(unsigned char));
+ memset(out_pixels, 0, num_pixels * sizeof(half));
}
else {
- const size_t num_pixels_safe = pixels_size / channels;
- unsigned char *cp = (unsigned char *)pixels;
- for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) {
- cp[0] = 255;
- cp[1] = 0;
- cp[2] = 255;
+ const size_t num_pixels_safe = out_pixels_size / channels;
+ half *out_pixel = (half *)out_pixels;
+ for (int i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
+ out_pixel[0] = float_to_half_image(1.0f);
+ out_pixel[1] = float_to_half_image(0.0f);
+ out_pixel[2] = float_to_half_image(1.0f);
if (channels == 4) {
- cp[3] = 255;
+ out_pixel[3] = float_to_half_image(1.0f);
}
}
}
}
- if (image_pixels) {
- MEM_freeN(image_pixels);
+ if (in_pixels) {
+ MEM_freeN(in_pixels);
}
+ }
+ else {
+ /* Byte. */
+ unsigned char *in_pixels = image_get_pixels_for_frame(b_image, frame, tile_number);
+
+ if (in_pixels && num_pixels * channels == out_pixels_size) {
+ /* Straight copy pixel data. */
+ memcpy(out_pixels, in_pixels, out_pixels_size * sizeof(unsigned char));
- if (associate_alpha) {
- /* Premultiply, byte images are always straight for Blender. */
- unsigned char *cp = (unsigned char *)pixels;
- for (size_t i = 0; i < num_pixels; i++, cp += channels) {
- cp[0] = (cp[0] * cp[3]) / 255;
- cp[1] = (cp[1] * cp[3]) / 255;
- cp[2] = (cp[2] * cp[3]) / 255;
+ if (associate_alpha && channels == 4) {
+ /* Premultiply, byte images are always straight for Blender. */
+ unsigned char *out_pixel = (unsigned char *)out_pixels;
+ for (size_t i = 0; i < num_pixels; i++, out_pixel += 4) {
+ out_pixel[0] = (out_pixel[0] * out_pixel[3]) / 255;
+ out_pixel[1] = (out_pixel[1] * out_pixel[3]) / 255;
+ out_pixel[2] = (out_pixel[2] * out_pixel[3]) / 255;
+ }
+ }
+ }
+ else {
+ /* Missing or invalid pixel data. */
+ if (channels == 1) {
+ memset(out_pixels, 0, out_pixels_size * sizeof(unsigned char));
+ }
+ else {
+ const size_t num_pixels_safe = out_pixels_size / channels;
+ unsigned char *out_pixel = (unsigned char *)out_pixels;
+ for (size_t i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
+ out_pixel[0] = 255;
+ out_pixel[1] = 0;
+ out_pixel[2] = 255;
+ if (channels == 4) {
+ out_pixel[3] = 255;
+ }
+ }
}
}
+
+ if (in_pixels) {
+ MEM_freeN(in_pixels);
+ }
}
/* Free image buffers to save memory during render. */
diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp
index e2db52cc5c1..63913b7cd7f 100644
--- a/intern/cycles/blender/mesh.cpp
+++ b/intern/cycles/blender/mesh.cpp
@@ -1212,17 +1212,17 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
memcmp(mP, &mesh->get_verts()[0], sizeof(float3) * numverts) == 0) {
/* no motion, remove attributes again */
if (b_mesh.vertices.length() != numverts) {
- VLOG(1) << "Topology differs, disabling motion blur for object " << ob_name;
+ VLOG_WARNING << "Topology differs, disabling motion blur for object " << ob_name;
}
else {
- VLOG(1) << "No actual deformation motion for object " << ob_name;
+ VLOG_DEBUG << "No actual deformation motion for object " << ob_name;
}
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
if (attr_mN)
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
}
else if (motion_step > 0) {
- VLOG(1) << "Filling deformation motion for object " << ob_name;
+ VLOG_DEBUG << "Filling deformation motion for object " << ob_name;
/* motion, fill up previous steps that we might have skipped because
* they had no motion, but we need them anyway now */
float3 *P = &mesh->get_verts()[0];
@@ -1236,8 +1236,8 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
}
else {
if (b_mesh.vertices.length() != numverts) {
- VLOG(1) << "Topology differs, discarding motion blur for object " << ob_name << " at time "
- << motion_step;
+ VLOG_WARNING << "Topology differs, discarding motion blur for object " << ob_name
+ << " at time " << motion_step;
memcpy(mP, &mesh->get_verts()[0], sizeof(float3) * numverts);
if (mN != NULL) {
memcpy(mN, attr_N->data_float3(), sizeof(float3) * numverts);
diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp
index 9b08b564b25..ca1aa6329d9 100644
--- a/intern/cycles/blender/object.cpp
+++ b/intern/cycles/blender/object.cpp
@@ -762,7 +762,7 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
continue;
}
- VLOG(1) << "Synchronizing motion for the relative time " << relative_time << ".";
+ VLOG_WORK << "Synchronizing motion for the relative time " << relative_time << ".";
/* fixed shutter time to get previous and next frame for motion pass */
float shuttertime = scene->motion_shutter_time();
diff --git a/intern/cycles/blender/session.cpp b/intern/cycles/blender/session.cpp
index 87f051ba50b..6d27b8e7d87 100644
--- a/intern/cycles/blender/session.cpp
+++ b/intern/cycles/blender/session.cpp
@@ -458,8 +458,8 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
double total_time, render_time;
session->progress.get_time(total_time, render_time);
- VLOG(1) << "Total render time: " << total_time;
- VLOG(1) << "Render time (without synchronization): " << render_time;
+ VLOG_INFO << "Total render time: " << total_time;
+ VLOG_INFO << "Render time (without synchronization): " << render_time;
}
void BlenderSession::render_frame_finish()
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
index 1028c940772..63e9e1e0e68 100644
--- a/intern/cycles/blender/sync.cpp
+++ b/intern/cycles/blender/sync.cpp
@@ -285,7 +285,7 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
free_data_after_sync(b_depsgraph);
- VLOG(1) << "Total time spent synchronizing data: " << timer.get_time();
+ VLOG_INFO << "Total time spent synchronizing data: " << timer.get_time();
has_updates_ = false;
}
@@ -390,7 +390,7 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
}
if (scrambling_distance != 1.0f) {
- VLOG(3) << "Using scrambling distance: " << scrambling_distance;
+ VLOG_INFO << "Using scrambling distance: " << scrambling_distance;
}
integrator->set_scrambling_distance(scrambling_distance);
diff --git a/intern/cycles/bvh/build.cpp b/intern/cycles/bvh/build.cpp
index 1df3517673e..cf03f05de60 100644
--- a/intern/cycles/bvh/build.cpp
+++ b/intern/cycles/bvh/build.cpp
@@ -529,7 +529,7 @@ BVHNode *BVHBuild::run()
if (progress.get_cancel()) {
rootnode->deleteSubtree();
rootnode = NULL;
- VLOG(1) << "BVH build cancelled.";
+ VLOG_WORK << "BVH build cancelled.";
}
else {
/*rotate(rootnode, 4, 5);*/
@@ -537,26 +537,26 @@ BVHNode *BVHBuild::run()
rootnode->update_time();
}
if (rootnode != NULL) {
- VLOG(1) << "BVH build statistics:\n"
- << " Build time: " << time_dt() - build_start_time << "\n"
- << " Total number of nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT))
- << "\n"
- << " Number of inner nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT))
- << "\n"
- << " Number of leaf nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT))
- << "\n"
- << " Number of unaligned nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT))
- << "\n"
- << " Allocation slop factor: "
- << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() :
- 1.0f)
- << "\n"
- << " Maximum depth: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_DEPTH)) << "\n";
+ VLOG_WORK << "BVH build statistics:\n"
+ << " Build time: " << time_dt() - build_start_time << "\n"
+ << " Total number of nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT))
+ << "\n"
+ << " Number of inner nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT))
+ << "\n"
+ << " Number of leaf nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT))
+ << "\n"
+ << " Number of unaligned nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT))
+ << "\n"
+ << " Allocation slop factor: "
+ << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() :
+ 1.0f)
+ << "\n"
+ << " Maximum depth: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_DEPTH)) << "\n";
}
}
diff --git a/intern/cycles/bvh/embree.cpp b/intern/cycles/bvh/embree.cpp
index 0fc71f49ce3..ea7480bd193 100644
--- a/intern/cycles/bvh/embree.cpp
+++ b/intern/cycles/bvh/embree.cpp
@@ -332,7 +332,7 @@ static bool rtc_memory_monitor_func(void *userPtr, const ssize_t bytes, const bo
static void rtc_error_func(void *, enum RTCError, const char *str)
{
- VLOG(1) << str;
+ VLOG_WARNING << str;
}
static double progress_start_time = 0.0;
@@ -521,8 +521,8 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(int) * 3, num_triangles);
assert(rtc_indices);
if (!rtc_indices) {
- VLOG(1) << "Embree could not create new geometry buffer for mesh " << mesh->name.c_str()
- << ".\n";
+ VLOG_WARNING << "Embree could not create new geometry buffer for mesh " << mesh->name.c_str()
+ << ".\n";
return;
}
for (size_t j = 0; j < num_triangles; ++j) {
diff --git a/intern/cycles/device/cpu/device_impl.cpp b/intern/cycles/device/cpu/device_impl.cpp
index 612c391f7d5..0a4eb089037 100644
--- a/intern/cycles/device/cpu/device_impl.cpp
+++ b/intern/cycles/device/cpu/device_impl.cpp
@@ -55,8 +55,8 @@ CPUDevice::CPUDevice(const DeviceInfo &info_, Stats &stats_, Profiler &profiler_
{
/* Pick any kernel, all of them are supposed to have same level of microarchitecture
* optimization. */
- VLOG(1) << "Using " << get_cpu_kernels().integrator_init_from_camera.get_uarch_name()
- << " CPU kernels.";
+ VLOG_INFO << "Using " << get_cpu_kernels().integrator_init_from_camera.get_uarch_name()
+ << " CPU kernels.";
if (info.cpu_threads == 0) {
info.cpu_threads = TaskScheduler::max_concurrency();
@@ -111,9 +111,9 @@ void CPUDevice::mem_alloc(device_memory &mem)
}
else {
if (mem.name) {
- VLOG(1) << "Buffer allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Buffer allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
}
if (mem.type == MEM_DEVICE_ONLY || !mem.host_pointer) {
@@ -205,9 +205,9 @@ void CPUDevice::const_copy_to(const char *name, void *host, size_t size)
void CPUDevice::global_alloc(device_memory &mem)
{
- VLOG(1) << "Global memory allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Global memory allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
kernel_global_memory_copy(&kernel_globals, mem.name, mem.host_pointer, mem.data_size);
@@ -227,9 +227,9 @@ void CPUDevice::global_free(device_memory &mem)
void CPUDevice::tex_alloc(device_texture &mem)
{
- VLOG(1) << "Texture allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Texture allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
mem.device_pointer = (device_ptr)mem.host_pointer;
mem.device_size = mem.memory_size();
diff --git a/intern/cycles/device/cuda/device.cpp b/intern/cycles/device/cuda/device.cpp
index 400490336d6..5a213c45b71 100644
--- a/intern/cycles/device/cuda/device.cpp
+++ b/intern/cycles/device/cuda/device.cpp
@@ -29,24 +29,25 @@ bool device_cuda_init()
initialized = true;
int cuew_result = cuewInit(CUEW_INIT_CUDA);
if (cuew_result == CUEW_SUCCESS) {
- VLOG(1) << "CUEW initialization succeeded";
+ VLOG_INFO << "CUEW initialization succeeded";
if (CUDADevice::have_precompiled_kernels()) {
- VLOG(1) << "Found precompiled kernels";
+ VLOG_INFO << "Found precompiled kernels";
result = true;
}
else if (cuewCompilerPath() != NULL) {
- VLOG(1) << "Found CUDA compiler " << cuewCompilerPath();
+ VLOG_INFO << "Found CUDA compiler " << cuewCompilerPath();
result = true;
}
else {
- VLOG(1) << "Neither precompiled kernels nor CUDA compiler was found,"
- << " unable to use CUDA";
+ VLOG_INFO << "Neither precompiled kernels nor CUDA compiler was found,"
+ << " unable to use CUDA";
}
}
else {
- VLOG(1) << "CUEW initialization failed: "
- << ((cuew_result == CUEW_ERROR_ATEXIT_FAILED) ? "Error setting up atexit() handler" :
- "Error opening the library");
+ VLOG_WARNING << "CUEW initialization failed: "
+ << ((cuew_result == CUEW_ERROR_ATEXIT_FAILED) ?
+ "Error setting up atexit() handler" :
+ "Error opening the library");
}
return result;
@@ -121,7 +122,8 @@ void device_cuda_info(vector<DeviceInfo> &devices)
int major;
cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, num);
if (major < 3) {
- VLOG(1) << "Ignoring device \"" << name << "\", this graphics card is no longer supported.";
+ VLOG_INFO << "Ignoring device \"" << name
+ << "\", this graphics card is no longer supported.";
continue;
}
@@ -166,21 +168,21 @@ void device_cuda_info(vector<DeviceInfo> &devices)
* Windows 10 even when it is, due to an issue in application profiles.
* Detect case where we expect it to be available and override. */
if (preempt_attr == 0 && (major >= 6) && system_windows_version_at_least(10, 17134)) {
- VLOG(1) << "Assuming device has compute preemption on Windows 10.";
+ VLOG_INFO << "Assuming device has compute preemption on Windows 10.";
preempt_attr = 1;
}
if (timeout_attr && !preempt_attr) {
- VLOG(1) << "Device is recognized as display.";
+ VLOG_INFO << "Device is recognized as display.";
info.description += " (Display)";
info.display_device = true;
display_devices.push_back(info);
}
else {
- VLOG(1) << "Device has compute preemption or is not used for display.";
+ VLOG_INFO << "Device has compute preemption or is not used for display.";
devices.push_back(info);
}
- VLOG(1) << "Added device \"" << name << "\" with id \"" << info.id << "\".";
+ VLOG_INFO << "Added device \"" << name << "\" with id \"" << info.id << "\".";
}
if (!display_devices.empty())
diff --git a/intern/cycles/device/cuda/device_impl.cpp b/intern/cycles/device/cuda/device_impl.cpp
index cb7e909a2d5..e75224abe90 100644
--- a/intern/cycles/device/cuda/device_impl.cpp
+++ b/intern/cycles/device/cuda/device_impl.cpp
@@ -244,9 +244,9 @@ string CUDADevice::compile_kernel(const uint kernel_features,
if (!use_adaptive_compilation()) {
if (!force_ptx) {
const string cubin = path_get(string_printf("lib/%s_sm_%d%d.cubin", name, major, minor));
- VLOG(1) << "Testing for pre-compiled kernel " << cubin << ".";
+ VLOG_INFO << "Testing for pre-compiled kernel " << cubin << ".";
if (path_exists(cubin)) {
- VLOG(1) << "Using precompiled kernel.";
+ VLOG_INFO << "Using precompiled kernel.";
return cubin;
}
}
@@ -256,9 +256,9 @@ string CUDADevice::compile_kernel(const uint kernel_features,
while (ptx_major >= 3) {
const string ptx = path_get(
string_printf("lib/%s_compute_%d%d.ptx", name, ptx_major, ptx_minor));
- VLOG(1) << "Testing for pre-compiled kernel " << ptx << ".";
+ VLOG_INFO << "Testing for pre-compiled kernel " << ptx << ".";
if (path_exists(ptx)) {
- VLOG(1) << "Using precompiled kernel.";
+ VLOG_INFO << "Using precompiled kernel.";
return ptx;
}
@@ -287,9 +287,9 @@ string CUDADevice::compile_kernel(const uint kernel_features,
const string cubin_file = string_printf(
"cycles_%s_%s_%d%d_%s.%s", name, kernel_arch, major, minor, kernel_md5.c_str(), kernel_ext);
const string cubin = path_cache_get(path_join("kernels", cubin_file));
- VLOG(1) << "Testing for locally compiled kernel " << cubin << ".";
+ VLOG_INFO << "Testing for locally compiled kernel " << cubin << ".";
if (path_exists(cubin)) {
- VLOG(1) << "Using locally compiled kernel.";
+ VLOG_INFO << "Using locally compiled kernel.";
return cubin;
}
@@ -323,7 +323,7 @@ string CUDADevice::compile_kernel(const uint kernel_features,
}
const int nvcc_cuda_version = cuewCompilerVersion();
- VLOG(1) << "Found nvcc " << nvcc << ", CUDA version " << nvcc_cuda_version << ".";
+ VLOG_INFO << "Found nvcc " << nvcc << ", CUDA version " << nvcc_cuda_version << ".";
if (nvcc_cuda_version < 101) {
printf(
"Unsupported CUDA version %d.%d detected, "
@@ -399,7 +399,8 @@ bool CUDADevice::load_kernels(const uint kernel_features)
*/
if (cuModule) {
if (use_adaptive_compilation()) {
- VLOG(1) << "Skipping CUDA kernel reload for adaptive compilation, not currently supported.";
+ VLOG_INFO
+ << "Skipping CUDA kernel reload for adaptive compilation, not currently supported.";
}
return true;
}
@@ -481,8 +482,8 @@ void CUDADevice::reserve_local_memory(const uint kernel_features)
cuMemGetInfo(&free_after, &total);
}
- VLOG(1) << "Local memory reserved " << string_human_readable_number(free_before - free_after)
- << " bytes. (" << string_human_readable_size(free_before - free_after) << ")";
+ VLOG_INFO << "Local memory reserved " << string_human_readable_number(free_before - free_after)
+ << " bytes. (" << string_human_readable_size(free_before - free_after) << ")";
# if 0
/* For testing mapped host memory, fill up device memory. */
@@ -513,7 +514,7 @@ void CUDADevice::init_host_memory()
}
}
else {
- VLOG(1) << "Mapped host memory disabled, failed to get system RAM";
+ VLOG_WARNING << "Mapped host memory disabled, failed to get system RAM";
map_host_limit = 0;
}
@@ -524,8 +525,8 @@ void CUDADevice::init_host_memory()
device_working_headroom = 32 * 1024 * 1024LL; // 32MB
device_texture_headroom = 128 * 1024 * 1024LL; // 128MB
- VLOG(1) << "Mapped host memory limit set to " << string_human_readable_number(map_host_limit)
- << " bytes. (" << string_human_readable_size(map_host_limit) << ")";
+ VLOG_INFO << "Mapped host memory limit set to " << string_human_readable_number(map_host_limit)
+ << " bytes. (" << string_human_readable_size(map_host_limit) << ")";
}
void CUDADevice::load_texture_info()
@@ -593,7 +594,7 @@ void CUDADevice::move_textures_to_host(size_t size, bool for_texture)
* multiple CUDA devices could be moving the memory. The
* first one will do it, and the rest will adopt the pointer. */
if (max_mem) {
- VLOG(1) << "Move memory from device to host: " << max_mem->name;
+ VLOG_WORK << "Move memory from device to host: " << max_mem->name;
static thread_mutex move_mutex;
thread_scoped_lock lock(move_mutex);
@@ -701,9 +702,9 @@ CUDADevice::CUDAMem *CUDADevice::generic_alloc(device_memory &mem, size_t pitch_
}
if (mem.name) {
- VLOG(1) << "Buffer allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")" << status;
+ VLOG_WORK << "Buffer allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")" << status;
}
mem.device_pointer = (device_ptr)device_pointer;
@@ -1008,9 +1009,9 @@ void CUDADevice::tex_alloc(device_texture &mem)
desc.NumChannels = mem.data_elements;
desc.Flags = 0;
- VLOG(1) << "Array 3D allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Array 3D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
cuda_assert(cuArray3DCreate(&array_3d, &desc));
diff --git a/intern/cycles/device/cuda/queue.cpp b/intern/cycles/device/cuda/queue.cpp
index 38c71866ad0..5912e68a92b 100644
--- a/intern/cycles/device/cuda/queue.cpp
+++ b/intern/cycles/device/cuda/queue.cpp
@@ -39,12 +39,12 @@ int CUDADeviceQueue::num_concurrent_states(const size_t state_size) const
num_states = max((int)(num_states * factor), 1024);
}
else {
- VLOG(3) << "CYCLES_CONCURRENT_STATES_FACTOR evaluated to 0";
+ VLOG_DEVICE_STATS << "CYCLES_CONCURRENT_STATES_FACTOR evaluated to 0";
}
}
- VLOG(3) << "GPU queue concurrent states: " << num_states << ", using up to "
- << string_human_readable_size(num_states * state_size);
+ VLOG_DEVICE_STATS << "GPU queue concurrent states: " << num_states << ", using up to "
+ << string_human_readable_size(num_states * state_size);
return num_states;
}
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index ea5b3c6dc8c..82c7881da5f 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -325,8 +325,8 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
int orig_cpu_threads = (threads) ? threads : TaskScheduler::max_concurrency();
int cpu_threads = max(orig_cpu_threads - (subdevices.size() - 1), size_t(0));
- VLOG(1) << "CPU render threads reduced from " << orig_cpu_threads << " to " << cpu_threads
- << ", to dedicate to GPU.";
+ VLOG_INFO << "CPU render threads reduced from " << orig_cpu_threads << " to "
+ << cpu_threads << ", to dedicate to GPU.";
if (cpu_threads >= 1) {
DeviceInfo cpu_device = device;
@@ -338,7 +338,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
}
}
else {
- VLOG(1) << "CPU render threads disabled for interactive render.";
+ VLOG_INFO << "CPU render threads disabled for interactive render.";
continue;
}
}
diff --git a/intern/cycles/device/hip/device.cpp b/intern/cycles/device/hip/device.cpp
index d6a5ed9c419..3c9c73e7db0 100644
--- a/intern/cycles/device/hip/device.cpp
+++ b/intern/cycles/device/hip/device.cpp
@@ -29,30 +29,31 @@ bool device_hip_init()
initialized = true;
int hipew_result = hipewInit(HIPEW_INIT_HIP);
if (hipew_result == HIPEW_SUCCESS) {
- VLOG(1) << "HIPEW initialization succeeded";
+ VLOG_INFO << "HIPEW initialization succeeded";
if (HIPDevice::have_precompiled_kernels()) {
- VLOG(1) << "Found precompiled kernels";
+ VLOG_INFO << "Found precompiled kernels";
result = true;
}
else if (hipewCompilerPath() != NULL) {
- VLOG(1) << "Found HIPCC " << hipewCompilerPath();
+ VLOG_INFO << "Found HIPCC " << hipewCompilerPath();
result = true;
}
else {
- VLOG(1) << "Neither precompiled kernels nor HIPCC was found,"
- << " unable to use HIP";
+ VLOG_INFO << "Neither precompiled kernels nor HIPCC was found,"
+ << " unable to use HIP";
}
}
else {
if (hipew_result == HIPEW_ERROR_ATEXIT_FAILED) {
- VLOG(1) << "HIPEW initialization failed: Error setting up atexit() handler";
+ VLOG_WARNING << "HIPEW initialization failed: Error setting up atexit() handler";
}
else if (hipew_result == HIPEW_ERROR_OLD_DRIVER) {
- VLOG(1) << "HIPEW initialization failed: Driver version too old, requires AMD Radeon Pro "
- "21.Q4 driver or newer";
+ VLOG_WARNING
+ << "HIPEW initialization failed: Driver version too old, requires AMD Radeon Pro "
+ "21.Q4 driver or newer";
}
else {
- VLOG(1) << "HIPEW initialization failed: Error opening HIP dynamic library";
+ VLOG_WARNING << "HIPEW initialization failed: Error opening HIP dynamic library";
}
}
@@ -165,16 +166,16 @@ void device_hip_info(vector<DeviceInfo> &devices)
hipDeviceGetAttribute(&timeout_attr, hipDeviceAttributeKernelExecTimeout, num);
if (timeout_attr && !preempt_attr) {
- VLOG(1) << "Device is recognized as display.";
+ VLOG_INFO << "Device is recognized as display.";
info.description += " (Display)";
info.display_device = true;
display_devices.push_back(info);
}
else {
- VLOG(1) << "Device has compute preemption or is not used for display.";
+ VLOG_INFO << "Device has compute preemption or is not used for display.";
devices.push_back(info);
}
- VLOG(1) << "Added device \"" << name << "\" with id \"" << info.id << "\".";
+ VLOG_INFO << "Added device \"" << name << "\" with id \"" << info.id << "\".";
}
if (!display_devices.empty())
diff --git a/intern/cycles/device/hip/device_impl.cpp b/intern/cycles/device/hip/device_impl.cpp
index ea68c821166..652c1001f85 100644
--- a/intern/cycles/device/hip/device_impl.cpp
+++ b/intern/cycles/device/hip/device_impl.cpp
@@ -233,9 +233,9 @@ string HIPDevice::compile_kernel(const uint kernel_features, const char *name, c
/* Attempt to use kernel provided with Blender. */
if (!use_adaptive_compilation()) {
const string fatbin = path_get(string_printf("lib/%s_%s.fatbin", name, arch));
- VLOG(1) << "Testing for pre-compiled kernel " << fatbin << ".";
+ VLOG_INFO << "Testing for pre-compiled kernel " << fatbin << ".";
if (path_exists(fatbin)) {
- VLOG(1) << "Using precompiled kernel.";
+ VLOG_INFO << "Using precompiled kernel.";
return fatbin;
}
}
@@ -265,9 +265,9 @@ string HIPDevice::compile_kernel(const uint kernel_features, const char *name, c
const string include_path = source_path;
const string fatbin_file = string_printf("cycles_%s_%s_%s", name, arch, kernel_md5.c_str());
const string fatbin = path_cache_get(path_join("kernels", fatbin_file));
- VLOG(1) << "Testing for locally compiled kernel " << fatbin << ".";
+ VLOG_INFO << "Testing for locally compiled kernel " << fatbin << ".";
if (path_exists(fatbin)) {
- VLOG(1) << "Using locally compiled kernel.";
+ VLOG_INFO << "Using locally compiled kernel.";
return fatbin;
}
@@ -301,7 +301,7 @@ string HIPDevice::compile_kernel(const uint kernel_features, const char *name, c
}
const int hipcc_hip_version = hipewCompilerVersion();
- VLOG(1) << "Found hipcc " << hipcc << ", HIP version " << hipcc_hip_version << ".";
+ VLOG_INFO << "Found hipcc " << hipcc << ", HIP version " << hipcc_hip_version << ".";
if (hipcc_hip_version < 40) {
printf(
"Unsupported HIP version %d.%d detected, "
@@ -361,7 +361,7 @@ bool HIPDevice::load_kernels(const uint kernel_features)
*/
if (hipModule) {
if (use_adaptive_compilation()) {
- VLOG(1) << "Skipping HIP kernel reload for adaptive compilation, not currently supported.";
+ VLOG_INFO << "Skipping HIP kernel reload for adaptive compilation, not currently supported.";
}
return true;
}
@@ -444,8 +444,8 @@ void HIPDevice::reserve_local_memory(const uint kernel_features)
hipMemGetInfo(&free_after, &total);
}
- VLOG(1) << "Local memory reserved " << string_human_readable_number(free_before - free_after)
- << " bytes. (" << string_human_readable_size(free_before - free_after) << ")";
+ VLOG_INFO << "Local memory reserved " << string_human_readable_number(free_before - free_after)
+ << " bytes. (" << string_human_readable_size(free_before - free_after) << ")";
# if 0
/* For testing mapped host memory, fill up device memory. */
@@ -476,7 +476,7 @@ void HIPDevice::init_host_memory()
}
}
else {
- VLOG(1) << "Mapped host memory disabled, failed to get system RAM";
+ VLOG_WARNING << "Mapped host memory disabled, failed to get system RAM";
map_host_limit = 0;
}
@@ -487,8 +487,8 @@ void HIPDevice::init_host_memory()
device_working_headroom = 32 * 1024 * 1024LL; // 32MB
device_texture_headroom = 128 * 1024 * 1024LL; // 128MB
- VLOG(1) << "Mapped host memory limit set to " << string_human_readable_number(map_host_limit)
- << " bytes. (" << string_human_readable_size(map_host_limit) << ")";
+ VLOG_INFO << "Mapped host memory limit set to " << string_human_readable_number(map_host_limit)
+ << " bytes. (" << string_human_readable_size(map_host_limit) << ")";
}
void HIPDevice::load_texture_info()
@@ -556,7 +556,7 @@ void HIPDevice::move_textures_to_host(size_t size, bool for_texture)
* multiple HIP devices could be moving the memory. The
* first one will do it, and the rest will adopt the pointer. */
if (max_mem) {
- VLOG(1) << "Move memory from device to host: " << max_mem->name;
+ VLOG_WORK << "Move memory from device to host: " << max_mem->name;
static thread_mutex move_mutex;
thread_scoped_lock lock(move_mutex);
@@ -658,9 +658,9 @@ HIPDevice::HIPMem *HIPDevice::generic_alloc(device_memory &mem, size_t pitch_pad
}
if (mem.name) {
- VLOG(1) << "Buffer allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")" << status;
+ VLOG_WORK << "Buffer allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")" << status;
}
mem.device_pointer = (device_ptr)device_pointer;
@@ -966,9 +966,9 @@ void HIPDevice::tex_alloc(device_texture &mem)
desc.NumChannels = mem.data_elements;
desc.Flags = 0;
- VLOG(1) << "Array 3D allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Array 3D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
hip_assert(hipArray3DCreate((hArray *)&array_3d, &desc));
diff --git a/intern/cycles/device/hip/queue.cpp b/intern/cycles/device/hip/queue.cpp
index 6c2c2c29624..8b3d963a32f 100644
--- a/intern/cycles/device/hip/queue.cpp
+++ b/intern/cycles/device/hip/queue.cpp
@@ -39,12 +39,12 @@ int HIPDeviceQueue::num_concurrent_states(const size_t state_size) const
num_states = max((int)(num_states * factor), 1024);
}
else {
- VLOG(3) << "CYCLES_CONCURRENT_STATES_FACTOR evaluated to 0";
+ VLOG_DEVICE_STATS << "CYCLES_CONCURRENT_STATES_FACTOR evaluated to 0";
}
}
- VLOG(3) << "GPU queue concurrent states: " << num_states << ", using up to "
- << string_human_readable_size(num_states * state_size);
+ VLOG_DEVICE_STATS << "GPU queue concurrent states: " << num_states << ", using up to "
+ << string_human_readable_size(num_states * state_size);
return num_states;
}
diff --git a/intern/cycles/device/metal/bvh.mm b/intern/cycles/device/metal/bvh.mm
index 086fbb093ba..09c4ace081e 100644
--- a/intern/cycles/device/metal/bvh.mm
+++ b/intern/cycles/device/metal/bvh.mm
@@ -11,6 +11,7 @@
# include "util/progress.h"
# include "device/metal/bvh.h"
+# include "device/metal/util.h"
CCL_NAMESPACE_BEGIN
@@ -18,6 +19,7 @@ CCL_NAMESPACE_BEGIN
{ \
string str = string_printf(__VA_ARGS__); \
progress.set_substatus(str); \
+ metal_printf("%s\n", str.c_str()); \
}
BVHMetal::BVHMetal(const BVHParams &params_,
diff --git a/intern/cycles/device/metal/device_impl.h b/intern/cycles/device/metal/device_impl.h
index 7506b9b069f..0e6817d94f8 100644
--- a/intern/cycles/device/metal/device_impl.h
+++ b/intern/cycles/device/metal/device_impl.h
@@ -31,6 +31,8 @@ class MetalDevice : public Device {
string source[PSO_NUM];
string source_md5[PSO_NUM];
+ bool capture_enabled = false;
+
KernelParamsMetal launch_params = {0};
/* MetalRT members ----------------------------------*/
diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm
index 16aabacb4cf..a0ac677beda 100644
--- a/intern/cycles/device/metal/device_impl.mm
+++ b/intern/cycles/device/metal/device_impl.mm
@@ -86,6 +86,10 @@ MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profile
use_metalrt = (atoi(metalrt) != 0);
}
+ if (getenv("CYCLES_DEBUG_METAL_CAPTURE_KERNEL")) {
+ capture_enabled = true;
+ }
+
MTLArgumentDescriptor *arg_desc_params = [[MTLArgumentDescriptor alloc] init];
arg_desc_params.dataType = MTLDataTypePointer;
arg_desc_params.access = MTLArgumentAccessReadOnly;
@@ -394,7 +398,7 @@ MetalDevice::MetalMem *MetalDevice::generic_alloc(device_memory &mem)
}
if (size > 0) {
- if (mem.type == MEM_DEVICE_ONLY) {
+ if (mem.type == MEM_DEVICE_ONLY && !capture_enabled) {
options = MTLResourceStorageModePrivate;
}
@@ -407,9 +411,9 @@ MetalDevice::MetalMem *MetalDevice::generic_alloc(device_memory &mem)
}
if (mem.name) {
- VLOG(2) << "Buffer allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Buffer allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
}
mem.device_size = metal_buffer.allocatedSize;
@@ -796,9 +800,9 @@ void MetalDevice::tex_alloc(device_texture &mem)
desc.textureType = MTLTextureType3D;
desc.depth = mem.data_depth;
- VLOG(2) << "Texture 3D allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Texture 3D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
mtlTexture = [mtlDevice newTextureWithDescriptor:desc];
assert(mtlTexture);
@@ -830,9 +834,9 @@ void MetalDevice::tex_alloc(device_texture &mem)
desc.storageMode = storage_mode;
desc.usage = MTLTextureUsageShaderRead;
- VLOG(2) << "Texture 2D allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Texture 2D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
mtlTexture = [mtlDevice newTextureWithDescriptor:desc];
assert(mtlTexture);
diff --git a/intern/cycles/device/metal/queue.h b/intern/cycles/device/metal/queue.h
index 6cc84a20787..b0bd487c86d 100644
--- a/intern/cycles/device/metal/queue.h
+++ b/intern/cycles/device/metal/queue.h
@@ -12,8 +12,6 @@
# include "device/metal/util.h"
# include "kernel/device/metal/globals.h"
-# define metal_printf VLOG(4) << string_printf
-
CCL_NAMESPACE_BEGIN
class MetalDevice;
@@ -40,43 +38,82 @@ class MetalDeviceQueue : public DeviceQueue {
virtual void copy_from_device(device_memory &mem) override;
protected:
+ void setup_capture();
+ void update_capture(DeviceKernel kernel);
+ void begin_capture();
+ void end_capture();
void prepare_resources(DeviceKernel kernel);
id<MTLComputeCommandEncoder> get_compute_encoder(DeviceKernel kernel);
id<MTLBlitCommandEncoder> get_blit_encoder();
- MetalDevice *metal_device;
- MetalBufferPool temp_buffer_pool;
+ MetalDevice *metal_device_;
+ MetalBufferPool temp_buffer_pool_;
API_AVAILABLE(macos(11.0), ios(14.0))
- MTLCommandBufferDescriptor *command_buffer_desc = nullptr;
- id<MTLDevice> mtlDevice = nil;
- id<MTLCommandQueue> mtlCommandQueue = nil;
- id<MTLCommandBuffer> mtlCommandBuffer = nil;
- id<MTLComputeCommandEncoder> mtlComputeEncoder = nil;
- id<MTLBlitCommandEncoder> mtlBlitEncoder = nil;
+ MTLCommandBufferDescriptor *command_buffer_desc_ = nullptr;
+ id<MTLDevice> mtlDevice_ = nil;
+ id<MTLCommandQueue> mtlCommandQueue_ = nil;
+ id<MTLCommandBuffer> mtlCommandBuffer_ = nil;
+ id<MTLComputeCommandEncoder> mtlComputeEncoder_ = nil;
+ id<MTLBlitCommandEncoder> mtlBlitEncoder_ = nil;
API_AVAILABLE(macos(10.14), ios(14.0))
- id<MTLSharedEvent> shared_event = nil;
+ id<MTLSharedEvent> shared_event_ = nil;
API_AVAILABLE(macos(10.14), ios(14.0))
- MTLSharedEventListener *shared_event_listener = nil;
+ MTLSharedEventListener *shared_event_listener_ = nil;
- dispatch_queue_t event_queue;
- dispatch_semaphore_t wait_semaphore;
+ dispatch_queue_t event_queue_;
+ dispatch_semaphore_t wait_semaphore_;
struct CopyBack {
void *host_pointer;
void *gpu_mem;
uint64_t size;
};
- std::vector<CopyBack> copy_back_mem;
+ std::vector<CopyBack> copy_back_mem_;
- uint64_t shared_event_id;
- uint64_t command_buffers_submitted = 0;
- uint64_t command_buffers_completed = 0;
- Stats &stats;
+ uint64_t shared_event_id_;
+ uint64_t command_buffers_submitted_ = 0;
+ uint64_t command_buffers_completed_ = 0;
+ Stats &stats_;
void close_compute_encoder();
void close_blit_encoder();
+
+ bool verbose_tracing_ = false;
+ bool label_command_encoders_ = false;
+
+ /* Per-kernel profiling (see CYCLES_METAL_PROFILING). */
+
+ struct TimingData {
+ DeviceKernel kernel;
+ int work_size;
+ uint64_t timing_id;
+ };
+ std::vector<TimingData> command_encoder_labels_;
+ API_AVAILABLE(macos(10.14), ios(14.0))
+ id<MTLSharedEvent> timing_shared_event_ = nil;
+ uint64_t timing_shared_event_id_;
+ uint64_t command_buffer_start_timing_id_;
+
+ struct TimingStats {
+ double total_time = 0.0;
+ uint64_t total_work_size = 0;
+ uint64_t num_dispatches = 0;
+ };
+ TimingStats timing_stats_[DEVICE_KERNEL_NUM];
+ double last_completion_time_ = 0.0;
+
+ /* .gputrace capture (see CYCLES_DEBUG_METAL_CAPTURE_...). */
+
+ id<MTLCaptureScope> mtlCaptureScope_ = nil;
+ DeviceKernel capture_kernel_;
+ int capture_dispatch_counter_ = 0;
+ bool capture_samples_ = false;
+ int capture_reset_counter_ = 0;
+ bool is_capturing_ = false;
+ bool is_capturing_to_disk_ = false;
+ bool has_captured_to_disk_ = false;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/metal/queue.mm b/intern/cycles/device/metal/queue.mm
index c1dab5b0d8f..55db7c5afce 100644
--- a/intern/cycles/device/metal/queue.mm
+++ b/intern/cycles/device/metal/queue.mm
@@ -17,46 +17,250 @@ CCL_NAMESPACE_BEGIN
/* MetalDeviceQueue */
MetalDeviceQueue::MetalDeviceQueue(MetalDevice *device)
- : DeviceQueue(device), metal_device(device), stats(device->stats)
+ : DeviceQueue(device), metal_device_(device), stats_(device->stats)
{
if (@available(macos 11.0, *)) {
- command_buffer_desc = [[MTLCommandBufferDescriptor alloc] init];
- command_buffer_desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
+ command_buffer_desc_ = [[MTLCommandBufferDescriptor alloc] init];
+ command_buffer_desc_.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
}
- mtlDevice = device->mtlDevice;
- mtlCommandQueue = [mtlDevice newCommandQueue];
+ mtlDevice_ = device->mtlDevice;
+ mtlCommandQueue_ = [mtlDevice_ newCommandQueue];
if (@available(macos 10.14, *)) {
- shared_event = [mtlDevice newSharedEvent];
- shared_event_id = 1;
+ shared_event_ = [mtlDevice_ newSharedEvent];
+ shared_event_id_ = 1;
/* Shareable event listener */
- event_queue = dispatch_queue_create("com.cycles.metal.event_queue", NULL);
- shared_event_listener = [[MTLSharedEventListener alloc] initWithDispatchQueue:event_queue];
+ event_queue_ = dispatch_queue_create("com.cycles.metal.event_queue", NULL);
+ shared_event_listener_ = [[MTLSharedEventListener alloc] initWithDispatchQueue:event_queue_];
}
- wait_semaphore = dispatch_semaphore_create(0);
+ wait_semaphore_ = dispatch_semaphore_create(0);
+
+ if (@available(macos 10.14, *)) {
+ if (getenv("CYCLES_METAL_PROFILING")) {
+ /* Enable per-kernel timing breakdown (shown at end of render). */
+ timing_shared_event_ = [mtlDevice_ newSharedEvent];
+ label_command_encoders_ = true;
+ }
+ if (getenv("CYCLES_METAL_DEBUG")) {
+ /* Enable very verbose tracing (shows every dispatch). */
+ verbose_tracing_ = true;
+ label_command_encoders_ = true;
+ }
+ timing_shared_event_id_ = 1;
+ }
+
+ setup_capture();
+}
+
+void MetalDeviceQueue::setup_capture()
+{
+ capture_kernel_ = DeviceKernel(-1);
+
+ if (auto capture_kernel_str = getenv("CYCLES_DEBUG_METAL_CAPTURE_KERNEL")) {
+ /* CYCLES_DEBUG_METAL_CAPTURE_KERNEL captures a single dispatch of the specified kernel. */
+ capture_kernel_ = DeviceKernel(atoi(capture_kernel_str));
+ printf("Capture kernel: %d = %s\n", capture_kernel_, device_kernel_as_string(capture_kernel_));
+
+ capture_dispatch_counter_ = 0;
+ if (auto capture_dispatch_str = getenv("CYCLES_DEBUG_METAL_CAPTURE_DISPATCH")) {
+ capture_dispatch_counter_ = atoi(capture_dispatch_str);
+
+ printf("Capture dispatch number %d\n", capture_dispatch_counter_);
+ }
+ }
+ else if (auto capture_samples_str = getenv("CYCLES_DEBUG_METAL_CAPTURE_SAMPLES")) {
+ /* CYCLES_DEBUG_METAL_CAPTURE_SAMPLES captures a block of dispatches from reset#(N) to
+ * reset#(N+1). */
+ capture_samples_ = true;
+ capture_reset_counter_ = atoi(capture_samples_str);
+
+ capture_dispatch_counter_ = INT_MAX;
+ if (auto capture_limit_str = getenv("CYCLES_DEBUG_METAL_CAPTURE_LIMIT")) {
+ /* CYCLES_DEBUG_METAL_CAPTURE_LIMIT sets the maximum number of dispatches to capture. */
+ capture_dispatch_counter_ = atoi(capture_limit_str);
+ }
+
+ printf("Capturing sample block %d (dispatch limit: %d)\n",
+ capture_reset_counter_,
+ capture_dispatch_counter_);
+ }
+ else {
+ /* No capturing requested. */
+ return;
+ }
+
+ /* Enable .gputrace capture for the specified DeviceKernel. */
+ MTLCaptureManager *captureManager = [MTLCaptureManager sharedCaptureManager];
+ mtlCaptureScope_ = [captureManager newCaptureScopeWithDevice:mtlDevice_];
+ mtlCaptureScope_.label = [NSString stringWithFormat:@"Cycles kernel dispatch"];
+ [captureManager setDefaultCaptureScope:mtlCaptureScope_];
+
+ label_command_encoders_ = true;
+
+ if (auto capture_url = getenv("CYCLES_DEBUG_METAL_CAPTURE_URL")) {
+ if (@available(macos 10.15, *)) {
+ if ([captureManager supportsDestination:MTLCaptureDestinationGPUTraceDocument]) {
+
+ MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
+ captureDescriptor.captureObject = mtlCaptureScope_;
+ captureDescriptor.destination = MTLCaptureDestinationGPUTraceDocument;
+ captureDescriptor.outputURL = [NSURL fileURLWithPath:@(capture_url)];
+
+ NSError *error;
+ if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error]) {
+ NSString *err = [error localizedDescription];
+ printf("Start capture failed: %s\n", [err UTF8String]);
+ }
+ else {
+ printf("Capture started (URL: %s)\n", capture_url);
+ is_capturing_to_disk_ = true;
+ }
+ }
+ else {
+ printf("Capture to file is not supported\n");
+ }
+ }
+ }
+}
+
+void MetalDeviceQueue::update_capture(DeviceKernel kernel)
+{
+ /* Handle capture end triggers. */
+ if (is_capturing_) {
+ capture_dispatch_counter_ -= 1;
+ if (capture_dispatch_counter_ <= 0 || kernel == DEVICE_KERNEL_INTEGRATOR_RESET) {
+ /* End capture if we've hit the dispatch limit or we hit a "reset". */
+ end_capture();
+ }
+ return;
+ }
+
+ if (capture_dispatch_counter_ < 0) {
+ /* We finished capturing. */
+ return;
+ }
+
+ /* Handle single-capture start trigger. */
+ if (kernel == capture_kernel_) {
+ /* Start capturing when the we hit the Nth dispatch of the specified kernel. */
+ if (capture_dispatch_counter_ == 0) {
+ begin_capture();
+ }
+ capture_dispatch_counter_ -= 1;
+ return;
+ }
+
+ /* Handle multi-capture start trigger. */
+ if (capture_samples_) {
+ /* Start capturing when the reset countdown is at 0. */
+ if (capture_reset_counter_ == 0) {
+ begin_capture();
+ }
+
+ if (kernel == DEVICE_KERNEL_INTEGRATOR_RESET) {
+ capture_reset_counter_ -= 1;
+ }
+ return;
+ }
+}
+
+void MetalDeviceQueue::begin_capture()
+{
+ /* Start gputrace capture. */
+ if (mtlCommandBuffer_) {
+ synchronize();
+ }
+ [mtlCaptureScope_ beginScope];
+ printf("[mtlCaptureScope_ beginScope]\n");
+ is_capturing_ = true;
+}
+
+void MetalDeviceQueue::end_capture()
+{
+ [mtlCaptureScope_ endScope];
+ is_capturing_ = false;
+ printf("[mtlCaptureScope_ endScope]\n");
+
+ if (is_capturing_to_disk_) {
+ if (@available(macos 10.15, *)) {
+ [[MTLCaptureManager sharedCaptureManager] stopCapture];
+ has_captured_to_disk_ = true;
+ is_capturing_to_disk_ = false;
+ is_capturing_ = false;
+ printf("Capture stopped\n");
+ }
+ }
}
MetalDeviceQueue::~MetalDeviceQueue()
{
/* Tidying up here isn't really practical - we should expect and require the work
* queue to be empty here. */
- assert(mtlCommandBuffer == nil);
- assert(command_buffers_submitted == command_buffers_completed);
+ assert(mtlCommandBuffer_ == nil);
+ assert(command_buffers_submitted_ == command_buffers_completed_);
if (@available(macos 10.14, *)) {
- [shared_event_listener release];
- [shared_event release];
+ [shared_event_listener_ release];
+ [shared_event_ release];
}
if (@available(macos 11.0, *)) {
- [command_buffer_desc release];
- }
- if (mtlCommandQueue) {
- [mtlCommandQueue release];
- mtlCommandQueue = nil;
+ [command_buffer_desc_ release];
+ }
+ if (mtlCommandQueue_) {
+ [mtlCommandQueue_ release];
+ mtlCommandQueue_ = nil;
+ }
+
+ if (mtlCaptureScope_) {
+ [mtlCaptureScope_ release];
+ }
+
+ double total_time = 0.0;
+
+ /* Show per-kernel timings, if gathered (see CYCLES_METAL_PROFILING). */
+ int64_t num_dispatches = 0;
+ for (auto &stat : timing_stats_) {
+ total_time += stat.total_time;
+ num_dispatches += stat.num_dispatches;
+ }
+
+ if (num_dispatches) {
+ printf("\nMetal dispatch stats:\n\n");
+ auto header = string_printf("%-40s %16s %12s %12s %7s %7s",
+ "Kernel name",
+ "Total threads",
+ "Dispatches",
+ "Avg. T/D",
+ "Time",
+ "Time%");
+ auto divider = string(header.length(), '-');
+ printf("%s\n%s\n%s\n", divider.c_str(), header.c_str(), divider.c_str());
+
+ for (size_t i = 0; i < DEVICE_KERNEL_NUM; i++) {
+ auto &stat = timing_stats_[i];
+ if (stat.num_dispatches > 0) {
+ printf("%-40s %16s %12s %12s %6.2fs %6.2f%%\n",
+ device_kernel_as_string(DeviceKernel(i)),
+ string_human_readable_number(stat.total_work_size).c_str(),
+ string_human_readable_number(stat.num_dispatches).c_str(),
+ string_human_readable_number(stat.total_work_size / stat.num_dispatches).c_str(),
+ stat.total_time,
+ stat.total_time * 100.0 / total_time);
+ }
+ }
+ printf("%s\n", divider.c_str());
+ printf("%-40s %16s %12s %12s %6.2fs %6.2f%%\n",
+ "",
+ "",
+ string_human_readable_number(num_dispatches).c_str(),
+ "",
+ total_time,
+ 100.0);
+ printf("%s\n\n", divider.c_str());
}
}
@@ -66,10 +270,10 @@ int MetalDeviceQueue::num_concurrent_states(const size_t /*state_size*/) const
/* TODO: compute automatically. */
/* TODO: must have at least num_threads_per_block. */
int result = 1048576;
- if (metal_device->device_vendor == METAL_GPU_AMD) {
+ if (metal_device_->device_vendor == METAL_GPU_AMD) {
result *= 2;
}
- else if (metal_device->device_vendor == METAL_GPU_APPLE) {
+ else if (metal_device_->device_vendor == METAL_GPU_APPLE) {
result *= 4;
}
return result;
@@ -80,10 +284,10 @@ int MetalDeviceQueue::num_concurrent_busy_states() const
/* METAL_WIP */
/* TODO: compute automatically. */
int result = 65536;
- if (metal_device->device_vendor == METAL_GPU_AMD) {
+ if (metal_device_->device_vendor == METAL_GPU_AMD) {
result *= 2;
}
- else if (metal_device->device_vendor == METAL_GPU_APPLE) {
+ else if (metal_device_->device_vendor == METAL_GPU_APPLE) {
result *= 4;
}
return result;
@@ -92,7 +296,7 @@ int MetalDeviceQueue::num_concurrent_busy_states() const
void MetalDeviceQueue::init_execution()
{
/* Synchronize all textures and memory copies before executing task. */
- metal_device->load_texture_info();
+ metal_device_->load_texture_info();
synchronize();
}
@@ -101,15 +305,23 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
const int work_size,
DeviceKernelArguments const &args)
{
- if (metal_device->have_error()) {
+ update_capture(kernel);
+
+ if (metal_device_->have_error()) {
return false;
}
- VLOG(3) << "Metal queue launch " << device_kernel_as_string(kernel) << ", work_size "
- << work_size;
+ VLOG_DEVICE_STATS << "Metal queue launch " << device_kernel_as_string(kernel) << ", work_size "
+ << work_size;
id<MTLComputeCommandEncoder> mtlComputeCommandEncoder = get_compute_encoder(kernel);
+ if (@available(macos 10.14, *)) {
+ if (timing_shared_event_) {
+ command_encoder_labels_.push_back({kernel, work_size, timing_shared_event_id_});
+ }
+ }
+
/* Determine size requirement for argument buffer. */
size_t arg_buffer_length = 0;
for (size_t i = 0; i < args.count; i++) {
@@ -126,8 +338,8 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
/* Metal ancillary bindless pointers. */
size_t metal_offsets = arg_buffer_length;
- arg_buffer_length += metal_device->mtlAncillaryArgEncoder.encodedLength;
- arg_buffer_length = round_up(arg_buffer_length, metal_device->mtlAncillaryArgEncoder.alignment);
+ arg_buffer_length += metal_device_->mtlAncillaryArgEncoder.encodedLength;
+ arg_buffer_length = round_up(arg_buffer_length, metal_device_->mtlAncillaryArgEncoder.alignment);
/* Temporary buffer used to prepare arg_buffer */
uint8_t *init_arg_buffer = (uint8_t *)alloca(arg_buffer_length);
@@ -150,19 +362,23 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
sizeof(IntegratorStateGPU);
size_t plain_old_launch_data_size = sizeof(KernelParamsMetal) - plain_old_launch_data_offset;
memcpy(init_arg_buffer + globals_offsets + plain_old_launch_data_offset,
- (uint8_t *)&metal_device->launch_params + plain_old_launch_data_offset,
+ (uint8_t *)&metal_device_->launch_params + plain_old_launch_data_offset,
plain_old_launch_data_size);
/* Allocate an argument buffer. */
MTLResourceOptions arg_buffer_options = MTLResourceStorageModeManaged;
if (@available(macOS 11.0, *)) {
- if ([mtlDevice hasUnifiedMemory]) {
+ if ([mtlDevice_ hasUnifiedMemory]) {
arg_buffer_options = MTLResourceStorageModeShared;
}
}
- id<MTLBuffer> arg_buffer = temp_buffer_pool.get_buffer(
- mtlDevice, mtlCommandBuffer, arg_buffer_length, arg_buffer_options, init_arg_buffer, stats);
+ id<MTLBuffer> arg_buffer = temp_buffer_pool_.get_buffer(mtlDevice_,
+ mtlCommandBuffer_,
+ arg_buffer_length,
+ arg_buffer_options,
+ init_arg_buffer,
+ stats_);
/* Encode the pointer "enqueue" arguments */
bytes_written = 0;
@@ -170,16 +386,16 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
size_t size_in_bytes = args.sizes[i];
bytes_written = round_up(bytes_written, size_in_bytes);
if (args.types[i] == DeviceKernelArguments::POINTER) {
- [metal_device->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer
- offset:bytes_written];
+ [metal_device_->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer
+ offset:bytes_written];
if (MetalDevice::MetalMem *mmem = *(MetalDevice::MetalMem **)args.values[i]) {
[mtlComputeCommandEncoder useResource:mmem->mtlBuffer
usage:MTLResourceUsageRead | MTLResourceUsageWrite];
- [metal_device->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer offset:0 atIndex:0];
+ [metal_device_->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer offset:0 atIndex:0];
}
else {
if (@available(macos 12.0, *)) {
- [metal_device->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:0];
+ [metal_device_->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:0];
}
}
}
@@ -187,49 +403,58 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
}
/* Encode KernelParamsMetal buffers */
- [metal_device->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer offset:globals_offsets];
+ [metal_device_->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer
+ offset:globals_offsets];
+
+ if (label_command_encoders_) {
+ /* Add human-readable labels if we're doing any form of debugging / profiling. */
+ mtlComputeCommandEncoder.label = [[NSString alloc]
+ initWithFormat:@"Metal queue launch %s, work_size %d",
+ device_kernel_as_string(kernel),
+ work_size];
+ }
/* this relies on IntegratorStateGPU layout being contiguous device_ptrs */
const size_t pointer_block_end = offsetof(KernelParamsMetal, __integrator_state) +
sizeof(IntegratorStateGPU);
for (size_t offset = 0; offset < pointer_block_end; offset += sizeof(device_ptr)) {
- int pointer_index = offset / sizeof(device_ptr);
+ int pointer_index = int(offset / sizeof(device_ptr));
MetalDevice::MetalMem *mmem = *(
- MetalDevice::MetalMem **)((uint8_t *)&metal_device->launch_params + offset);
- if (mmem && (mmem->mtlBuffer || mmem->mtlTexture)) {
- [metal_device->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer
- offset:0
- atIndex:pointer_index];
+ MetalDevice::MetalMem **)((uint8_t *)&metal_device_->launch_params + offset);
+ if (mmem && mmem->mem && (mmem->mtlBuffer || mmem->mtlTexture)) {
+ [metal_device_->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer
+ offset:0
+ atIndex:pointer_index];
}
else {
if (@available(macos 12.0, *)) {
- [metal_device->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:pointer_index];
+ [metal_device_->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:pointer_index];
}
}
}
bytes_written = globals_offsets + sizeof(KernelParamsMetal);
- const MetalKernelPipeline *metal_kernel_pso = MetalDeviceKernels::get_best_pipeline(metal_device,
- kernel);
+ const MetalKernelPipeline *metal_kernel_pso = MetalDeviceKernels::get_best_pipeline(
+ metal_device_, kernel);
if (!metal_kernel_pso) {
- metal_device->set_error(
+ metal_device_->set_error(
string_printf("No MetalKernelPipeline for %s\n", device_kernel_as_string(kernel)));
return false;
}
/* Encode ancillaries */
- [metal_device->mtlAncillaryArgEncoder setArgumentBuffer:arg_buffer offset:metal_offsets];
- [metal_device->mtlAncillaryArgEncoder setBuffer:metal_device->texture_bindings_2d
- offset:0
- atIndex:0];
- [metal_device->mtlAncillaryArgEncoder setBuffer:metal_device->texture_bindings_3d
- offset:0
- atIndex:1];
+ [metal_device_->mtlAncillaryArgEncoder setArgumentBuffer:arg_buffer offset:metal_offsets];
+ [metal_device_->mtlAncillaryArgEncoder setBuffer:metal_device_->texture_bindings_2d
+ offset:0
+ atIndex:0];
+ [metal_device_->mtlAncillaryArgEncoder setBuffer:metal_device_->texture_bindings_3d
+ offset:0
+ atIndex:1];
if (@available(macos 12.0, *)) {
- if (metal_device->use_metalrt) {
- if (metal_device->bvhMetalRT) {
- id<MTLAccelerationStructure> accel_struct = metal_device->bvhMetalRT->accel_struct;
- [metal_device->mtlAncillaryArgEncoder setAccelerationStructure:accel_struct atIndex:2];
+ if (metal_device_->use_metalrt) {
+ if (metal_device_->bvhMetalRT) {
+ id<MTLAccelerationStructure> accel_struct = metal_device_->bvhMetalRT->accel_struct;
+ [metal_device_->mtlAncillaryArgEncoder setAccelerationStructure:accel_struct atIndex:2];
}
for (int table = 0; table < METALRT_TABLE_NUM; table++) {
@@ -237,19 +462,19 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
[metal_kernel_pso->intersection_func_table[table] setBuffer:arg_buffer
offset:globals_offsets
atIndex:1];
- [metal_device->mtlAncillaryArgEncoder
+ [metal_device_->mtlAncillaryArgEncoder
setIntersectionFunctionTable:metal_kernel_pso->intersection_func_table[table]
atIndex:3 + table];
[mtlComputeCommandEncoder useResource:metal_kernel_pso->intersection_func_table[table]
usage:MTLResourceUsageRead];
}
else {
- [metal_device->mtlAncillaryArgEncoder setIntersectionFunctionTable:nil
- atIndex:3 + table];
+ [metal_device_->mtlAncillaryArgEncoder setIntersectionFunctionTable:nil
+ atIndex:3 + table];
}
}
}
- bytes_written = metal_offsets + metal_device->mtlAncillaryArgEncoder.encodedLength;
+ bytes_written = metal_offsets + metal_device_->mtlAncillaryArgEncoder.encodedLength;
}
if (arg_buffer.storageMode == MTLStorageModeManaged) {
@@ -260,10 +485,10 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
[mtlComputeCommandEncoder setBuffer:arg_buffer offset:globals_offsets atIndex:1];
[mtlComputeCommandEncoder setBuffer:arg_buffer offset:metal_offsets atIndex:2];
- if (metal_device->use_metalrt) {
+ if (metal_device_->use_metalrt) {
if (@available(macos 12.0, *)) {
- auto bvhMetalRT = metal_device->bvhMetalRT;
+ auto bvhMetalRT = metal_device_->bvhMetalRT;
switch (kernel) {
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
@@ -305,7 +530,7 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
/* See parallel_active_index.h for why this amount of shared memory is needed.
* Rounded up to 16 bytes for Metal */
- shared_mem_bytes = round_up((num_threads_per_block + 1) * sizeof(int), 16);
+ shared_mem_bytes = (int)round_up((num_threads_per_block + 1) * sizeof(int), 16);
[mtlComputeCommandEncoder setThreadgroupMemoryLength:shared_mem_bytes atIndex:0];
break;
@@ -319,7 +544,7 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
[mtlComputeCommandEncoder dispatchThreadgroups:size_threadgroups_per_dispatch
threadsPerThreadgroup:size_threads_per_threadgroup];
- [mtlCommandBuffer addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ [mtlCommandBuffer_ addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
NSString *kernel_name = metal_kernel_pso->function.label;
/* Enhanced command buffer errors are only available in 11.0+ */
@@ -344,50 +569,117 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
}
}];
- return !(metal_device->have_error());
+ if (verbose_tracing_ || is_capturing_) {
+ /* Force a sync we've enabled step-by-step verbose tracing or if we're capturing. */
+ synchronize();
+
+ /* Show queue counters and dispatch timing. */
+ if (verbose_tracing_) {
+ if (kernel == DEVICE_KERNEL_INTEGRATOR_RESET) {
+ printf(
+ "_____________________________________.____________________.______________.___________"
+ "______________________________________\n");
+ }
+
+ printf("%-40s| %7d threads |%5.2fms | buckets [",
+ device_kernel_as_string(kernel),
+ work_size,
+ last_completion_time_ * 1000.0);
+ std::lock_guard<std::recursive_mutex> lock(metal_device_->metal_mem_map_mutex);
+ for (auto &it : metal_device_->metal_mem_map) {
+ const string c_integrator_queue_counter = "integrator_queue_counter";
+ if (it.first->name == c_integrator_queue_counter) {
+ /* Workaround "device_copy_from" being protected. */
+ struct MyDeviceMemory : device_memory {
+ void device_copy_from__IntegratorQueueCounter()
+ {
+ device_copy_from(0, data_width, 1, sizeof(IntegratorQueueCounter));
+ }
+ };
+ ((MyDeviceMemory *)it.first)->device_copy_from__IntegratorQueueCounter();
+
+ if (IntegratorQueueCounter *queue_counter = (IntegratorQueueCounter *)
+ it.first->host_pointer) {
+ for (int i = 0; i < DEVICE_KERNEL_INTEGRATOR_NUM; i++)
+ printf("%s%d", i == 0 ? "" : ",", int(queue_counter->num_queued[i]));
+ }
+ break;
+ }
+ }
+ printf("]\n");
+ }
+ }
+
+ return !(metal_device_->have_error());
}
bool MetalDeviceQueue::synchronize()
{
- if (metal_device->have_error()) {
+ if (has_captured_to_disk_ || metal_device_->have_error()) {
return false;
}
- if (mtlComputeEncoder) {
+ if (mtlComputeEncoder_) {
close_compute_encoder();
}
close_blit_encoder();
- if (mtlCommandBuffer) {
- uint64_t shared_event_id = this->shared_event_id++;
+ if (mtlCommandBuffer_) {
+ scoped_timer timer;
if (@available(macos 10.14, *)) {
- __block dispatch_semaphore_t block_sema = wait_semaphore;
- [shared_event notifyListener:shared_event_listener
- atValue:shared_event_id
- block:^(id<MTLSharedEvent> sharedEvent, uint64_t value) {
- dispatch_semaphore_signal(block_sema);
- }];
+ if (timing_shared_event_) {
+ /* For per-kernel timing, add event handlers to measure & accumulate dispatch times. */
+ __block double completion_time = 0;
+ for (uint64_t i = command_buffer_start_timing_id_; i < timing_shared_event_id_; i++) {
+ [timing_shared_event_ notifyListener:shared_event_listener_
+ atValue:i
+ block:^(id<MTLSharedEvent> sharedEvent, uint64_t value) {
+ completion_time = timer.get_time() - completion_time;
+ last_completion_time_ = completion_time;
+ for (auto label : command_encoder_labels_) {
+ if (label.timing_id == value) {
+ TimingStats &stat = timing_stats_[label.kernel];
+ stat.num_dispatches++;
+ stat.total_time += completion_time;
+ stat.total_work_size += label.work_size;
+ }
+ }
+ }];
+ }
+ }
+ }
+
+ uint64_t shared_event_id_ = this->shared_event_id_++;
- [mtlCommandBuffer encodeSignalEvent:shared_event value:shared_event_id];
- [mtlCommandBuffer commit];
- dispatch_semaphore_wait(wait_semaphore, DISPATCH_TIME_FOREVER);
+ if (@available(macos 10.14, *)) {
+ __block dispatch_semaphore_t block_sema = wait_semaphore_;
+ [shared_event_ notifyListener:shared_event_listener_
+ atValue:shared_event_id_
+ block:^(id<MTLSharedEvent> sharedEvent, uint64_t value) {
+ dispatch_semaphore_signal(block_sema);
+ }];
+
+ [mtlCommandBuffer_ encodeSignalEvent:shared_event_ value:shared_event_id_];
+ [mtlCommandBuffer_ commit];
+ dispatch_semaphore_wait(wait_semaphore_, DISPATCH_TIME_FOREVER);
}
- [mtlCommandBuffer release];
+ [mtlCommandBuffer_ release];
- for (const CopyBack &mmem : copy_back_mem) {
+ for (const CopyBack &mmem : copy_back_mem_) {
memcpy((uchar *)mmem.host_pointer, (uchar *)mmem.gpu_mem, mmem.size);
}
- copy_back_mem.clear();
+ copy_back_mem_.clear();
- temp_buffer_pool.process_command_buffer_completion(mtlCommandBuffer);
- metal_device->flush_delayed_free_list();
+ temp_buffer_pool_.process_command_buffer_completion(mtlCommandBuffer_);
+ metal_device_->flush_delayed_free_list();
- mtlCommandBuffer = nil;
+ mtlCommandBuffer_ = nil;
+ command_encoder_labels_.clear();
}
- return !(metal_device->have_error());
+ return !(metal_device_->have_error());
}
void MetalDeviceQueue::zero_to_device(device_memory &mem)
@@ -400,20 +692,20 @@ void MetalDeviceQueue::zero_to_device(device_memory &mem)
/* Allocate on demand. */
if (mem.device_pointer == 0) {
- metal_device->mem_alloc(mem);
+ metal_device_->mem_alloc(mem);
}
/* Zero memory on device. */
assert(mem.device_pointer != 0);
- std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
- MetalDevice::MetalMem &mmem = *metal_device->metal_mem_map.at(&mem);
+ std::lock_guard<std::recursive_mutex> lock(metal_device_->metal_mem_map_mutex);
+ MetalDevice::MetalMem &mmem = *metal_device_->metal_mem_map.at(&mem);
if (mmem.mtlBuffer) {
id<MTLBlitCommandEncoder> blitEncoder = get_blit_encoder();
[blitEncoder fillBuffer:mmem.mtlBuffer range:NSMakeRange(mmem.offset, mmem.size) value:0];
}
else {
- metal_device->mem_zero(mem);
+ metal_device_->mem_zero(mem);
}
}
@@ -425,15 +717,15 @@ void MetalDeviceQueue::copy_to_device(device_memory &mem)
/* Allocate on demand. */
if (mem.device_pointer == 0) {
- metal_device->mem_alloc(mem);
+ metal_device_->mem_alloc(mem);
}
assert(mem.device_pointer != 0);
assert(mem.host_pointer != nullptr);
- std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
- auto result = metal_device->metal_mem_map.find(&mem);
- if (result != metal_device->metal_mem_map.end()) {
+ std::lock_guard<std::recursive_mutex> lock(metal_device_->metal_mem_map_mutex);
+ auto result = metal_device_->metal_mem_map.find(&mem);
+ if (result != metal_device_->metal_mem_map.end()) {
if (mem.host_pointer == mem.shared_pointer) {
return;
}
@@ -441,12 +733,12 @@ void MetalDeviceQueue::copy_to_device(device_memory &mem)
MetalDevice::MetalMem &mmem = *result->second;
id<MTLBlitCommandEncoder> blitEncoder = get_blit_encoder();
- id<MTLBuffer> buffer = temp_buffer_pool.get_buffer(mtlDevice,
- mtlCommandBuffer,
- mmem.size,
- MTLResourceStorageModeShared,
- mem.host_pointer,
- stats);
+ id<MTLBuffer> buffer = temp_buffer_pool_.get_buffer(mtlDevice_,
+ mtlCommandBuffer_,
+ mmem.size,
+ MTLResourceStorageModeShared,
+ mem.host_pointer,
+ stats_);
[blitEncoder copyFromBuffer:buffer
sourceOffset:0
@@ -455,7 +747,7 @@ void MetalDeviceQueue::copy_to_device(device_memory &mem)
size:mmem.size];
}
else {
- metal_device->mem_copy_to(mem);
+ metal_device_->mem_copy_to(mem);
}
}
@@ -470,8 +762,8 @@ void MetalDeviceQueue::copy_from_device(device_memory &mem)
assert(mem.device_pointer != 0);
assert(mem.host_pointer != nullptr);
- std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
- MetalDevice::MetalMem &mmem = *metal_device->metal_mem_map.at(&mem);
+ std::lock_guard<std::recursive_mutex> lock(metal_device_->metal_mem_map_mutex);
+ MetalDevice::MetalMem &mmem = *metal_device_->metal_mem_map.at(&mem);
if (mmem.mtlBuffer) {
const size_t size = mem.memory_size();
@@ -481,8 +773,8 @@ void MetalDeviceQueue::copy_from_device(device_memory &mem)
[blitEncoder synchronizeResource:mmem.mtlBuffer];
}
if (mem.host_pointer != mmem.hostPtr) {
- if (mtlCommandBuffer) {
- copy_back_mem.push_back({mem.host_pointer, mmem.hostPtr, size});
+ if (mtlCommandBuffer_) {
+ copy_back_mem_.push_back({mem.host_pointer, mmem.hostPtr, size});
}
else {
memcpy((uchar *)mem.host_pointer, (uchar *)mmem.hostPtr, size);
@@ -494,16 +786,16 @@ void MetalDeviceQueue::copy_from_device(device_memory &mem)
}
}
else {
- metal_device->mem_copy_from(mem);
+ metal_device_->mem_copy_from(mem);
}
}
void MetalDeviceQueue::prepare_resources(DeviceKernel kernel)
{
- std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
+ std::lock_guard<std::recursive_mutex> lock(metal_device_->metal_mem_map_mutex);
/* declare resource usage */
- for (auto &it : metal_device->metal_mem_map) {
+ for (auto &it : metal_device_->metal_mem_map) {
device_memory *mem = it.first;
MTLResourceUsage usage = MTLResourceUsageRead;
@@ -513,17 +805,17 @@ void MetalDeviceQueue::prepare_resources(DeviceKernel kernel)
if (it.second->mtlBuffer) {
/* METAL_WIP - use array version (i.e. useResources) */
- [mtlComputeEncoder useResource:it.second->mtlBuffer usage:usage];
+ [mtlComputeEncoder_ useResource:it.second->mtlBuffer usage:usage];
}
else if (it.second->mtlTexture) {
/* METAL_WIP - use array version (i.e. useResources) */
- [mtlComputeEncoder useResource:it.second->mtlTexture usage:usage | MTLResourceUsageSample];
+ [mtlComputeEncoder_ useResource:it.second->mtlTexture usage:usage | MTLResourceUsageSample];
}
}
/* ancillaries */
- [mtlComputeEncoder useResource:metal_device->texture_bindings_2d usage:MTLResourceUsageRead];
- [mtlComputeEncoder useResource:metal_device->texture_bindings_3d usage:MTLResourceUsageRead];
+ [mtlComputeEncoder_ useResource:metal_device_->texture_bindings_2d usage:MTLResourceUsageRead];
+ [mtlComputeEncoder_ useResource:metal_device_->texture_bindings_3d usage:MTLResourceUsageRead];
}
id<MTLComputeCommandEncoder> MetalDeviceQueue::get_compute_encoder(DeviceKernel kernel)
@@ -531,67 +823,81 @@ id<MTLComputeCommandEncoder> MetalDeviceQueue::get_compute_encoder(DeviceKernel
bool concurrent = (kernel < DEVICE_KERNEL_INTEGRATOR_NUM);
if (@available(macos 10.14, *)) {
- if (mtlComputeEncoder) {
- if (mtlComputeEncoder.dispatchType == concurrent ? MTLDispatchTypeConcurrent :
- MTLDispatchTypeSerial) {
+ if (timing_shared_event_) {
+ /* Close the current encoder to ensure we're able to capture per-encoder timing data. */
+ if (mtlComputeEncoder_) {
+ close_compute_encoder();
+ }
+ }
+
+ if (mtlComputeEncoder_) {
+ if (mtlComputeEncoder_.dispatchType == concurrent ? MTLDispatchTypeConcurrent :
+ MTLDispatchTypeSerial) {
/* declare usage of MTLBuffers etc */
prepare_resources(kernel);
- return mtlComputeEncoder;
+ return mtlComputeEncoder_;
}
close_compute_encoder();
}
close_blit_encoder();
- if (!mtlCommandBuffer) {
- mtlCommandBuffer = [mtlCommandQueue commandBuffer];
- [mtlCommandBuffer retain];
+ if (!mtlCommandBuffer_) {
+ mtlCommandBuffer_ = [mtlCommandQueue_ commandBuffer];
+ [mtlCommandBuffer_ retain];
}
- mtlComputeEncoder = [mtlCommandBuffer
+ mtlComputeEncoder_ = [mtlCommandBuffer_
computeCommandEncoderWithDispatchType:concurrent ? MTLDispatchTypeConcurrent :
MTLDispatchTypeSerial];
- [mtlComputeEncoder setLabel:@(device_kernel_as_string(kernel))];
+ [mtlComputeEncoder_ setLabel:@(device_kernel_as_string(kernel))];
/* declare usage of MTLBuffers etc */
prepare_resources(kernel);
}
- return mtlComputeEncoder;
+ return mtlComputeEncoder_;
}
id<MTLBlitCommandEncoder> MetalDeviceQueue::get_blit_encoder()
{
- if (mtlBlitEncoder) {
- return mtlBlitEncoder;
+ if (mtlBlitEncoder_) {
+ return mtlBlitEncoder_;
}
- if (mtlComputeEncoder) {
+ if (mtlComputeEncoder_) {
close_compute_encoder();
}
- if (!mtlCommandBuffer) {
- mtlCommandBuffer = [mtlCommandQueue commandBuffer];
- [mtlCommandBuffer retain];
+ if (!mtlCommandBuffer_) {
+ mtlCommandBuffer_ = [mtlCommandQueue_ commandBuffer];
+ [mtlCommandBuffer_ retain];
+ command_buffer_start_timing_id_ = timing_shared_event_id_;
}
- mtlBlitEncoder = [mtlCommandBuffer blitCommandEncoder];
- return mtlBlitEncoder;
+ mtlBlitEncoder_ = [mtlCommandBuffer_ blitCommandEncoder];
+ return mtlBlitEncoder_;
}
void MetalDeviceQueue::close_compute_encoder()
{
- [mtlComputeEncoder endEncoding];
- mtlComputeEncoder = nil;
+ [mtlComputeEncoder_ endEncoding];
+ mtlComputeEncoder_ = nil;
+
+ if (@available(macos 10.14, *)) {
+ if (timing_shared_event_) {
+ [mtlCommandBuffer_ encodeSignalEvent:timing_shared_event_ value:timing_shared_event_id_++];
+ }
+ }
}
void MetalDeviceQueue::close_blit_encoder()
{
- if (mtlBlitEncoder) {
- [mtlBlitEncoder endEncoding];
- mtlBlitEncoder = nil;
+ if (mtlBlitEncoder_) {
+ [mtlBlitEncoder_ endEncoding];
+ mtlBlitEncoder_ = nil;
}
}
diff --git a/intern/cycles/device/metal/util.h b/intern/cycles/device/metal/util.h
index cc653ab7e12..f728967835d 100644
--- a/intern/cycles/device/metal/util.h
+++ b/intern/cycles/device/metal/util.h
@@ -14,6 +14,8 @@
# include "util/thread.h"
+# define metal_printf VLOG(4) << string_printf
+
CCL_NAMESPACE_BEGIN
enum MetalGPUVendor {
diff --git a/intern/cycles/device/optix/device.cpp b/intern/cycles/device/optix/device.cpp
index 70810bae10d..68ca21374fd 100644
--- a/intern/cycles/device/optix/device.cpp
+++ b/intern/cycles/device/optix/device.cpp
@@ -31,12 +31,12 @@ bool device_optix_init()
const OptixResult result = optixInit();
if (result == OPTIX_ERROR_UNSUPPORTED_ABI_VERSION) {
- VLOG(1) << "OptiX initialization failed because the installed NVIDIA driver is too old. "
- "Please update to the latest driver first!";
+ VLOG_WARNING << "OptiX initialization failed because the installed NVIDIA driver is too old. "
+ "Please update to the latest driver first!";
return false;
}
else if (result != OPTIX_SUCCESS) {
- VLOG(1) << "OptiX initialization failed with error code " << (unsigned int)result;
+ VLOG_WARNING << "OptiX initialization failed with error code " << (unsigned int)result;
return false;
}
diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp
index 35717c49d1a..53697db5c04 100644
--- a/intern/cycles/device/optix/device_impl.cpp
+++ b/intern/cycles/device/optix/device_impl.cpp
@@ -278,7 +278,7 @@ OptiXDevice::OptiXDevice(const DeviceInfo &info, Stats &stats, Profiler &profile
};
# endif
if (DebugFlags().optix.use_debug) {
- VLOG(1) << "Using OptiX debug mode.";
+ VLOG_INFO << "Using OptiX debug mode.";
options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL;
}
optix_assert(optixDeviceContextCreate(cuContext, &options, &context));
@@ -553,7 +553,8 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
OptixBuiltinISOptions builtin_options = {};
# if OPTIX_ABI_VERSION >= 55
builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM;
- builtin_options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE;
+ builtin_options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE |
+ OPTIX_BUILD_FLAG_ALLOW_COMPACTION;
builtin_options.curveEndcapFlags = OPTIX_CURVE_ENDCAP_DEFAULT; /* Disable end-caps. */
# else
builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE;
@@ -1387,12 +1388,15 @@ bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh,
OptixAccelBufferSizes sizes = {};
OptixAccelBuildOptions options = {};
options.operation = operation;
- if (use_fast_trace_bvh) {
- VLOG(2) << "Using fast to trace OptiX BVH";
+ if (use_fast_trace_bvh ||
+ /* The build flags have to match the ones used to query the built-in curve intersection
+ program (see optixBuiltinISModuleGet above) */
+ build_input.type == OPTIX_BUILD_INPUT_TYPE_CURVES) {
+ VLOG_INFO << "Using fast to trace OptiX BVH";
options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE | OPTIX_BUILD_FLAG_ALLOW_COMPACTION;
}
else {
- VLOG(2) << "Using fast to update OptiX BVH";
+ VLOG_INFO << "Using fast to update OptiX BVH";
options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_BUILD | OPTIX_BUILD_FLAG_ALLOW_UPDATE;
}
diff --git a/intern/cycles/device/queue.cpp b/intern/cycles/device/queue.cpp
index de65047ed6a..cc0cf0ccf84 100644
--- a/intern/cycles/device/queue.cpp
+++ b/intern/cycles/device/queue.cpp
@@ -19,7 +19,7 @@ DeviceQueue::DeviceQueue(Device *device)
DeviceQueue::~DeviceQueue()
{
- if (VLOG_IS_ON(3)) {
+ if (VLOG_DEVICE_STATS_IS_ON) {
/* Print kernel execution times sorted by time. */
vector<pair<DeviceKernelMask, double>> stats_sorted;
for (const auto &stat : stats_kernel_time_) {
@@ -32,17 +32,18 @@ DeviceQueue::~DeviceQueue()
return a.second > b.second;
});
- VLOG(3) << "GPU queue stats:";
+ VLOG_DEVICE_STATS << "GPU queue stats:";
for (const auto &[mask, time] : stats_sorted) {
- VLOG(3) << " " << std::setfill(' ') << std::setw(10) << std::fixed << std::setprecision(5)
- << std::right << time << "s: " << device_kernel_mask_as_string(mask);
+ VLOG_DEVICE_STATS << " " << std::setfill(' ') << std::setw(10) << std::fixed
+ << std::setprecision(5) << std::right << time
+ << "s: " << device_kernel_mask_as_string(mask);
}
}
}
void DeviceQueue::debug_init_execution()
{
- if (VLOG_IS_ON(3)) {
+ if (VLOG_DEVICE_STATS_IS_ON) {
last_sync_time_ = time_dt();
}
@@ -51,9 +52,9 @@ void DeviceQueue::debug_init_execution()
void DeviceQueue::debug_enqueue(DeviceKernel kernel, const int work_size)
{
- if (VLOG_IS_ON(3)) {
- VLOG(4) << "GPU queue launch " << device_kernel_as_string(kernel) << ", work_size "
- << work_size;
+ if (VLOG_DEVICE_STATS_IS_ON) {
+ VLOG_DEVICE_STATS << "GPU queue launch " << device_kernel_as_string(kernel) << ", work_size "
+ << work_size;
}
last_kernels_enqueued_ |= (uint64_t(1) << (uint64_t)kernel);
@@ -61,10 +62,10 @@ void DeviceQueue::debug_enqueue(DeviceKernel kernel, const int work_size)
void DeviceQueue::debug_synchronize()
{
- if (VLOG_IS_ON(3)) {
+ if (VLOG_DEVICE_STATS_IS_ON) {
const double new_time = time_dt();
const double elapsed_time = new_time - last_sync_time_;
- VLOG(4) << "GPU queue synchronize, elapsed " << std::setw(10) << elapsed_time << "s";
+ VLOG_DEVICE_STATS << "GPU queue synchronize, elapsed " << std::setw(10) << elapsed_time << "s";
stats_kernel_time_[last_kernels_enqueued_] += elapsed_time;
diff --git a/intern/cycles/hydra/display_driver.cpp b/intern/cycles/hydra/display_driver.cpp
index a809ace63e2..0c0b577c358 100644
--- a/intern/cycles/hydra/display_driver.cpp
+++ b/intern/cycles/hydra/display_driver.cpp
@@ -23,10 +23,18 @@ HdCyclesDisplayDriver::HdCyclesDisplayDriver(HdCyclesSession *renderParam, Hgi *
HdCyclesDisplayDriver::~HdCyclesDisplayDriver()
{
- deinit();
+ if (texture_) {
+ _hgi->DestroyTexture(&texture_);
+ }
+
+ if (gl_pbo_id_) {
+ glDeleteBuffers(1, &gl_pbo_id_);
+ }
+
+ gl_context_dispose();
}
-void HdCyclesDisplayDriver::init()
+void HdCyclesDisplayDriver::gl_context_create()
{
#ifdef _WIN32
if (!gl_context_) {
@@ -64,16 +72,42 @@ void HdCyclesDisplayDriver::init()
}
}
-void HdCyclesDisplayDriver::deinit()
+bool HdCyclesDisplayDriver::gl_context_enable()
{
- if (texture_) {
- _hgi->DestroyTexture(&texture_);
+#ifdef _WIN32
+ if (!hdc_ || !gl_context_) {
+ return false;
}
- if (gl_pbo_id_) {
- glDeleteBuffers(1, &gl_pbo_id_);
+ mutex_.lock();
+
+ // Do not change context if this is called in the main thread
+ if (wglGetCurrentContext() == nullptr) {
+ if (!TF_VERIFY(wglMakeCurrent((HDC)hdc_, (HGLRC)gl_context_))) {
+ mutex_.unlock();
+ return false;
+ }
+ }
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+void HdCyclesDisplayDriver::gl_context_disable()
+{
+#ifdef _WIN32
+ if (wglGetCurrentContext() == gl_context_) {
+ TF_VERIFY(wglMakeCurrent(nullptr, nullptr));
}
+ mutex_.unlock();
+#endif
+}
+
+void HdCyclesDisplayDriver::gl_context_dispose()
+{
#ifdef _WIN32
if (gl_context_) {
TF_VERIFY(wglDeleteContext((HGLRC)gl_context_));
@@ -90,13 +124,9 @@ bool HdCyclesDisplayDriver::update_begin(const Params &params,
int texture_width,
int texture_height)
{
-#ifdef _WIN32
- if (!hdc_ || !gl_context_) {
+ if (!gl_context_enable()) {
return false;
}
-#endif
-
- graphics_interop_activate();
if (gl_render_sync_) {
glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
@@ -121,15 +151,14 @@ bool HdCyclesDisplayDriver::update_begin(const Params &params,
void HdCyclesDisplayDriver::update_end()
{
gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-
glFlush();
- graphics_interop_deactivate();
+ gl_context_disable();
}
void HdCyclesDisplayDriver::flush()
{
- graphics_interop_activate();
+ gl_context_enable();
if (gl_upload_sync_) {
glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
@@ -139,7 +168,7 @@ void HdCyclesDisplayDriver::flush()
glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
}
- graphics_interop_deactivate();
+ gl_context_disable();
}
half4 *HdCyclesDisplayDriver::map_texture_buffer()
@@ -179,25 +208,12 @@ DisplayDriver::GraphicsInterop HdCyclesDisplayDriver::graphics_interop_get()
void HdCyclesDisplayDriver::graphics_interop_activate()
{
- mutex_.lock();
-
-#ifdef _WIN32
- // Do not change context if this is called in the main thread
- if (wglGetCurrentContext() == nullptr) {
- TF_VERIFY(wglMakeCurrent((HDC)hdc_, (HGLRC)gl_context_));
- }
-#endif
+ gl_context_enable();
}
void HdCyclesDisplayDriver::graphics_interop_deactivate()
{
-#ifdef _WIN32
- if (wglGetCurrentContext() == gl_context_) {
- TF_VERIFY(wglMakeCurrent(nullptr, nullptr));
- }
-#endif
-
- mutex_.unlock();
+ gl_context_disable();
}
void HdCyclesDisplayDriver::clear()
@@ -214,7 +230,11 @@ void HdCyclesDisplayDriver::draw(const Params &params)
return;
}
- init();
+ if (!renderBuffer->IsResourceUsed()) {
+ return;
+ }
+
+ gl_context_create();
// Cycles 'DisplayDriver' only supports 'half4' format
TF_VERIFY(renderBuffer->GetFormat() == HdFormatFloat16Vec4);
@@ -255,7 +275,6 @@ void HdCyclesDisplayDriver::draw(const Params &params)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-
glFlush();
need_update_ = false;
diff --git a/intern/cycles/hydra/display_driver.h b/intern/cycles/hydra/display_driver.h
index 20086830e6a..2a05397c325 100644
--- a/intern/cycles/hydra/display_driver.h
+++ b/intern/cycles/hydra/display_driver.h
@@ -19,9 +19,6 @@ class HdCyclesDisplayDriver final : public CCL_NS::DisplayDriver {
~HdCyclesDisplayDriver();
private:
- void init();
- void deinit();
-
void next_tile_begin() override;
bool update_begin(const Params &params, int texture_width, int texture_height) override;
@@ -41,6 +38,11 @@ class HdCyclesDisplayDriver final : public CCL_NS::DisplayDriver {
void draw(const Params &params) override;
+ void gl_context_create();
+ bool gl_context_enable();
+ void gl_context_disable();
+ void gl_context_dispose();
+
HdCyclesSession *const _renderParam;
Hgi *const _hgi;
@@ -48,7 +50,6 @@ class HdCyclesDisplayDriver final : public CCL_NS::DisplayDriver {
void *hdc_ = nullptr;
void *gl_context_ = nullptr;
#endif
-
CCL_NS::thread_mutex mutex_;
PXR_NS::HgiTextureHandle texture_;
diff --git a/intern/cycles/hydra/output_driver.cpp b/intern/cycles/hydra/output_driver.cpp
index c5f64ac1c18..f4ea853f243 100644
--- a/intern/cycles/hydra/output_driver.cpp
+++ b/intern/cycles/hydra/output_driver.cpp
@@ -30,11 +30,11 @@ bool HdCyclesOutputDriver::update_render_tile(const Tile &tile)
std::vector<float> pixels;
for (const HdRenderPassAovBinding &aovBinding : _renderParam->GetAovBindings()) {
- if (aovBinding == _renderParam->GetDisplayAovBinding()) {
- continue; // Display AOV binding is already updated by Cycles display driver
- }
-
if (const auto renderBuffer = static_cast<HdCyclesRenderBuffer *>(aovBinding.renderBuffer)) {
+ if (aovBinding == _renderParam->GetDisplayAovBinding() && renderBuffer->IsResourceUsed()) {
+ continue; // Display AOV binding is already updated by Cycles display driver
+ }
+
const HdFormat format = renderBuffer->GetFormat();
if (format == HdFormatInvalid) {
continue; // Skip invalid AOV bindings
diff --git a/intern/cycles/hydra/render_buffer.cpp b/intern/cycles/hydra/render_buffer.cpp
index 4867def0624..4d8b21d1e61 100644
--- a/intern/cycles/hydra/render_buffer.cpp
+++ b/intern/cycles/hydra/render_buffer.cpp
@@ -35,7 +35,7 @@ bool HdCyclesRenderBuffer::Allocate(const GfVec3i &dimensions, HdFormat format,
return false;
}
- const size_t oldSize = _data.size();
+ const size_t oldSize = _dataSize;
const size_t newSize = dimensions[0] * dimensions[1] * HdDataSizeOfFormat(format);
if (oldSize == newSize) {
return true;
@@ -49,8 +49,8 @@ bool HdCyclesRenderBuffer::Allocate(const GfVec3i &dimensions, HdFormat format,
_width = dimensions[0];
_height = dimensions[1];
_format = format;
-
- _data.resize(newSize);
+ _dataSize = newSize;
+ _resourceUsed = false;
return true;
}
@@ -63,6 +63,7 @@ void HdCyclesRenderBuffer::_Deallocate()
_data.clear();
_data.shrink_to_fit();
+ _dataSize = 0;
_resource = VtValue();
}
@@ -74,6 +75,10 @@ void *HdCyclesRenderBuffer::Map()
return nullptr;
}
+ if (_data.size() != _dataSize) {
+ _data.resize(_dataSize);
+ }
+
++_mapped;
return _data.data();
@@ -103,10 +108,17 @@ void HdCyclesRenderBuffer::SetConverged(bool converged)
_converged = converged;
}
+bool HdCyclesRenderBuffer::IsResourceUsed() const
+{
+ return _resourceUsed;
+}
+
VtValue HdCyclesRenderBuffer::GetResource(bool multiSampled) const
{
TF_UNUSED(multiSampled);
+ _resourceUsed = true;
+
return _resource;
}
diff --git a/intern/cycles/hydra/render_buffer.h b/intern/cycles/hydra/render_buffer.h
index 8eb874f0068..90629d4aee0 100644
--- a/intern/cycles/hydra/render_buffer.h
+++ b/intern/cycles/hydra/render_buffer.h
@@ -58,6 +58,8 @@ class HdCyclesRenderBuffer final : public PXR_NS::HdRenderBuffer {
void SetConverged(bool converged);
+ bool IsResourceUsed() const;
+
PXR_NS::VtValue GetResource(bool multiSampled = false) const override;
void SetResource(const PXR_NS::VtValue &resource);
@@ -74,9 +76,11 @@ class HdCyclesRenderBuffer final : public PXR_NS::HdRenderBuffer {
unsigned int _width = 0u;
unsigned int _height = 0u;
PXR_NS::HdFormat _format = PXR_NS::HdFormatInvalid;
+ size_t _dataSize = 0;
std::vector<uint8_t> _data;
PXR_NS::VtValue _resource;
+ mutable std::atomic_bool _resourceUsed = false;
std::atomic_int _mapped = 0;
std::atomic_bool _converged = false;
diff --git a/intern/cycles/integrator/denoiser.cpp b/intern/cycles/integrator/denoiser.cpp
index 23ab825a4d2..94991d63e4c 100644
--- a/intern/cycles/integrator/denoiser.cpp
+++ b/intern/cycles/integrator/denoiser.cpp
@@ -58,8 +58,8 @@ bool Denoiser::load_kernels(Progress *progress)
return false;
}
- VLOG(3) << "Will denoise on " << denoiser_device->info.description << " ("
- << denoiser_device->info.id << ")";
+ VLOG_WORK << "Will denoise on " << denoiser_device->info.description << " ("
+ << denoiser_device->info.id << ")";
return true;
}
diff --git a/intern/cycles/integrator/denoiser_device.cpp b/intern/cycles/integrator/denoiser_device.cpp
index 595397312b3..5414f9dfb1a 100644
--- a/intern/cycles/integrator/denoiser_device.cpp
+++ b/intern/cycles/integrator/denoiser_device.cpp
@@ -48,7 +48,7 @@ bool DeviceDenoiser::denoise_buffer(const BufferParams &buffer_params,
task.render_buffers = render_buffers;
}
else {
- VLOG(3) << "Creating temporary buffer on denoiser device.";
+ VLOG_WORK << "Creating temporary buffer on denoiser device.";
DeviceQueue *queue = denoiser_device->get_denoise_queue();
diff --git a/intern/cycles/integrator/denoiser_oidn.cpp b/intern/cycles/integrator/denoiser_oidn.cpp
index b074408e229..04e659a15e2 100644
--- a/intern/cycles/integrator/denoiser_oidn.cpp
+++ b/intern/cycles/integrator/denoiser_oidn.cpp
@@ -284,8 +284,8 @@ class OIDNDenoiseContext {
/* Read pass pixels using PassAccessor into a temporary buffer which is owned by the pass.. */
void read_pass_pixels_into_buffer(OIDNPass &oidn_pass)
{
- VLOG(3) << "Allocating temporary buffer for pass " << oidn_pass.name << " ("
- << pass_type_as_string(oidn_pass.type) << ")";
+ VLOG_WORK << "Allocating temporary buffer for pass " << oidn_pass.name << " ("
+ << pass_type_as_string(oidn_pass.type) << ")";
const int64_t width = buffer_params_.width;
const int64_t height = buffer_params_.height;
diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp
index 36a0326e405..9ad1c465725 100644
--- a/intern/cycles/integrator/path_trace.cpp
+++ b/intern/cycles/integrator/path_trace.cpp
@@ -348,8 +348,8 @@ void PathTrace::path_trace(RenderWork &render_work)
return;
}
- VLOG(3) << "Will path trace " << render_work.path_trace.num_samples
- << " samples at the resolution divider " << render_work.resolution_divider;
+ VLOG_WORK << "Will path trace " << render_work.path_trace.num_samples
+ << " samples at the resolution divider " << render_work.resolution_divider;
const double start_time = time_dt();
@@ -373,9 +373,9 @@ void PathTrace::path_trace(RenderWork &render_work)
work_balance_infos_[i].time_spent += work_time;
work_balance_infos_[i].occupancy = statistics.occupancy;
- VLOG(3) << "Rendered " << num_samples << " samples in " << work_time << " seconds ("
- << work_time / num_samples
- << " seconds per sample), occupancy: " << statistics.occupancy;
+ VLOG_WORK << "Rendered " << num_samples << " samples in " << work_time << " seconds ("
+ << work_time / num_samples
+ << " seconds per sample), occupancy: " << statistics.occupancy;
});
float occupancy_accum = 0.0f;
@@ -398,10 +398,10 @@ void PathTrace::adaptive_sample(RenderWork &render_work)
bool did_reschedule_on_idle = false;
while (true) {
- VLOG(3) << "Will filter adaptive stopping buffer, threshold "
- << render_work.adaptive_sampling.threshold;
+ VLOG_WORK << "Will filter adaptive stopping buffer, threshold "
+ << render_work.adaptive_sampling.threshold;
if (render_work.adaptive_sampling.reset) {
- VLOG(3) << "Will re-calculate convergency flag for currently converged pixels.";
+ VLOG_WORK << "Will re-calculate convergency flag for currently converged pixels.";
}
const double start_time = time_dt();
@@ -420,11 +420,11 @@ void PathTrace::adaptive_sample(RenderWork &render_work)
render_work, time_dt() - start_time, is_cancel_requested());
if (num_active_pixels == 0) {
- VLOG(3) << "All pixels converged.";
+ VLOG_WORK << "All pixels converged.";
if (!render_scheduler_.render_work_reschedule_on_converge(render_work)) {
break;
}
- VLOG(3) << "Continuing with lower threshold.";
+ VLOG_WORK << "Continuing with lower threshold.";
}
else if (did_reschedule_on_idle) {
break;
@@ -436,10 +436,10 @@ void PathTrace::adaptive_sample(RenderWork &render_work)
* A better heuristic is possible here: for example, use maximum of 128^2 and percentage of
* the final resolution. */
if (!render_scheduler_.render_work_reschedule_on_idle(render_work)) {
- VLOG(3) << "Rescheduling is not possible: final threshold is reached.";
+ VLOG_WORK << "Rescheduling is not possible: final threshold is reached.";
break;
}
- VLOG(3) << "Rescheduling lower threshold.";
+ VLOG_WORK << "Rescheduling lower threshold.";
did_reschedule_on_idle = true;
}
else {
@@ -483,7 +483,7 @@ void PathTrace::cryptomatte_postprocess(const RenderWork &render_work)
if (!render_work.cryptomatte.postprocess) {
return;
}
- VLOG(3) << "Perform cryptomatte work.";
+ VLOG_WORK << "Perform cryptomatte work.";
parallel_for_each(path_trace_works_, [&](unique_ptr<PathTraceWork> &path_trace_work) {
path_trace_work->cryptomatte_postproces();
@@ -501,7 +501,7 @@ void PathTrace::denoise(const RenderWork &render_work)
return;
}
- VLOG(3) << "Perform denoising work.";
+ VLOG_WORK << "Perform denoising work.";
const double start_time = time_dt();
@@ -599,26 +599,26 @@ void PathTrace::update_display(const RenderWork &render_work)
}
if (!display_ && !output_driver_) {
- VLOG(3) << "Ignore display update.";
+ VLOG_WORK << "Ignore display update.";
return;
}
if (full_params_.width == 0 || full_params_.height == 0) {
- VLOG(3) << "Skipping PathTraceDisplay update due to 0 size of the render buffer.";
+ VLOG_WORK << "Skipping PathTraceDisplay update due to 0 size of the render buffer.";
return;
}
const double start_time = time_dt();
if (output_driver_) {
- VLOG(3) << "Invoke buffer update callback.";
+ VLOG_WORK << "Invoke buffer update callback.";
PathTraceTile tile(*this);
output_driver_->update_render_tile(tile);
}
if (display_) {
- VLOG(3) << "Perform copy to GPUDisplay work.";
+ VLOG_WORK << "Perform copy to GPUDisplay work.";
const int texture_width = render_state_.effective_big_tile_params.window_width;
const int texture_height = render_state_.effective_big_tile_params.window_height;
@@ -654,33 +654,33 @@ void PathTrace::rebalance(const RenderWork &render_work)
const int num_works = path_trace_works_.size();
if (num_works == 1) {
- VLOG(3) << "Ignoring rebalance work due to single device render.";
+ VLOG_WORK << "Ignoring rebalance work due to single device render.";
return;
}
const double start_time = time_dt();
if (VLOG_IS_ON(3)) {
- VLOG(3) << "Perform rebalance work.";
- VLOG(3) << "Per-device path tracing time (seconds):";
+ VLOG_WORK << "Perform rebalance work.";
+ VLOG_WORK << "Per-device path tracing time (seconds):";
for (int i = 0; i < num_works; ++i) {
- VLOG(3) << path_trace_works_[i]->get_device()->info.description << ": "
- << work_balance_infos_[i].time_spent;
+ VLOG_WORK << path_trace_works_[i]->get_device()->info.description << ": "
+ << work_balance_infos_[i].time_spent;
}
}
const bool did_rebalance = work_balance_do_rebalance(work_balance_infos_);
if (VLOG_IS_ON(3)) {
- VLOG(3) << "Calculated per-device weights for works:";
+ VLOG_WORK << "Calculated per-device weights for works:";
for (int i = 0; i < num_works; ++i) {
- VLOG(3) << path_trace_works_[i]->get_device()->info.description << ": "
- << work_balance_infos_[i].weight;
+ VLOG_WORK << path_trace_works_[i]->get_device()->info.description << ": "
+ << work_balance_infos_[i].weight;
}
}
if (!did_rebalance) {
- VLOG(3) << "Balance in path trace works did not change.";
+ VLOG_WORK << "Balance in path trace works did not change.";
render_scheduler_.report_rebalance_time(render_work, time_dt() - start_time, false);
return;
}
@@ -704,7 +704,7 @@ void PathTrace::write_tile_buffer(const RenderWork &render_work)
return;
}
- VLOG(3) << "Write tile result.";
+ VLOG_WORK << "Write tile result.";
render_state_.tile_written = true;
@@ -718,14 +718,14 @@ void PathTrace::write_tile_buffer(const RenderWork &render_work)
*
* Important thing is: tile should be written to the software via callback only once. */
if (!has_multiple_tiles) {
- VLOG(3) << "Write tile result via buffer write callback.";
+ VLOG_WORK << "Write tile result via buffer write callback.";
tile_buffer_write();
}
/* Write tile to disk, so that the render work's render buffer can be re-used for the next tile.
*/
if (has_multiple_tiles) {
- VLOG(3) << "Write tile result into .";
+ VLOG_WORK << "Write tile result into .";
tile_buffer_write_to_disk();
}
}
@@ -736,10 +736,10 @@ void PathTrace::finalize_full_buffer_on_disk(const RenderWork &render_work)
return;
}
- VLOG(3) << "Handle full-frame render buffer work.";
+ VLOG_WORK << "Handle full-frame render buffer work.";
if (!tile_manager_.has_written_tiles()) {
- VLOG(3) << "No tiles on disk.";
+ VLOG_WORK << "No tiles on disk.";
return;
}
@@ -935,7 +935,7 @@ static string get_layer_view_name(const RenderBuffers &buffers)
void PathTrace::process_full_buffer_from_disk(string_view filename)
{
- VLOG(3) << "Processing full frame buffer file " << filename;
+ VLOG_WORK << "Processing full frame buffer file " << filename;
progress_set_status("Reading full buffer from disk");
diff --git a/intern/cycles/integrator/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp
index ede81705ae8..0acaeace4b0 100644
--- a/intern/cycles/integrator/path_trace_work_gpu.cpp
+++ b/intern/cycles/integrator/path_trace_work_gpu.cpp
@@ -152,7 +152,7 @@ void PathTraceWorkGPU::alloc_integrator_soa()
total_soa_size += soa_memory->memory_size();
}
- VLOG(3) << "GPU SoA state size: " << string_human_readable_size(total_soa_size);
+ VLOG_DEVICE_STATS << "GPU SoA state size: " << string_human_readable_size(total_soa_size);
}
}
@@ -820,10 +820,10 @@ bool PathTraceWorkGPU::should_use_graphics_interop()
interop_use_ = device->should_use_graphics_interop();
if (interop_use_) {
- VLOG(2) << "Using graphics interop GPU display update.";
+ VLOG_INFO << "Using graphics interop GPU display update.";
}
else {
- VLOG(2) << "Using naive GPU display update.";
+ VLOG_INFO << "Using naive GPU display update.";
}
interop_use_checked_ = true;
diff --git a/intern/cycles/integrator/render_scheduler.cpp b/intern/cycles/integrator/render_scheduler.cpp
index ebc3170393f..e4676bd059c 100644
--- a/intern/cycles/integrator/render_scheduler.cpp
+++ b/intern/cycles/integrator/render_scheduler.cpp
@@ -225,7 +225,7 @@ bool RenderScheduler::render_work_reschedule_on_idle(RenderWork &render_work)
void RenderScheduler::render_work_reschedule_on_cancel(RenderWork &render_work)
{
- VLOG(3) << "Schedule work for cancel.";
+ VLOG_WORK << "Schedule work for cancel.";
/* Un-schedule samples: they will not be rendered and should not be counted. */
state_.num_rendered_samples -= render_work.path_trace.num_samples;
@@ -475,14 +475,14 @@ void RenderScheduler::report_path_trace_time(const RenderWork &render_work,
path_trace_time_.add_average(final_time_approx, render_work.path_trace.num_samples);
- VLOG(4) << "Average path tracing time: " << path_trace_time_.get_average() << " seconds.";
+ VLOG_WORK << "Average path tracing time: " << path_trace_time_.get_average() << " seconds.";
}
void RenderScheduler::report_path_trace_occupancy(const RenderWork &render_work, float occupancy)
{
state_.occupancy_num_samples = render_work.path_trace.num_samples;
state_.occupancy = occupancy;
- VLOG(4) << "Measured path tracing occupancy: " << occupancy;
+ VLOG_WORK << "Measured path tracing occupancy: " << occupancy;
}
void RenderScheduler::report_adaptive_filter_time(const RenderWork &render_work,
@@ -503,8 +503,8 @@ void RenderScheduler::report_adaptive_filter_time(const RenderWork &render_work,
adaptive_filter_time_.add_average(final_time_approx, render_work.path_trace.num_samples);
- VLOG(4) << "Average adaptive sampling filter time: " << adaptive_filter_time_.get_average()
- << " seconds.";
+ VLOG_WORK << "Average adaptive sampling filter time: " << adaptive_filter_time_.get_average()
+ << " seconds.";
}
void RenderScheduler::report_denoise_time(const RenderWork &render_work, double time)
@@ -523,7 +523,7 @@ void RenderScheduler::report_denoise_time(const RenderWork &render_work, double
denoise_time_.add_average(final_time_approx);
- VLOG(4) << "Average denoising time: " << denoise_time_.get_average() << " seconds.";
+ VLOG_WORK << "Average denoising time: " << denoise_time_.get_average() << " seconds.";
}
void RenderScheduler::report_display_update_time(const RenderWork &render_work, double time)
@@ -542,7 +542,8 @@ void RenderScheduler::report_display_update_time(const RenderWork &render_work,
display_update_time_.add_average(final_time_approx);
- VLOG(4) << "Average display update time: " << display_update_time_.get_average() << " seconds.";
+ VLOG_WORK << "Average display update time: " << display_update_time_.get_average()
+ << " seconds.";
/* Move the display update moment further in time, so that logic which checks when last update
* did happen have more reliable point in time (without path tracing and denoising parts of the
@@ -568,7 +569,7 @@ void RenderScheduler::report_rebalance_time(const RenderWork &render_work,
state_.last_rebalance_changed = balance_changed;
- VLOG(4) << "Average rebalance time: " << rebalance_time_.get_average() << " seconds.";
+ VLOG_WORK << "Average rebalance time: " << rebalance_time_.get_average() << " seconds.";
}
string RenderScheduler::full_report() const
@@ -1063,7 +1064,7 @@ void RenderScheduler::update_start_resolution_divider()
/* Resolution divider has never been calculated before: use default resolution, so that we have
* somewhat good initial behavior, giving a chance to collect real numbers. */
start_resolution_divider_ = default_start_resolution_divider_;
- VLOG(3) << "Initial resolution divider is " << start_resolution_divider_;
+ VLOG_WORK << "Initial resolution divider is " << start_resolution_divider_;
return;
}
@@ -1092,7 +1093,7 @@ void RenderScheduler::update_start_resolution_divider()
* simple and compute device is fast). */
start_resolution_divider_ = max(resolution_divider_for_update, pixel_size_);
- VLOG(3) << "Calculated resolution divider is " << start_resolution_divider_;
+ VLOG_WORK << "Calculated resolution divider is " << start_resolution_divider_;
}
double RenderScheduler::guess_viewport_navigation_update_interval_in_seconds() const
diff --git a/intern/cycles/integrator/shader_eval.cpp b/intern/cycles/integrator/shader_eval.cpp
index 92b9d1c662d..b1450732f5c 100644
--- a/intern/cycles/integrator/shader_eval.cpp
+++ b/intern/cycles/integrator/shader_eval.cpp
@@ -31,8 +31,8 @@ bool ShaderEval::eval(const ShaderEvalType type,
device_->foreach_device([&](Device *device) {
if (!first_device) {
- LOG(ERROR) << "Multi-devices are not yet fully implemented, will evaluate shader on a "
- "single device.";
+ VLOG_WORK << "Multi-devices are not yet fully implemented, will evaluate shader on a "
+ "single device.";
return;
}
first_device = false;
diff --git a/intern/cycles/integrator/work_tile_scheduler.cpp b/intern/cycles/integrator/work_tile_scheduler.cpp
index 6dc511064c9..4bc8c0c4396 100644
--- a/intern/cycles/integrator/work_tile_scheduler.cpp
+++ b/intern/cycles/integrator/work_tile_scheduler.cpp
@@ -55,7 +55,7 @@ void WorkTileScheduler::reset_scheduler_state()
tile_size_ = tile_calculate_best_size(
accelerated_rt_, image_size_px_, samples_num_, max_num_path_states_, scrambling_distance_);
- VLOG(3) << "Will schedule tiles of size " << tile_size_;
+ VLOG_WORK << "Will schedule tiles of size " << tile_size_;
if (VLOG_IS_ON(3)) {
/* The logging is based on multiple tiles scheduled, ignoring overhead of multi-tile scheduling
@@ -63,8 +63,8 @@ void WorkTileScheduler::reset_scheduler_state()
const int num_path_states_in_tile = tile_size_.width * tile_size_.height *
tile_size_.num_samples;
const int num_tiles = max_num_path_states_ / num_path_states_in_tile;
- VLOG(3) << "Number of unused path states: "
- << max_num_path_states_ - num_tiles * num_path_states_in_tile;
+ VLOG_WORK << "Number of unused path states: "
+ << max_num_path_states_ - num_tiles * num_path_states_in_tile;
}
num_tiles_x_ = divide_up(image_size_px_.x, tile_size_.width);
diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h
index 71045157372..d53198f97a3 100644
--- a/intern/cycles/kernel/bvh/util.h
+++ b/intern/cycles/kernel/bvh/util.h
@@ -111,16 +111,16 @@ ccl_device_inline int intersection_find_attribute(KernelGlobals kg,
const uint id)
{
uint attr_offset = kernel_tex_fetch(__objects, object).attribute_map_offset;
- uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+ AttributeMap attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
- while (attr_map.x != id) {
- if (UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
- if (UNLIKELY(attr_map.y == 0)) {
+ while (attr_map.id != id) {
+ if (UNLIKELY(attr_map.id == ATTR_STD_NONE)) {
+ if (UNLIKELY(attr_map.element == 0)) {
return (int)ATTR_STD_NOT_FOUND;
}
else {
/* Chain jump to a different part of the table. */
- attr_offset = attr_map.z;
+ attr_offset = attr_map.offset;
}
}
else {
@@ -130,7 +130,7 @@ ccl_device_inline int intersection_find_attribute(KernelGlobals kg,
}
/* return result */
- return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
+ return (attr_map.element == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.offset;
}
/* Transparent Shadows */
diff --git a/intern/cycles/kernel/device/gpu/kernel.h b/intern/cycles/kernel/device/gpu/kernel.h
index 6405e365847..d657571a5fa 100644
--- a/intern/cycles/kernel/device/gpu/kernel.h
+++ b/intern/cycles/kernel/device/gpu/kernel.h
@@ -241,7 +241,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
}
ccl_gpu_kernel_postfix
-#ifdef __KERNEL_METAL__
+#if defined(__KERNEL_METAL_APPLE__) && defined(__METALRT__)
constant int __dummy_constant [[function_constant(0)]];
#endif
@@ -256,7 +256,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
-#ifdef __KERNEL_METAL__
+#if defined(__KERNEL_METAL_APPLE__) && defined(__METALRT__)
KernelGlobals kg = NULL;
/* Workaround Ambient Occlusion and Bevel nodes not working with Metal.
* Dummy offset should not affect result, but somehow fixes bug! */
diff --git a/intern/cycles/kernel/geom/attribute.h b/intern/cycles/kernel/geom/attribute.h
index da620f69e2d..774b25a76ff 100644
--- a/intern/cycles/kernel/geom/attribute.h
+++ b/intern/cycles/kernel/geom/attribute.h
@@ -56,16 +56,16 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
/* for SVM, find attribute by unique id */
uint attr_offset = object_attribute_map_offset(kg, sd->object);
attr_offset += attribute_primitive_type(kg, sd);
- uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+ AttributeMap attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
- while (attr_map.x != id) {
- if (UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
- if (UNLIKELY(attr_map.y == 0)) {
+ while (attr_map.id != id) {
+ if (UNLIKELY(attr_map.id == ATTR_STD_NONE)) {
+ if (UNLIKELY(attr_map.element == 0)) {
return attribute_not_found();
}
else {
/* Chain jump to a different part of the table. */
- attr_offset = attr_map.z;
+ attr_offset = attr_map.offset;
}
}
else {
@@ -75,7 +75,7 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
}
AttributeDescriptor desc;
- desc.element = (AttributeElement)attr_map.y;
+ desc.element = (AttributeElement)attr_map.element;
if (sd->prim == PRIM_NONE && desc.element != ATTR_ELEMENT_MESH &&
desc.element != ATTR_ELEMENT_VOXEL && desc.element != ATTR_ELEMENT_OBJECT) {
@@ -83,9 +83,10 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
}
/* return result */
- desc.offset = (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
- desc.type = (NodeAttributeType)(attr_map.w & 0xff);
- desc.flags = (AttributeFlag)(attr_map.w >> 8);
+ desc.offset = (attr_map.element == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND :
+ (int)attr_map.offset;
+ desc.type = (NodeAttributeType)attr_map.type;
+ desc.flags = (AttributeFlag)attr_map.flags;
return desc;
}
diff --git a/intern/cycles/kernel/integrator/shade_background.h b/intern/cycles/kernel/integrator/shade_background.h
index 62b3ce1c15c..72ecf67e8a0 100644
--- a/intern/cycles/kernel/integrator/shade_background.h
+++ b/intern/cycles/kernel/integrator/shade_background.h
@@ -48,7 +48,7 @@ ccl_device float3 integrator_eval_background_shader(KernelGlobals kg,
PROFILING_SHADER(emission_sd->object, emission_sd->shader);
PROFILING_EVENT(PROFILING_SHADE_LIGHT_EVAL);
- shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT>(
+ shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_BACKGROUND>(
kg, state, emission_sd, render_buffer, path_flag | PATH_RAY_EMISSION);
L = shader_background_eval(emission_sd);
diff --git a/intern/cycles/kernel/osl/services.cpp b/intern/cycles/kernel/osl/services.cpp
index e2e10b5b83f..6e75ae54f33 100644
--- a/intern/cycles/kernel/osl/services.cpp
+++ b/intern/cycles/kernel/osl/services.cpp
@@ -132,7 +132,7 @@ OSLRenderServices::OSLRenderServices(OSL::TextureSystem *texture_system)
OSLRenderServices::~OSLRenderServices()
{
if (texture_system) {
- VLOG(2) << "OSL texture system stats:\n" << texture_system->getstats();
+ VLOG_INFO << "OSL texture system stats:\n" << texture_system->getstats();
}
}
diff --git a/intern/cycles/kernel/textures.h b/intern/cycles/kernel/textures.h
index 7deb589a0a9..d8ac9cbe51f 100644
--- a/intern/cycles/kernel/textures.h
+++ b/intern/cycles/kernel/textures.h
@@ -47,7 +47,7 @@ KERNEL_TEX(float4, __points)
KERNEL_TEX(uint, __points_shader)
/* attributes */
-KERNEL_TEX(uint4, __attributes_map)
+KERNEL_TEX(AttributeMap, __attributes_map)
KERNEL_TEX(float, __attributes_float)
KERNEL_TEX(float2, __attributes_float2)
KERNEL_TEX(packed_float3, __attributes_float3)
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 80eccd6d41f..ad022716207 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -670,6 +670,16 @@ typedef struct AttributeDescriptor {
int offset;
} AttributeDescriptor;
+/* For looking up attributes on objects and geometry. */
+typedef struct AttributeMap {
+ uint id; /* Global unique identifier. */
+ uint element; /* AttributeElement. */
+ int offset; /* Offset into __attributes global arrays. */
+ uint8_t type; /* NodeAttributeType. */
+ uint8_t flags; /* AttributeFlag. */
+ uint8_t pad[2];
+} AttributeMap;
+
/* Closure data */
#ifndef __MAX_CLOSURE__
@@ -1700,6 +1710,8 @@ enum KernelFeatureFlag : uint32_t {
#define KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT \
(KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VORONOI_EXTRA | \
KERNEL_FEATURE_NODE_LIGHT_PATH)
+#define KERNEL_FEATURE_NODE_MASK_SURFACE_BACKGROUND \
+ (KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT | KERNEL_FEATURE_NODE_AOV)
#define KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW \
(KERNEL_FEATURE_NODE_BSDF | KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VOLUME | \
KERNEL_FEATURE_NODE_BUMP | KERNEL_FEATURE_NODE_BUMP_STATE | \
diff --git a/intern/cycles/scene/alembic.cpp b/intern/cycles/scene/alembic.cpp
index c1e2d306fcc..e6f39bf8625 100644
--- a/intern/cycles/scene/alembic.cpp
+++ b/intern/cycles/scene/alembic.cpp
@@ -1514,7 +1514,7 @@ void AlembicProcedural::build_caches(Progress &progress)
}
}
- VLOG(1) << "AlembicProcedural memory usage : " << string_human_readable_size(memory_used);
+ VLOG_WORK << "AlembicProcedural memory usage : " << string_human_readable_size(memory_used);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/attribute.cpp b/intern/cycles/scene/attribute.cpp
index df01189a54b..d6b4c0240f6 100644
--- a/intern/cycles/scene/attribute.cpp
+++ b/intern/cycles/scene/attribute.cpp
@@ -661,6 +661,26 @@ Attribute *AttributeSet::find(AttributeStandard std) const
return NULL;
}
+Attribute *AttributeSet::find_matching(const Attribute &other)
+{
+ for (Attribute &attr : attributes) {
+ if (attr.name != other.name) {
+ continue;
+ }
+ if (attr.std != other.std) {
+ continue;
+ }
+ if (attr.type != other.type) {
+ continue;
+ }
+ if (attr.element != other.element) {
+ continue;
+ }
+ return &attr;
+ }
+ return nullptr;
+}
+
void AttributeSet::remove(AttributeStandard std)
{
Attribute *attr = find(std);
@@ -729,32 +749,24 @@ void AttributeSet::clear(bool preserve_voxel_data)
void AttributeSet::update(AttributeSet &&new_attributes)
{
- /* add or update old_attributes based on the new_attributes */
- foreach (Attribute &attr, new_attributes.attributes) {
- Attribute *nattr = add(attr.name, attr.type, attr.element);
- nattr->std = attr.std;
- nattr->set_data_from(std::move(attr));
- }
-
- /* remove any attributes not on new_attributes */
+ /* Remove any attributes not on new_attributes. */
list<Attribute>::iterator it;
for (it = attributes.begin(); it != attributes.end();) {
- if (it->std != ATTR_STD_NONE) {
- if (new_attributes.find(it->std) == nullptr) {
- remove(it++);
- continue;
- }
- }
- else if (it->name != "") {
- if (new_attributes.find(it->name) == nullptr) {
- remove(it++);
- continue;
- }
+ const Attribute &old_attr = *it;
+ if (new_attributes.find_matching(old_attr) == nullptr) {
+ remove(it++);
+ continue;
}
-
it++;
}
+ /* Add or update old_attributes based on the new_attributes. */
+ foreach (Attribute &attr, new_attributes.attributes) {
+ Attribute *nattr = add(attr.name, attr.type, attr.element);
+ nattr->std = attr.std;
+ nattr->set_data_from(std::move(attr));
+ }
+
/* If all attributes were replaced, transform is no longer applied. */
geometry->transform_applied = false;
}
diff --git a/intern/cycles/scene/attribute.h b/intern/cycles/scene/attribute.h
index fd13b8ff6de..7f8cbf32049 100644
--- a/intern/cycles/scene/attribute.h
+++ b/intern/cycles/scene/attribute.h
@@ -194,6 +194,7 @@ class AttributeSet {
void remove(AttributeStandard std);
Attribute *find(AttributeRequest &req);
+ Attribute *find_matching(const Attribute &other);
void remove(Attribute *attribute);
diff --git a/intern/cycles/scene/camera.cpp b/intern/cycles/scene/camera.cpp
index 710f1c5ee90..eec269ab542 100644
--- a/intern/cycles/scene/camera.cpp
+++ b/intern/cycles/scene/camera.cpp
@@ -530,7 +530,7 @@ void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scen
if (object->get_geometry()->has_volume &&
viewplane_boundbox.intersects(object->bounds)) {
/* TODO(sergey): Consider adding more grained check. */
- VLOG(1) << "Detected camera inside volume.";
+ VLOG_INFO << "Detected camera inside volume.";
kcam->is_inside_volume = 1;
parallel_for_cancel();
break;
@@ -539,7 +539,7 @@ void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scen
});
if (!kcam->is_inside_volume) {
- VLOG(1) << "Camera is outside of the volume.";
+ VLOG_INFO << "Camera is outside of the volume.";
}
}
diff --git a/intern/cycles/scene/colorspace.cpp b/intern/cycles/scene/colorspace.cpp
index f87b4c62ab2..189e3bc752d 100644
--- a/intern/cycles/scene/colorspace.cpp
+++ b/intern/cycles/scene/colorspace.cpp
@@ -55,8 +55,8 @@ ColorSpaceProcessor *ColorSpaceManager::get_processor(ustring colorspace)
}
catch (OCIO::Exception &exception) {
cached_processors[colorspace] = OCIO::ConstProcessorRcPtr();
- VLOG(1) << "Colorspace " << colorspace.c_str()
- << " can't be converted to scene_linear: " << exception.what();
+ VLOG_WARNING << "Colorspace " << colorspace.c_str()
+ << " can't be converted to scene_linear: " << exception.what();
}
}
@@ -132,12 +132,12 @@ ustring ColorSpaceManager::detect_known_colorspace(ustring colorspace,
thread_scoped_lock cache_lock(cache_colorspaces_mutex);
if (is_scene_linear) {
- VLOG(1) << "Colorspace " << colorspace.string() << " is no-op";
+ VLOG_INFO << "Colorspace " << colorspace.string() << " is no-op";
cached_colorspaces[colorspace] = u_colorspace_raw;
return u_colorspace_raw;
}
else if (is_srgb) {
- VLOG(1) << "Colorspace " << colorspace.string() << " is sRGB";
+ VLOG_INFO << "Colorspace " << colorspace.string() << " is sRGB";
cached_colorspaces[colorspace] = u_colorspace_srgb;
return u_colorspace_srgb;
}
@@ -146,22 +146,23 @@ ustring ColorSpaceManager::detect_known_colorspace(ustring colorspace,
if (!get_processor(colorspace)) {
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
if (!config || !config->getColorSpace(colorspace.c_str())) {
- VLOG(1) << "Colorspace " << colorspace.c_str() << " not found, using raw instead";
+ VLOG_WARNING << "Colorspace " << colorspace.c_str() << " not found, using raw instead";
}
else {
- VLOG(1) << "Colorspace " << colorspace.c_str()
- << " can't be converted to scene_linear, using raw instead";
+ VLOG_WARNING << "Colorspace " << colorspace.c_str()
+ << " can't be converted to scene_linear, using raw instead";
}
cached_colorspaces[colorspace] = u_colorspace_raw;
return u_colorspace_raw;
}
/* Convert to/from colorspace with OpenColorIO. */
- VLOG(1) << "Colorspace " << colorspace.string() << " handled through OpenColorIO";
+ VLOG_INFO << "Colorspace " << colorspace.string() << " handled through OpenColorIO";
cached_colorspaces[colorspace] = colorspace;
return colorspace;
#else
- VLOG(1) << "Colorspace " << colorspace.c_str() << " not available, built without OpenColorIO";
+ VLOG_WARNING << "Colorspace " << colorspace.c_str()
+ << " not available, built without OpenColorIO";
return u_colorspace_raw;
#endif
}
diff --git a/intern/cycles/scene/constant_fold.cpp b/intern/cycles/scene/constant_fold.cpp
index 46ffbe9043a..4bce5661f9b 100644
--- a/intern/cycles/scene/constant_fold.cpp
+++ b/intern/cycles/scene/constant_fold.cpp
@@ -30,8 +30,8 @@ bool ConstantFolder::all_inputs_constant() const
void ConstantFolder::make_constant(float value) const
{
- VLOG(3) << "Folding " << node->name << "::" << output->name() << " to constant (" << value
- << ").";
+ VLOG_DEBUG << "Folding " << node->name << "::" << output->name() << " to constant (" << value
+ << ").";
foreach (ShaderInput *sock, output->links) {
sock->set(value);
@@ -43,7 +43,8 @@ void ConstantFolder::make_constant(float value) const
void ConstantFolder::make_constant(float3 value) const
{
- VLOG(3) << "Folding " << node->name << "::" << output->name() << " to constant " << value << ".";
+ VLOG_DEBUG << "Folding " << node->name << "::" << output->name() << " to constant " << value
+ << ".";
foreach (ShaderInput *sock, output->links) {
sock->set(value);
@@ -99,8 +100,8 @@ void ConstantFolder::bypass(ShaderOutput *new_output) const
{
assert(new_output);
- VLOG(3) << "Folding " << node->name << "::" << output->name() << " to socket "
- << new_output->parent->name << "::" << new_output->name() << ".";
+ VLOG_DEBUG << "Folding " << node->name << "::" << output->name() << " to socket "
+ << new_output->parent->name << "::" << new_output->name() << ".";
/* Remove all outgoing links from socket and connect them to new_output instead.
* The graph->relink method affects node inputs, so it's not safe to use in constant
@@ -118,7 +119,7 @@ void ConstantFolder::discard() const
{
assert(output->type() == SocketType::CLOSURE);
- VLOG(3) << "Discarding closure " << node->name << ".";
+ VLOG_DEBUG << "Discarding closure " << node->name << ".";
graph->disconnect(output);
}
diff --git a/intern/cycles/scene/film.cpp b/intern/cycles/scene/film.cpp
index 7f69df7b321..17acb30e9e7 100644
--- a/intern/cycles/scene/film.cpp
+++ b/intern/cycles/scene/film.cpp
@@ -580,10 +580,10 @@ void Film::update_passes(Scene *scene, bool add_sample_count_pass)
tag_modified();
/* Debug logging. */
- if (VLOG_IS_ON(2)) {
- VLOG(2) << "Effective scene passes:";
+ if (VLOG_INFO_IS_ON) {
+ VLOG_INFO << "Effective scene passes:";
for (const Pass *pass : scene->passes) {
- VLOG(2) << "- " << *pass;
+ VLOG_INFO << "- " << *pass;
}
}
}
diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp
index 9152abacbdb..5ad0742b009 100644
--- a/intern/cycles/scene/geometry.cpp
+++ b/intern/cycles/scene/geometry.cpp
@@ -407,43 +407,47 @@ void GeometryManager::update_osl_attributes(Device *device,
/* Generate a normal attribute map entry from an attribute descriptor. */
static void emit_attribute_map_entry(
- uint4 *attr_map, int index, uint id, TypeDesc type, const AttributeDescriptor &desc)
+ AttributeMap *attr_map, int index, uint id, TypeDesc type, const AttributeDescriptor &desc)
{
- attr_map[index].x = id;
- attr_map[index].y = desc.element;
- attr_map[index].z = as_uint(desc.offset);
+ attr_map[index].id = id;
+ attr_map[index].element = desc.element;
+ attr_map[index].offset = as_uint(desc.offset);
if (type == TypeDesc::TypeFloat)
- attr_map[index].w = NODE_ATTR_FLOAT;
+ attr_map[index].type = NODE_ATTR_FLOAT;
else if (type == TypeDesc::TypeMatrix)
- attr_map[index].w = NODE_ATTR_MATRIX;
+ attr_map[index].type = NODE_ATTR_MATRIX;
else if (type == TypeFloat2)
- attr_map[index].w = NODE_ATTR_FLOAT2;
+ attr_map[index].type = NODE_ATTR_FLOAT2;
else if (type == TypeFloat4)
- attr_map[index].w = NODE_ATTR_FLOAT4;
+ attr_map[index].type = NODE_ATTR_FLOAT4;
else if (type == TypeRGBA)
- attr_map[index].w = NODE_ATTR_RGBA;
+ attr_map[index].type = NODE_ATTR_RGBA;
else
- attr_map[index].w = NODE_ATTR_FLOAT3;
+ attr_map[index].type = NODE_ATTR_FLOAT3;
- attr_map[index].w |= desc.flags << 8;
+ attr_map[index].flags = desc.flags;
}
/* Generate an attribute map end marker, optionally including a link to another map.
* Links are used to connect object attribute maps to mesh attribute maps. */
-static void emit_attribute_map_terminator(uint4 *attr_map, int index, bool chain, uint chain_link)
+static void emit_attribute_map_terminator(AttributeMap *attr_map,
+ int index,
+ bool chain,
+ uint chain_link)
{
for (int j = 0; j < ATTR_PRIM_TYPES; j++) {
- attr_map[index + j].x = ATTR_STD_NONE;
- attr_map[index + j].y = chain; /* link is valid flag */
- attr_map[index + j].z = chain ? chain_link + j : 0; /* link to the correct sub-entry */
- attr_map[index + j].w = 0;
+ attr_map[index + j].id = ATTR_STD_NONE;
+ attr_map[index + j].element = chain; /* link is valid flag */
+ attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */
+ attr_map[index + j].type = 0;
+ attr_map[index + j].flags = 0;
}
}
/* Generate all necessary attribute map entries from the attribute request. */
static void emit_attribute_mapping(
- uint4 *attr_map, int index, Scene *scene, AttributeRequest &req, Geometry *geom)
+ AttributeMap *attr_map, int index, Scene *scene, AttributeRequest &req, Geometry *geom)
{
uint id;
@@ -501,8 +505,8 @@ void GeometryManager::update_svm_attributes(Device *,
}
/* create attribute map */
- uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size);
- memset(attr_map, 0, dscene->attributes_map.size() * sizeof(uint));
+ AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size);
+ memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map));
for (size_t i = 0; i < scene->geometry.size(); i++) {
Geometry *geom = scene->geometry[i];
@@ -1288,7 +1292,7 @@ void GeometryManager::device_update_bvh(Device *device,
bparams.bvh_type = scene->params.bvh_type;
bparams.curve_subdivisions = scene->params.curve_subdivisions();
- VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
+ VLOG_INFO << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
const bool can_refit = scene->bvh != nullptr &&
(bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX ||
@@ -1799,7 +1803,7 @@ void GeometryManager::device_update(Device *device,
if (!need_update())
return;
- VLOG(1) << "Total " << scene->geometry.size() << " meshes.";
+ VLOG_INFO << "Total " << scene->geometry.size() << " meshes.";
bool true_displacement_used = false;
bool curve_shadow_transparency_used = false;
@@ -2038,7 +2042,7 @@ void GeometryManager::device_update(Device *device,
TaskPool::Summary summary;
pool.wait_work(&summary);
- VLOG(2) << "Objects BVH build pool statistics:\n" << summary.full_report();
+ VLOG_WORK << "Objects BVH build pool statistics:\n" << summary.full_report();
}
foreach (Shader *shader, scene->shaders) {
diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp
index 2aa9a6bc1a1..f0d57309ffb 100644
--- a/intern/cycles/scene/image.cpp
+++ b/intern/cycles/scene/image.cpp
@@ -272,17 +272,12 @@ void ImageMetaData::detect_colorspace()
compress_as_srgb = true;
}
else {
- /* Always compress non-raw 8bit images as scene linear + sRGB, as a
- * heuristic to keep memory usage the same without too much data loss
- * due to quantization in common cases. */
- compress_as_srgb = (type == IMAGE_DATA_TYPE_BYTE || type == IMAGE_DATA_TYPE_BYTE4);
-
/* If colorspace conversion needed, use half instead of short so we can
* represent HDR values that might result from conversion. */
- if (type == IMAGE_DATA_TYPE_USHORT) {
+ if (type == IMAGE_DATA_TYPE_BYTE || type == IMAGE_DATA_TYPE_USHORT) {
type = IMAGE_DATA_TYPE_HALF;
}
- else if (type == IMAGE_DATA_TYPE_USHORT4) {
+ else if (type == IMAGE_DATA_TYPE_BYTE4 || type == IMAGE_DATA_TYPE_USHORT4) {
type = IMAGE_DATA_TYPE_HALF4;
}
}
@@ -658,8 +653,8 @@ bool ImageManager::file_load_image(Image *img, int texture_limit)
while (max_size * scale_factor > texture_limit) {
scale_factor *= 0.5f;
}
- VLOG(1) << "Scaling image " << img->loader->name() << " by a factor of " << scale_factor
- << ".";
+ VLOG_WORK << "Scaling image " << img->loader->name() << " by a factor of " << scale_factor
+ << ".";
vector<StorageType> scaled_pixels;
size_t scaled_width, scaled_height, scaled_depth;
util_image_resize_pixels(pixels_storage,
diff --git a/intern/cycles/scene/image_oiio.cpp b/intern/cycles/scene/image_oiio.cpp
index 1b7f8f49696..500e53ed763 100644
--- a/intern/cycles/scene/image_oiio.cpp
+++ b/intern/cycles/scene/image_oiio.cpp
@@ -22,11 +22,11 @@ bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures & /*features*/,
{
/* Perform preliminary checks, with meaningful logging. */
if (!path_exists(filepath.string())) {
- VLOG(1) << "File '" << filepath.string() << "' does not exist.";
+ VLOG_WARNING << "File '" << filepath.string() << "' does not exist.";
return false;
}
if (path_is_directory(filepath.string())) {
- VLOG(1) << "File '" << filepath.string() << "' is a directory, can't use as image.";
+ VLOG_WARNING << "File '" << filepath.string() << "' is a directory, can't use as image.";
return false;
}
@@ -94,10 +94,11 @@ bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures & /*features*/,
template<TypeDesc::BASETYPE FileFormat, typename StorageType>
static void oiio_load_pixels(const ImageMetaData &metadata,
const unique_ptr<ImageInput> &in,
+ const bool associate_alpha,
StorageType *pixels)
{
- const int width = metadata.width;
- const int height = metadata.height;
+ const size_t width = metadata.width;
+ const size_t height = metadata.height;
const int depth = metadata.depth;
const int components = metadata.channels;
@@ -105,12 +106,12 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
StorageType *readpixels = pixels;
vector<StorageType> tmppixels;
if (components > 4) {
- tmppixels.resize(((size_t)width) * height * components);
+ tmppixels.resize(width * height * components);
readpixels = &tmppixels[0];
}
if (depth <= 1) {
- size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType);
+ size_t scanlinesize = width * components * sizeof(StorageType);
in->read_image(FileFormat,
(uchar *)readpixels + (height - 1) * scanlinesize,
AutoStride,
@@ -122,7 +123,7 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
}
if (components > 4) {
- size_t dimensions = ((size_t)width) * height;
+ size_t dimensions = width * height;
for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
pixels[i * 4 + 3] = tmppixels[i * components + 3];
pixels[i * 4 + 2] = tmppixels[i * components + 2];
@@ -137,7 +138,7 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
if (cmyk) {
const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
- const size_t num_pixels = ((size_t)width) * height * depth;
+ const size_t num_pixels = width * height * depth;
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
float c = util_image_cast_to_float(pixels[i * 4 + 0]);
float m = util_image_cast_to_float(pixels[i * 4 + 1]);
@@ -149,6 +150,16 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
pixels[i * 4 + 3] = one;
}
}
+
+ if (components == 4 && associate_alpha) {
+ size_t dimensions = width * height;
+ for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
+ const StorageType alpha = pixels[i * 4 + 3];
+ pixels[i * 4 + 0] = util_image_multiply_native(pixels[i * 4 + 0], alpha);
+ pixels[i * 4 + 1] = util_image_multiply_native(pixels[i * 4 + 1], alpha);
+ pixels[i * 4 + 2] = util_image_multiply_native(pixels[i * 4 + 2], alpha);
+ }
+ }
}
bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
@@ -172,30 +183,36 @@ bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
ImageSpec spec = ImageSpec();
ImageSpec config = ImageSpec();
- if (!associate_alpha) {
- config.attribute("oiio:UnassociatedAlpha", 1);
- }
+ /* Load without automatic OIIO alpha conversion, we do it ourselves. OIIO
+ * will associate alpha in the the 8bit buffer for PNGs, which leads to too
+ * much precision loss when we load it as half float to do a colorspace
+ * transform. */
+ config.attribute("oiio:UnassociatedAlpha", 1);
if (!in->open(filepath.string(), spec, config)) {
return false;
}
+ const bool do_associate_alpha = associate_alpha &&
+ spec.get_int_attribute("oiio:UnassociatedAlpha", 0);
+
switch (metadata.type) {
case IMAGE_DATA_TYPE_BYTE:
case IMAGE_DATA_TYPE_BYTE4:
- oiio_load_pixels<TypeDesc::UINT8, uchar>(metadata, in, (uchar *)pixels);
+ oiio_load_pixels<TypeDesc::UINT8, uchar>(metadata, in, do_associate_alpha, (uchar *)pixels);
break;
case IMAGE_DATA_TYPE_USHORT:
case IMAGE_DATA_TYPE_USHORT4:
- oiio_load_pixels<TypeDesc::USHORT, uint16_t>(metadata, in, (uint16_t *)pixels);
+ oiio_load_pixels<TypeDesc::USHORT, uint16_t>(
+ metadata, in, do_associate_alpha, (uint16_t *)pixels);
break;
case IMAGE_DATA_TYPE_HALF:
case IMAGE_DATA_TYPE_HALF4:
- oiio_load_pixels<TypeDesc::HALF, half>(metadata, in, (half *)pixels);
+ oiio_load_pixels<TypeDesc::HALF, half>(metadata, in, do_associate_alpha, (half *)pixels);
break;
case IMAGE_DATA_TYPE_FLOAT:
case IMAGE_DATA_TYPE_FLOAT4:
- oiio_load_pixels<TypeDesc::FLOAT, float>(metadata, in, (float *)pixels);
+ oiio_load_pixels<TypeDesc::FLOAT, float>(metadata, in, do_associate_alpha, (float *)pixels);
break;
case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
diff --git a/intern/cycles/scene/image_vdb.cpp b/intern/cycles/scene/image_vdb.cpp
index 2209be60a97..059eb09fef4 100644
--- a/intern/cycles/scene/image_vdb.cpp
+++ b/intern/cycles/scene/image_vdb.cpp
@@ -70,7 +70,7 @@ struct ToNanoOp {
nanogrid = nanovdb::openToNanoVDB(floatgrid);
}
catch (const std::exception &e) {
- VLOG(1) << "Error converting OpenVDB to NanoVDB grid: " << e.what();
+ VLOG_WARNING << "Error converting OpenVDB to NanoVDB grid: " << e.what();
}
return true;
}
diff --git a/intern/cycles/scene/integrator.cpp b/intern/cycles/scene/integrator.cpp
index fda6ecc8d14..aa11004fb48 100644
--- a/intern/cycles/scene/integrator.cpp
+++ b/intern/cycles/scene/integrator.cpp
@@ -338,7 +338,7 @@ AdaptiveSampling Integrator::get_adaptive_sampling() const
if (aa_samples > 0 && adaptive_threshold == 0.0f) {
adaptive_sampling.threshold = max(0.001f, 1.0f / (float)aa_samples);
- VLOG(1) << "Cycles adaptive sampling: automatic threshold = " << adaptive_sampling.threshold;
+ VLOG_INFO << "Cycles adaptive sampling: automatic threshold = " << adaptive_sampling.threshold;
}
else {
adaptive_sampling.threshold = adaptive_threshold;
@@ -350,8 +350,8 @@ AdaptiveSampling Integrator::get_adaptive_sampling() const
* in various test scenes. */
const int min_samples = (int)ceilf(16.0f / powf(adaptive_sampling.threshold, 0.3f));
adaptive_sampling.min_samples = max(4, min_samples);
- VLOG(1) << "Cycles adaptive sampling: automatic min samples = "
- << adaptive_sampling.min_samples;
+ VLOG_INFO << "Cycles adaptive sampling: automatic min samples = "
+ << adaptive_sampling.min_samples;
}
else {
adaptive_sampling.min_samples = max(4, adaptive_min_samples);
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index 5e311d3051f..2b0d0c807a7 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -215,7 +215,9 @@ void LightManager::test_enabled_lights(Scene *scene)
*/
Shader *shader = scene->background->get_shader(scene);
const bool disable_mis = !(has_portal || shader->has_surface_spatial_varying);
- VLOG_IF(1, disable_mis) << "Background MIS has been disabled.\n";
+ if (disable_mis) {
+ VLOG_INFO << "Background MIS has been disabled.\n";
+ }
foreach (Light *light, scene->lights) {
if (light->light_type == LIGHT_BACKGROUND) {
light->is_enabled = !disable_mis;
@@ -309,7 +311,7 @@ void LightManager::device_update_distribution(Device *,
}
size_t num_distribution = num_triangles + num_lights;
- VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
+ VLOG_INFO << "Total " << num_distribution << " of light distribution primitives.";
/* emission area */
KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1);
@@ -655,13 +657,14 @@ void LightManager::device_update_background(Device *device,
if (res.x == 0) {
res = environment_res;
if (res.x > 0 && res.y > 0) {
- VLOG(2) << "Automatically set World MIS resolution to " << res.x << " by " << res.y << "\n";
+ VLOG_INFO << "Automatically set World MIS resolution to " << res.x << " by " << res.y
+ << "\n";
}
}
/* If it's still unknown, just use the default. */
if (res.x == 0 || res.y == 0) {
res = make_int2(1024, 512);
- VLOG(2) << "Setting World MIS resolution to default\n";
+ VLOG_INFO << "Setting World MIS resolution to default\n";
}
kbackground->map_res_x = res.x;
kbackground->map_res_y = res.y;
@@ -704,7 +707,7 @@ void LightManager::device_update_background(Device *device,
marg_cdf[res.y].y = 1.0f;
- VLOG(2) << "Background MIS build time " << time_dt() - time_start << "\n";
+ VLOG_WORK << "Background MIS build time " << time_dt() - time_start << "\n";
/* update device */
dscene->light_background_marginal_cdf.copy_to_device();
@@ -725,7 +728,7 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
KernelLight *klights = dscene->lights.alloc(num_lights);
if (num_lights == 0) {
- VLOG(1) << "No effective light, ignoring points update.";
+ VLOG_WORK << "No effective light, ignoring points update.";
return;
}
@@ -955,9 +958,9 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
light_index++;
}
- VLOG(1) << "Number of lights sent to the device: " << light_index;
+ VLOG_INFO << "Number of lights sent to the device: " << light_index;
- VLOG(1) << "Number of lights without contribution: " << num_scene_lights - light_index;
+ VLOG_INFO << "Number of lights without contribution: " << num_scene_lights - light_index;
dscene->lights.copy_to_device();
}
@@ -976,7 +979,7 @@ void LightManager::device_update(Device *device,
}
});
- VLOG(1) << "Total " << scene->lights.size() << " lights.";
+ VLOG_INFO << "Total " << scene->lights.size() << " lights.";
/* Detect which lights are enabled, also determines if we need to update the background. */
test_enabled_lights(scene);
diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp
index ddd89a16640..3a1c177fe3b 100644
--- a/intern/cycles/scene/object.cpp
+++ b/intern/cycles/scene/object.cpp
@@ -688,7 +688,7 @@ void ObjectManager::device_update(Device *device,
dscene->objects.tag_modified();
}
- VLOG(1) << "Total " << scene->objects.size() << " objects.";
+ VLOG_INFO << "Total " << scene->objects.size() << " objects.";
device_free(device, dscene, false);
diff --git a/intern/cycles/scene/osl.cpp b/intern/cycles/scene/osl.cpp
index 6698e6e2cce..f5ee0c0f1d3 100644
--- a/intern/cycles/scene/osl.cpp
+++ b/intern/cycles/scene/osl.cpp
@@ -92,7 +92,7 @@ void OSLShaderManager::device_update_specific(Device *device,
}
});
- VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
+ VLOG_INFO << "Total " << scene->shaders.size() << " shaders.";
device_free(device, dscene, scene);
@@ -240,7 +240,7 @@ void OSLShaderManager::shading_system_init()
ss_shared->attribute("searchpath:shader", shader_path);
ss_shared->attribute("greedyjit", 1);
- VLOG(1) << "Using shader search path: " << shader_path;
+ VLOG_INFO << "Using shader search path: " << shader_path;
/* our own ray types */
static const char *raytypes[] = {
diff --git a/intern/cycles/scene/particles.cpp b/intern/cycles/scene/particles.cpp
index a05acf17ccf..b527dd0ebe8 100644
--- a/intern/cycles/scene/particles.cpp
+++ b/intern/cycles/scene/particles.cpp
@@ -105,7 +105,7 @@ void ParticleSystemManager::device_update(Device *device,
}
});
- VLOG(1) << "Total " << scene->particle_systems.size() << " particle systems.";
+ VLOG_INFO << "Total " << scene->particle_systems.size() << " particle systems.";
device_free(device, dscene);
diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp
index 8b5604eba72..33ce0a45733 100644
--- a/intern/cycles/scene/scene.cpp
+++ b/intern/cycles/scene/scene.cpp
@@ -373,11 +373,11 @@ void Scene::device_update(Device *device_, Progress &progress)
size_t mem_used = util_guarded_get_mem_used();
size_t mem_peak = util_guarded_get_mem_peak();
- VLOG(1) << "System memory statistics after full device sync:\n"
- << " Usage: " << string_human_readable_number(mem_used) << " ("
- << string_human_readable_size(mem_used) << ")\n"
- << " Peak: " << string_human_readable_number(mem_peak) << " ("
- << string_human_readable_size(mem_peak) << ")";
+ VLOG_INFO << "System memory statistics after full device sync:\n"
+ << " Usage: " << string_human_readable_number(mem_used) << " ("
+ << string_human_readable_size(mem_used) << ")\n"
+ << " Peak: " << string_human_readable_number(mem_peak) << " ("
+ << string_human_readable_size(mem_peak) << ")";
}
}
@@ -586,35 +586,38 @@ bool Scene::update(Progress &progress)
static void log_kernel_features(const uint features)
{
- VLOG(2) << "Requested features:\n";
- VLOG(2) << "Use BSDF " << string_from_bool(features & KERNEL_FEATURE_NODE_BSDF) << "\n";
- VLOG(2) << "Use Principled BSDF " << string_from_bool(features & KERNEL_FEATURE_PRINCIPLED)
- << "\n";
- VLOG(2) << "Use Emission " << string_from_bool(features & KERNEL_FEATURE_NODE_EMISSION) << "\n";
- VLOG(2) << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_NODE_VOLUME) << "\n";
- VLOG(2) << "Use Bump " << string_from_bool(features & KERNEL_FEATURE_NODE_BUMP) << "\n";
- VLOG(2) << "Use Voronoi " << string_from_bool(features & KERNEL_FEATURE_NODE_VORONOI_EXTRA)
- << "\n";
- VLOG(2) << "Use Shader Raytrace " << string_from_bool(features & KERNEL_FEATURE_NODE_RAYTRACE)
- << "\n";
- VLOG(2) << "Use MNEE" << string_from_bool(features & KERNEL_FEATURE_MNEE) << "\n";
- VLOG(2) << "Use Transparent " << string_from_bool(features & KERNEL_FEATURE_TRANSPARENT) << "\n";
- VLOG(2) << "Use Denoising " << string_from_bool(features & KERNEL_FEATURE_DENOISING) << "\n";
- VLOG(2) << "Use Path Tracing " << string_from_bool(features & KERNEL_FEATURE_PATH_TRACING)
- << "\n";
- VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_HAIR) << "\n";
- VLOG(2) << "Use Pointclouds " << string_from_bool(features & KERNEL_FEATURE_POINTCLOUD) << "\n";
- VLOG(2) << "Use Object Motion " << string_from_bool(features & KERNEL_FEATURE_OBJECT_MOTION)
- << "\n";
- VLOG(2) << "Use Camera Motion " << string_from_bool(features & KERNEL_FEATURE_CAMERA_MOTION)
- << "\n";
- VLOG(2) << "Use Baking " << string_from_bool(features & KERNEL_FEATURE_BAKING) << "\n";
- VLOG(2) << "Use Subsurface " << string_from_bool(features & KERNEL_FEATURE_SUBSURFACE) << "\n";
- VLOG(2) << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_VOLUME) << "\n";
- VLOG(2) << "Use Patch Evaluation "
- << string_from_bool(features & KERNEL_FEATURE_PATCH_EVALUATION) << "\n";
- VLOG(2) << "Use Shadow Catcher " << string_from_bool(features & KERNEL_FEATURE_SHADOW_CATCHER)
- << "\n";
+ VLOG_INFO << "Requested features:\n";
+ VLOG_INFO << "Use BSDF " << string_from_bool(features & KERNEL_FEATURE_NODE_BSDF) << "\n";
+ VLOG_INFO << "Use Principled BSDF " << string_from_bool(features & KERNEL_FEATURE_PRINCIPLED)
+ << "\n";
+ VLOG_INFO << "Use Emission " << string_from_bool(features & KERNEL_FEATURE_NODE_EMISSION)
+ << "\n";
+ VLOG_INFO << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_NODE_VOLUME) << "\n";
+ VLOG_INFO << "Use Bump " << string_from_bool(features & KERNEL_FEATURE_NODE_BUMP) << "\n";
+ VLOG_INFO << "Use Voronoi " << string_from_bool(features & KERNEL_FEATURE_NODE_VORONOI_EXTRA)
+ << "\n";
+ VLOG_INFO << "Use Shader Raytrace " << string_from_bool(features & KERNEL_FEATURE_NODE_RAYTRACE)
+ << "\n";
+ VLOG_INFO << "Use MNEE" << string_from_bool(features & KERNEL_FEATURE_MNEE) << "\n";
+ VLOG_INFO << "Use Transparent " << string_from_bool(features & KERNEL_FEATURE_TRANSPARENT)
+ << "\n";
+ VLOG_INFO << "Use Denoising " << string_from_bool(features & KERNEL_FEATURE_DENOISING) << "\n";
+ VLOG_INFO << "Use Path Tracing " << string_from_bool(features & KERNEL_FEATURE_PATH_TRACING)
+ << "\n";
+ VLOG_INFO << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_HAIR) << "\n";
+ VLOG_INFO << "Use Pointclouds " << string_from_bool(features & KERNEL_FEATURE_POINTCLOUD)
+ << "\n";
+ VLOG_INFO << "Use Object Motion " << string_from_bool(features & KERNEL_FEATURE_OBJECT_MOTION)
+ << "\n";
+ VLOG_INFO << "Use Camera Motion " << string_from_bool(features & KERNEL_FEATURE_CAMERA_MOTION)
+ << "\n";
+ VLOG_INFO << "Use Baking " << string_from_bool(features & KERNEL_FEATURE_BAKING) << "\n";
+ VLOG_INFO << "Use Subsurface " << string_from_bool(features & KERNEL_FEATURE_SUBSURFACE) << "\n";
+ VLOG_INFO << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_VOLUME) << "\n";
+ VLOG_INFO << "Use Patch Evaluation "
+ << string_from_bool(features & KERNEL_FEATURE_PATCH_EVALUATION) << "\n";
+ VLOG_INFO << "Use Shadow Catcher " << string_from_bool(features & KERNEL_FEATURE_SHADOW_CATCHER)
+ << "\n";
}
bool Scene::load_kernels(Progress &progress, bool lock_scene)
@@ -675,8 +678,8 @@ int Scene::get_max_closure_count()
* closures discarded due to mixing or low weights. We need to limit
* to MAX_CLOSURE as this is hardcoded in CPU/mega kernels, and it
* avoids excessive memory usage for split kernels. */
- VLOG(2) << "Maximum number of closures exceeded: " << max_closure_global << " > "
- << MAX_CLOSURE;
+ VLOG_WARNING << "Maximum number of closures exceeded: " << max_closure_global << " > "
+ << MAX_CLOSURE;
max_closure_global = MAX_CLOSURE;
}
@@ -723,7 +726,7 @@ int Scene::get_volume_stack_size() const
volume_stack_size = min(volume_stack_size, MAX_VOLUME_STACK_SIZE);
- VLOG(3) << "Detected required volume stack size " << volume_stack_size;
+ VLOG_WORK << "Detected required volume stack size " << volume_stack_size;
return volume_stack_size;
}
diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h
index a0d2f4a6c06..d04c6a27f11 100644
--- a/intern/cycles/scene/scene.h
+++ b/intern/cycles/scene/scene.h
@@ -98,7 +98,7 @@ class DeviceScene {
device_vector<DecomposedTransform> camera_motion;
/* attributes */
- device_vector<uint4> attributes_map;
+ device_vector<AttributeMap> attributes_map;
device_vector<float> attributes_float;
device_vector<float2> attributes_float2;
device_vector<packed_float3> attributes_float3;
diff --git a/intern/cycles/scene/shader_graph.cpp b/intern/cycles/scene/shader_graph.cpp
index f25d0b7c7b9..ef3f142ed4e 100644
--- a/intern/cycles/scene/shader_graph.cpp
+++ b/intern/cycles/scene/shader_graph.cpp
@@ -659,7 +659,7 @@ void ShaderGraph::deduplicate_nodes()
}
if (num_deduplicated > 0) {
- VLOG(1) << "Deduplicated " << num_deduplicated << " nodes.";
+ VLOG_DEBUG << "Deduplicated " << num_deduplicated << " nodes.";
}
}
@@ -700,7 +700,7 @@ void ShaderGraph::verify_volume_output()
}
}
if (!has_valid_volume) {
- VLOG(1) << "Disconnect meaningless volume output.";
+ VLOG_DEBUG << "Disconnect meaningless volume output.";
disconnect(volume_in->link);
}
}
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
index 3b58556f601..f93a1a5231a 100644
--- a/intern/cycles/scene/shader_nodes.cpp
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -2391,7 +2391,7 @@ void GlossyBsdfNode::simplify_settings(Scene *scene)
* NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
- VLOG(3) << "Using sharp glossy BSDF.";
+ VLOG_DEBUG << "Using sharp glossy BSDF.";
distribution = CLOSURE_BSDF_REFLECTION_ID;
}
}
@@ -2400,7 +2400,7 @@ void GlossyBsdfNode::simplify_settings(Scene *scene)
* benefit from closure blur to remove unwanted noise.
*/
if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFLECTION_ID) {
- VLOG(3) << "Using GGX glossy with filter glossy.";
+ VLOG_DEBUG << "Using GGX glossy with filter glossy.";
distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
roughness = 0.0f;
}
@@ -2484,7 +2484,7 @@ void GlassBsdfNode::simplify_settings(Scene *scene)
* NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
- VLOG(3) << "Using sharp glass BSDF.";
+ VLOG_DEBUG << "Using sharp glass BSDF.";
distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
}
}
@@ -2493,7 +2493,7 @@ void GlassBsdfNode::simplify_settings(Scene *scene)
* benefit from closure blur to remove unwanted noise.
*/
if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_SHARP_GLASS_ID) {
- VLOG(3) << "Using GGX glass with filter glossy.";
+ VLOG_DEBUG << "Using GGX glass with filter glossy.";
distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
roughness = 0.0f;
}
@@ -2577,7 +2577,7 @@ void RefractionBsdfNode::simplify_settings(Scene *scene)
* NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
- VLOG(3) << "Using sharp refraction BSDF.";
+ VLOG_DEBUG << "Using sharp refraction BSDF.";
distribution = CLOSURE_BSDF_REFRACTION_ID;
}
}
@@ -2586,7 +2586,7 @@ void RefractionBsdfNode::simplify_settings(Scene *scene)
* benefit from closure blur to remove unwanted noise.
*/
if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFRACTION_ID) {
- VLOG(3) << "Using GGX refraction with filter glossy.";
+ VLOG_DEBUG << "Using GGX refraction with filter glossy.";
distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
roughness = 0.0f;
}
diff --git a/intern/cycles/scene/svm.cpp b/intern/cycles/scene/svm.cpp
index 484a7d6de72..4bc5a1b9cc2 100644
--- a/intern/cycles/scene/svm.cpp
+++ b/intern/cycles/scene/svm.cpp
@@ -51,9 +51,9 @@ void SVMShaderManager::device_update_shader(Scene *scene,
compiler.background = (shader == scene->background->get_shader(scene));
compiler.compile(shader, *svm_nodes, 0, &summary);
- VLOG(3) << "Compilation summary:\n"
- << "Shader name: " << shader->name << "\n"
- << summary.full_report();
+ VLOG_WORK << "Compilation summary:\n"
+ << "Shader name: " << shader->name << "\n"
+ << summary.full_report();
}
void SVMShaderManager::device_update_specific(Device *device,
@@ -72,7 +72,7 @@ void SVMShaderManager::device_update_specific(Device *device,
const int num_shaders = scene->shaders.size();
- VLOG(1) << "Total " << num_shaders << " shaders.";
+ VLOG_INFO << "Total " << num_shaders << " shaders.";
double start_time = time_dt();
@@ -148,8 +148,8 @@ void SVMShaderManager::device_update_specific(Device *device,
update_flags = UPDATE_NONE;
- VLOG(1) << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
- << " seconds.";
+ VLOG_INFO << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
+ << " seconds.";
}
void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
diff --git a/intern/cycles/scene/tables.cpp b/intern/cycles/scene/tables.cpp
index bb35880d37e..3e57b535f35 100644
--- a/intern/cycles/scene/tables.cpp
+++ b/intern/cycles/scene/tables.cpp
@@ -34,7 +34,7 @@ void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene)
}
});
- VLOG(1) << "Total " << lookup_tables.size() << " lookup tables.";
+ VLOG_INFO << "Total " << lookup_tables.size() << " lookup tables.";
if (lookup_tables.size() > 0)
dscene->lookup_table.copy_to_device();
diff --git a/intern/cycles/scene/volume.cpp b/intern/cycles/scene/volume.cpp
index 39e9b0bbbf4..77955350305 100644
--- a/intern/cycles/scene/volume.cpp
+++ b/intern/cycles/scene/volume.cpp
@@ -754,11 +754,11 @@ void GeometryManager::create_volume_mesh(const Scene *scene, Volume *volume, Pro
}
/* Print stats. */
- VLOG(1) << "Memory usage volume mesh: "
- << ((vertices.size() + face_normals.size()) * sizeof(float3) +
- indices.size() * sizeof(int)) /
- (1024.0 * 1024.0)
- << "Mb.";
+ VLOG_WORK << "Memory usage volume mesh: "
+ << ((vertices.size() + face_normals.size()) * sizeof(float3) +
+ indices.size() * sizeof(int)) /
+ (1024.0 * 1024.0)
+ << "Mb.";
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/session/denoising.cpp b/intern/cycles/session/denoising.cpp
index ff9ca1b4345..a9377d412e8 100644
--- a/intern/cycles/session/denoising.cpp
+++ b/intern/cycles/session/denoising.cpp
@@ -90,7 +90,7 @@ static vector<ChannelMapping> output_channels()
return map;
}
-/* Renderlayer Handling */
+/* Render-layer Handling. */
bool DenoiseImageLayer::detect_denoising_channels()
{
diff --git a/intern/cycles/session/session.cpp b/intern/cycles/session/session.cpp
index ef177636046..ba30be817cf 100644
--- a/intern/cycles/session/session.cpp
+++ b/intern/cycles/session/session.cpp
@@ -146,11 +146,11 @@ void Session::run_main_render_loop()
RenderWork render_work = run_update_for_next_iteration();
if (!render_work) {
- if (VLOG_IS_ON(2)) {
+ if (VLOG_WORK_IS_ON) {
double total_time, render_time;
progress.get_time(total_time, render_time);
- VLOG(2) << "Rendering in main loop is done in " << render_time << " seconds.";
- VLOG(2) << path_trace_->full_report();
+ VLOG_WORK << "Rendering in main loop is done in " << render_time << " seconds.";
+ VLOG_WORK << path_trace_->full_report();
}
if (params.background) {
diff --git a/intern/cycles/session/tile.cpp b/intern/cycles/session/tile.cpp
index 82272a7dbf5..f4930cbb945 100644
--- a/intern/cycles/session/tile.cpp
+++ b/intern/cycles/session/tile.cpp
@@ -335,7 +335,7 @@ int TileManager::compute_render_tile_size(const int suggested_tile_size) const
void TileManager::reset_scheduling(const BufferParams &params, int2 tile_size)
{
- VLOG(3) << "Using tile size of " << tile_size;
+ VLOG_WORK << "Using tile size of " << tile_size;
close_tile_output();
@@ -466,7 +466,7 @@ bool TileManager::open_tile_output()
write_state_.num_tiles_written = 0;
- VLOG(3) << "Opened tile file " << write_state_.filename;
+ VLOG_WORK << "Opened tile file " << write_state_.filename;
return true;
}
@@ -485,7 +485,7 @@ bool TileManager::close_tile_output()
return false;
}
- VLOG(3) << "Tile output is closed.";
+ VLOG_WORK << "Tile output is closed.";
return true;
}
@@ -536,7 +536,7 @@ bool TileManager::write_tile(const RenderBuffers &tile_buffers)
pixels = pixel_storage.data();
}
- VLOG(3) << "Write tile at " << tile_x << ", " << tile_y;
+ VLOG_WORK << "Write tile at " << tile_x << ", " << tile_y;
/* The image tile sizes in the OpenEXR file are different from the size of our big tiles. The
* write_tiles() method expects a contiguous image region that will be split into tiles
@@ -567,7 +567,7 @@ bool TileManager::write_tile(const RenderBuffers &tile_buffers)
++write_state_.num_tiles_written;
- VLOG(3) << "Tile written in " << time_dt() - time_start << " seconds.";
+ VLOG_WORK << "Tile written in " << time_dt() - time_start << " seconds.";
return true;
}
@@ -591,7 +591,7 @@ void TileManager::finish_write_tiles()
const int tile_x = tile.x + tile.window_x;
const int tile_y = tile.y + tile.window_y;
- VLOG(3) << "Write dummy tile at " << tile_x << ", " << tile_y;
+ VLOG_WORK << "Write dummy tile at " << tile_x << ", " << tile_y;
write_state_.tile_out->write_tiles(tile_x,
tile_x + tile.window_width,
@@ -610,8 +610,8 @@ void TileManager::finish_write_tiles()
full_buffer_written_cb(write_state_.filename);
}
- VLOG(3) << "Tile file size is "
- << string_human_readable_number(path_file_size(write_state_.filename)) << " bytes.";
+ VLOG_WORK << "Tile file size is "
+ << string_human_readable_number(path_file_size(write_state_.filename)) << " bytes.";
/* Advance the counter upon explicit finish of the file.
* Makes it possible to re-use tile manager for another scene, and avoids unnecessary increments
diff --git a/intern/cycles/test/render_graph_finalize_test.cpp b/intern/cycles/test/render_graph_finalize_test.cpp
index dac36ab0135..2dc13f0eccb 100644
--- a/intern/cycles/test/render_graph_finalize_test.cpp
+++ b/intern/cycles/test/render_graph_finalize_test.cpp
@@ -166,7 +166,7 @@ class RenderGraph : public testing::Test {
virtual void SetUp()
{
util_logging_start();
- util_logging_verbosity_set(3);
+ util_logging_verbosity_set(5);
device_cpu = Device::create(device_info, stats, profiler);
scene = new Scene(scene_params, device_cpu);
diff --git a/intern/cycles/util/debug.cpp b/intern/cycles/util/debug.cpp
index 65d108bb9d1..faa54a92c24 100644
--- a/intern/cycles/util/debug.cpp
+++ b/intern/cycles/util/debug.cpp
@@ -25,7 +25,7 @@ void DebugFlags::CPU::reset()
do { \
flag = (getenv(env) == NULL); \
if (!flag) { \
- VLOG(1) << "Disabling " << STRINGIFY(flag) << " instruction set."; \
+ VLOG_INFO << "Disabling " << STRINGIFY(flag) << " instruction set."; \
} \
} while (0)
diff --git a/intern/cycles/util/image.h b/intern/cycles/util/image.h
index 9348125d072..17446a83e59 100644
--- a/intern/cycles/util/image.h
+++ b/intern/cycles/util/image.h
@@ -78,6 +78,26 @@ template<> inline half util_image_cast_from_float(float value)
return float_to_half_image(value);
}
+/* Multiply image pixels in native data format. */
+template<typename T> inline T util_image_multiply_native(T a, T b);
+
+template<> inline float util_image_multiply_native(float a, float b)
+{
+ return a * b;
+}
+template<> inline uchar util_image_multiply_native(uchar a, uchar b)
+{
+ return ((uint32_t)a * (uint32_t)b) / 255;
+}
+template<> inline uint16_t util_image_multiply_native(uint16_t a, uint16_t b)
+{
+ return ((uint32_t)a * (uint32_t)b) / 65535;
+}
+template<> inline half util_image_multiply_native(half a, half b)
+{
+ return float_to_half_image(half_to_float_image(a) * half_to_float_image(b));
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_IMAGE_H__ */
diff --git a/intern/cycles/util/log.h b/intern/cycles/util/log.h
index b33c826d6f5..3780d03c0d1 100644
--- a/intern/cycles/util/log.h
+++ b/intern/cycles/util/log.h
@@ -69,9 +69,22 @@ class LogMessageVoidify {
# define LOG_ASSERT(expression) LOG_SUPPRESS()
#endif
-#define VLOG_ONCE(level, flag) \
- if (!flag) \
- flag = true, VLOG(level)
+/* Verbose logging categories. */
+
+/* Warnings. */
+#define VLOG_WARNING VLOG(1)
+/* Info about devices, scene contents and features used. */
+#define VLOG_INFO VLOG(2)
+#define VLOG_INFO_IS_ON VLOG_IS_ON(2)
+/* Work being performed and timing/memory stats about that work. */
+#define VLOG_WORK VLOG(3)
+#define VLOG_WORK_IS_ON VLOG_IS_ON(3)
+/* Detailed device timing stats. */
+#define VLOG_DEVICE_STATS VLOG(4)
+#define VLOG_DEVICE_STATS_IS_ON VLOG_IS_ON(4)
+/* Verbose debug messages. */
+#define VLOG_DEBUG VLOG(5)
+#define VLOG_DEBUG_IS_ON VLOG_IS_ON(5)
struct int2;
struct float3;
diff --git a/intern/cycles/util/task.cpp b/intern/cycles/util/task.cpp
index 2edc82eb7c3..12f661f752d 100644
--- a/intern/cycles/util/task.cpp
+++ b/intern/cycles/util/task.cpp
@@ -70,7 +70,7 @@ void TaskScheduler::init(int num_threads)
}
if (num_threads > 0) {
/* Automatic number of threads. */
- VLOG(1) << "Overriding number of TBB threads to " << num_threads << ".";
+ VLOG_INFO << "Overriding number of TBB threads to " << num_threads << ".";
global_control = new tbb::global_control(tbb::global_control::max_allowed_parallelism,
num_threads);
active_num_threads = num_threads;
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index dceb9ced803..5b06b5d98e6 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -324,16 +324,21 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
${CMAKE_CURRENT_BINARY_DIR}
)
- # xdg-shell.
+ # `xdg-shell`.
generate_protocol_bindings(
xdg-shell
"${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml"
)
- # xdg-decoration.
+ # `xdg-decoration`.
generate_protocol_bindings(
xdg-decoration
"${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
)
+ # `xdg-output`.
+ generate_protocol_bindings(
+ xdg-output
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-output/xdg-output-unstable-v1.xml"
+ )
# Pointer-constraints.
generate_protocol_bindings(
pointer-constraints
@@ -344,6 +349,11 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
relative-pointer
"${WAYLAND_PROTOCOLS_DIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
)
+ # Tablet.
+ generate_protocol_bindings(
+ tablet
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/tablet/tablet-unstable-v2.xml"
+ )
add_definitions(-DWITH_GHOST_WAYLAND)
endif()
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index ae749eb3b8c..d27be40af0c 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -20,7 +20,7 @@ extern "C" {
* \param event: The event received.
* \param userdata: The callback's user data, supplied to #GHOST_CreateSystem.
*/
-typedef int (*GHOST_EventCallbackProcPtr)(GHOST_EventHandle event, GHOST_TUserDataPtr userdata);
+typedef bool (*GHOST_EventCallbackProcPtr)(GHOST_EventHandle event, GHOST_TUserDataPtr userdata);
/**
* Creates the one and only system.
@@ -206,7 +206,7 @@ extern GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandl
*/
extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr userdata);
-extern int GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle);
+extern bool GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle);
/**
* Dispose a window.
@@ -223,7 +223,7 @@ extern GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle,
* \param windowhandle: Handle to the window to be checked.
* \return Indication of validity.
*/
-extern int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle);
+extern bool GHOST_ValidWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle);
/**
* Begins full screen mode.
@@ -235,7 +235,7 @@ extern int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle
*/
extern GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle,
GHOST_DisplaySetting *setting,
- const int stereoVisual);
+ const bool stereoVisual);
/**
* Ends full screen mode.
@@ -249,7 +249,7 @@ extern GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle);
* \param systemhandle: The handle to the system.
* \return The current status.
*/
-extern int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle);
+extern bool GHOST_GetFullScreen(GHOST_SystemHandle systemhandle);
/**
* Get the Window under the cursor.
@@ -369,7 +369,7 @@ extern GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle
* \param windowhandle: The handle to the window.
* \return The visibility state of the cursor.
*/
-extern int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle);
+extern bool GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle);
/**
* Shows or hides the cursor.
@@ -377,7 +377,7 @@ extern int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle);
* \param visible: The new visibility state of the cursor.
* \return Indication of success.
*/
-extern GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, int visible);
+extern GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, bool visible);
/**
* Returns the current location of the cursor (location in screen coordinates)
@@ -402,6 +402,11 @@ extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle,
int32_t x,
int32_t y);
+void GHOST_GetCursorGrabState(GHOST_WindowHandle windowhandle,
+ GHOST_TGrabCursorMode *r_mode,
+ GHOST_TAxisFlag *r_wrap_axis,
+ int r_bounds[4]);
+
/**
* Grabs the cursor for a modal operation, to keep receiving
* events when the mouse is outside the window. X11 only, others
@@ -431,7 +436,7 @@ extern GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
*/
extern GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle,
GHOST_TModifierKeyMask mask,
- int *isDown);
+ bool *r_is_down);
/**
* Returns the state of a mouse button (outside the message queue).
@@ -442,7 +447,7 @@ extern GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle,
*/
extern GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle,
GHOST_TButtonMask mask,
- int *isDown);
+ bool *r_is_down);
#ifdef WITH_INPUT_NDOF
/***************************************************************************************
@@ -463,7 +468,7 @@ extern void GHOST_setNDOFDeadZone(float deadzone);
/**
* Tells if the ongoing drag'n'drop object can be accepted upon mouse drop
*/
-extern void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, bool canAccept);
+extern void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, bool can_accept);
/**
* Returns the event type.
@@ -529,7 +534,7 @@ extern void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle,
* \param windowhandle: The handle to the window.
* \return The validity of the window.
*/
-extern int GHOST_GetValid(GHOST_WindowHandle windowhandle);
+extern bool GHOST_GetValid(GHOST_WindowHandle windowhandle);
/**
* Returns the type of drawing context used in this window.
@@ -889,17 +894,32 @@ extern void GHOST_putClipboard(const char *buffer, bool selection);
* \param action: console state
* \return current status (1 -visible, 0 - hidden)
*/
-extern int setConsoleWindowState(GHOST_TConsoleWindowState action);
+extern bool GHOST_setConsoleWindowState(GHOST_TConsoleWindowState action);
/**
* Use native pixel size (MacBook pro 'retina'), if supported.
*/
-extern int GHOST_UseNativePixels(void);
+extern bool GHOST_UseNativePixels(void);
+
+/**
+ * Warp the cursor, if supported.
+ */
+extern bool GHOST_SupportsCursorWarp(void);
+
+/**
+ * Support positioning windows (when false `wmWindow.x,y` are meaningless).
+ */
+extern bool GHOST_SupportsWindowPosition(void);
+
+/**
+ * Assign the callback which generates a back-trace (may be NULL).
+ */
+extern void GHOST_SetBacktraceHandler(GHOST_TBacktraceFn backtrace_fn);
/**
* Focus window after opening, or put them in the background.
*/
-extern void GHOST_UseWindowFocus(int use_focus);
+extern void GHOST_UseWindowFocus(bool use_focus);
/**
* If window was opened using native pixel size, it returns scaling factor.
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index bb91abbadec..d946d2d882a 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -133,6 +133,9 @@ class GHOST_ISystem {
*/
static GHOST_ISystem *getSystem();
+ static GHOST_TBacktraceFn getBacktraceFn();
+ static void setBacktraceFn(GHOST_TBacktraceFn backtrace_fn);
+
protected:
/**
* Constructor.
@@ -305,6 +308,16 @@ class GHOST_ISystem {
virtual bool useNativePixel(void) = 0;
/**
+ * Return true when warping the cursor is supported.
+ */
+ virtual bool supportsCursorWarp() = 0;
+
+ /**
+ * Return true getting/setting the window position is supported.
+ */
+ virtual bool supportsWindowPosition() = 0;
+
+ /**
* Focus window after opening, or put them in the background.
*/
virtual void useWindowFocus(const bool use_focus) = 0;
@@ -477,6 +490,9 @@ class GHOST_ISystem {
/** The one and only system */
static GHOST_ISystem *m_system;
+ /** Function to call that sets the back-trace. */
+ static GHOST_TBacktraceFn m_backtrace_fn;
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_ISystem")
#endif
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index 183e97a4b55..7927190de04 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -254,6 +254,12 @@ class GHOST_IWindow {
*/
virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape) = 0;
+ virtual GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) = 0;
+
+ virtual void getCursorGrabState(GHOST_TGrabCursorMode &mode,
+ GHOST_TAxisFlag &axis_flag,
+ GHOST_Rect &bounds) = 0;
+
/**
* Test if the standard cursor shape is supported by current platform.
* \return Indication of success.
diff --git a/intern/ghost/GHOST_Rect.h b/intern/ghost/GHOST_Rect.h
index 0a5561b7d68..a8082bf015a 100644
--- a/intern/ghost/GHOST_Rect.h
+++ b/intern/ghost/GHOST_Rect.h
@@ -190,26 +190,34 @@ inline bool GHOST_Rect::isValid() const
inline void GHOST_Rect::unionRect(const GHOST_Rect &r)
{
- if (r.m_l < m_l)
+ if (r.m_l < m_l) {
m_l = r.m_l;
- if (r.m_r > m_r)
+ }
+ if (r.m_r > m_r) {
m_r = r.m_r;
- if (r.m_t < m_t)
+ }
+ if (r.m_t < m_t) {
m_t = r.m_t;
- if (r.m_b > m_b)
+ }
+ if (r.m_b > m_b) {
m_b = r.m_b;
+ }
}
inline void GHOST_Rect::unionPoint(int32_t x, int32_t y)
{
- if (x < m_l)
+ if (x < m_l) {
m_l = x;
- if (x > m_r)
+ }
+ if (x > m_r) {
m_r = x;
- if (y < m_t)
+ }
+ if (y < m_t) {
m_t = y;
- if (y > m_b)
+ }
+ if (y > m_b) {
m_b = y;
+ }
}
inline void GHOST_Rect::wrapPoint(int32_t &x, int32_t &y, int32_t ofs, GHOST_TAxisFlag axis)
@@ -223,16 +231,20 @@ inline void GHOST_Rect::wrapPoint(int32_t &x, int32_t &y, int32_t ofs, GHOST_TAx
}
if (axis & GHOST_kAxisX) {
- while (x - ofs < m_l)
+ while (x - ofs < m_l) {
x += w - (ofs * 2);
- while (x + ofs > m_r)
+ }
+ while (x + ofs > m_r) {
x -= w - (ofs * 2);
+ }
}
if (axis & GHOST_kGrabAxisY) {
- while (y - ofs < m_t)
+ while (y - ofs < m_t) {
y += h - (ofs * 2);
- while (y + ofs > m_b)
+ }
+ while (y + ofs > m_b) {
y -= h - (ofs * 2);
+ }
}
}
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 85913fbd10c..78f2b24ea78 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -42,6 +42,8 @@ GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle);
GHOST_DECLARE_HANDLE(GHOST_ContextHandle);
GHOST_DECLARE_HANDLE(GHOST_XrContextHandle);
+typedef void (*GHOST_TBacktraceFn)(void *file_handle);
+
typedef struct {
int flags;
} GHOST_GLSettings;
@@ -403,6 +405,8 @@ typedef enum {
GHOST_kGrabHide,
} GHOST_TGrabCursorMode;
+#define GHOST_GRAB_NEEDS_SOFTWARE_CURSOR_FOR_WARP(grab) ((grab) == GHOST_kGrabWrap)
+
typedef enum {
/** Axis that cursor grab will wrap. */
GHOST_kGrabAxisNone = 0,
@@ -521,7 +525,7 @@ typedef struct {
} GHOST_TEventNDOFMotionData;
typedef enum { GHOST_kPress, GHOST_kRelease } GHOST_TButtonAction;
-/* Good for mouse or other buttons too, hmmm? */
+/* Good for mouse or other buttons too? */
typedef struct {
GHOST_TButtonAction action;
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 9374d087408..c8127f59941 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -177,11 +177,11 @@ void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr
window->setUserData(userdata);
}
-int GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle)
+bool GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- return (int)window->isDialog();
+ return window->isDialog();
}
GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle,
@@ -193,17 +193,17 @@ GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle,
return system->disposeWindow(window);
}
-int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle)
+bool GHOST_ValidWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- return (int)system->validWindow(window);
+ return system->validWindow(window);
}
GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle,
GHOST_DisplaySetting *setting,
- const int stereoVisual)
+ const bool stereoVisual)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
GHOST_IWindow *window = nullptr;
@@ -228,11 +228,11 @@ GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle)
return system->endFullScreen();
}
-int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle)
+bool GHOST_GetFullScreen(GHOST_SystemHandle systemhandle)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
- return (int)system->getFullScreen();
+ return system->getFullScreen();
}
GHOST_WindowHandle GHOST_GetWindowUnderCursor(GHOST_SystemHandle systemhandle,
@@ -326,18 +326,18 @@ GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle,
return window->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
}
-int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle)
+bool GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- return (int)window->getCursorVisibility();
+ return window->getCursorVisibility();
}
-GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, int visible)
+GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, bool visible)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- return window->setCursorVisibility(visible ? true : false);
+ return window->setCursorVisibility(visible);
}
GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle, int32_t *x, int32_t *y)
@@ -376,30 +376,44 @@ GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
mode, wrap_axis, bounds ? &bounds_rect : nullptr, mouse_ungrab_xy ? mouse_xy : nullptr);
}
+void GHOST_GetCursorGrabState(GHOST_WindowHandle windowhandle,
+ GHOST_TGrabCursorMode *r_mode,
+ GHOST_TAxisFlag *r_axis_flag,
+ int r_bounds[4])
+{
+ GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
+ GHOST_Rect bounds_rect;
+ window->getCursorGrabState(*r_mode, *r_axis_flag, bounds_rect);
+ r_bounds[0] = bounds_rect.m_l;
+ r_bounds[1] = bounds_rect.m_t;
+ r_bounds[2] = bounds_rect.m_r;
+ r_bounds[3] = bounds_rect.m_b;
+}
+
GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle,
GHOST_TModifierKeyMask mask,
- int *isDown)
+ bool *r_is_down)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
GHOST_TSuccess result;
- bool isdown = false;
+ bool is_down = false;
- result = system->getModifierKeyState(mask, isdown);
- *isDown = (int)isdown;
+ result = system->getModifierKeyState(mask, is_down);
+ *r_is_down = is_down;
return result;
}
GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle,
GHOST_TButtonMask mask,
- int *isDown)
+ bool *r_is_down)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
GHOST_TSuccess result;
- bool isdown = false;
+ bool is_down = false;
- result = system->getButtonState(mask, isdown);
- *isDown = (int)isdown;
+ result = system->getButtonState(mask, is_down);
+ *r_is_down = is_down;
return result;
}
@@ -412,11 +426,11 @@ void GHOST_setNDOFDeadZone(float deadzone)
}
#endif
-void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, bool canAccept)
+void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, bool can_accept)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- window->setAcceptDragOperation(canAccept);
+ window->setAcceptDragOperation(can_accept);
}
GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle)
@@ -475,11 +489,11 @@ void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle, GHOST_TUs
timertask->setUserData(userdata);
}
-int GHOST_GetValid(GHOST_WindowHandle windowhandle)
+bool GHOST_GetValid(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- return (int)window->getValid();
+ return window->getValid();
}
GHOST_TDrawingContextType GHOST_GetDrawingContextType(GHOST_WindowHandle windowhandle)
@@ -803,19 +817,37 @@ void GHOST_putClipboard(const char *buffer, bool selection)
system->putClipboard(buffer, selection);
}
-int setConsoleWindowState(GHOST_TConsoleWindowState action)
+bool GHOST_setConsoleWindowState(GHOST_TConsoleWindowState action)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
- return system->setConsoleWindowState(action);
+ /* FIXME: use `bool` instead of int for this value. */
+ return (bool)system->setConsoleWindowState(action);
}
-int GHOST_UseNativePixels(void)
+bool GHOST_UseNativePixels(void)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
return system->useNativePixel();
}
-void GHOST_UseWindowFocus(int use_focus)
+bool GHOST_SupportsCursorWarp(void)
+{
+ GHOST_ISystem *system = GHOST_ISystem::getSystem();
+ return system->supportsCursorWarp();
+}
+
+bool GHOST_SupportsWindowPosition(void)
+{
+ GHOST_ISystem *system = GHOST_ISystem::getSystem();
+ return system->supportsWindowPosition();
+}
+
+void GHOST_SetBacktraceHandler(GHOST_TBacktraceFn backtrace_fn)
+{
+ GHOST_ISystem::setBacktraceFn(backtrace_fn);
+}
+
+void GHOST_UseWindowFocus(bool use_focus)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
return system->useWindowFocus(use_focus);
diff --git a/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp b/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp
index 72aeebdc876..9f14d56cd9a 100644
--- a/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp
+++ b/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp
@@ -22,5 +22,5 @@ GHOST_CallbackEventConsumer::GHOST_CallbackEventConsumer(GHOST_EventCallbackProc
bool GHOST_CallbackEventConsumer::processEvent(GHOST_IEvent *event)
{
- return m_eventCallback((GHOST_EventHandle)event, m_userData) != 0;
+ return m_eventCallback((GHOST_EventHandle)event, m_userData);
}
diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp
index baabdc6c521..b4a076e4598 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.cpp
+++ b/intern/ghost/intern/GHOST_ContextGLX.cpp
@@ -105,7 +105,7 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store);
/* -------------------------------------------------------------------- */
- /* Begin Inline Glew */
+ /* Begin Inline GLEW. */
#ifdef USE_GLXEW_INIT_WORKAROUND
const GLubyte *extStart = (GLubyte *)"";
@@ -142,11 +142,11 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
"GLX_EXT_create_context_es2_profile", extStart, extEnd);
# endif /* WITH_GLEW_ES */
- /* End Inline Glew */
+ /* End Inline GLEW. */
/* -------------------------------------------------------------------- */
#else
- /* important to initialize only glxew (_not_ glew),
- * since this breaks w/ Mesa's `swrast`, see: T46431 */
+ /* Important to initialize only glxew (_not_ GLEW),
+ * since this breaks w/ Mesa's `swrast`, see: T46431. */
glxewInit();
#endif /* USE_GLXEW_INIT_WORKAROUND */
@@ -395,7 +395,7 @@ int GHOST_X11_GL_GetAttributes(
return i;
}
-/* excuse inlining part of glew */
+/* Excuse inlining part of GLEW. */
#ifdef USE_GLXEW_INIT_WORKAROUND
static GLuint _glewStrLen(const GLubyte *s)
{
diff --git a/intern/ghost/intern/GHOST_DropTargetX11.cpp b/intern/ghost/intern/GHOST_DropTargetX11.cpp
index 70c2eb8c29e..900e46c3732 100644
--- a/intern/ghost/intern/GHOST_DropTargetX11.cpp
+++ b/intern/ghost/intern/GHOST_DropTargetX11.cpp
@@ -31,7 +31,7 @@ int GHOST_DropTargetX11::m_refCounter = 0;
#define dndTypePlainText m_dndTypes[dndTypePlainTextID]
#define dndTypeOctetStream m_dndTypes[dndTypeOctetStreamID]
-void GHOST_DropTargetX11::Initialize(void)
+void GHOST_DropTargetX11::Initialize()
{
Display *display = m_system->getXDisplay();
int dndTypesCount = sizeof(m_dndMimeTypes) / sizeof(char *);
@@ -60,7 +60,7 @@ void GHOST_DropTargetX11::Initialize(void)
m_dndActions[counter++] = 0;
}
-void GHOST_DropTargetX11::Uninitialize(void)
+void GHOST_DropTargetX11::Uninitialize()
{
xdnd_shut(&m_dndClass);
@@ -98,12 +98,12 @@ GHOST_DropTargetX11::~GHOST_DropTargetX11()
/* Based on: https://stackoverflow.com/a/2766963/432509 */
-typedef enum DecodeState_e {
+using DecodeState_e = enum DecodeState_e {
/** Searching for an ampersand to convert. */
STATE_SEARCH = 0,
/** Convert the two proceeding characters from hex. */
STATE_CONVERTING
-} DecodeState_e;
+};
void GHOST_DropTargetX11::UrlDecode(char *decodedOut, int bufferSize, const char *encodedIn)
{
@@ -122,7 +122,7 @@ void GHOST_DropTargetX11::UrlDecode(char *decodedOut, int bufferSize, const char
case STATE_SEARCH:
if (encodedIn[i] != '%') {
strncat(decodedOut, &encodedIn[i], 1);
- assert(strlen(decodedOut) < bufferSize);
+ assert((int)strlen(decodedOut) < bufferSize);
break;
}
@@ -145,18 +145,19 @@ void GHOST_DropTargetX11::UrlDecode(char *decodedOut, int bufferSize, const char
/* Ensure both characters are hexadecimal */
for (j = 0; j < 2; ++j) {
- if (!isxdigit(tempNumBuf[j]))
+ if (!isxdigit(tempNumBuf[j])) {
bothDigits = false;
+ }
}
- if (!bothDigits)
+ if (!bothDigits) {
break;
-
+ }
/* Convert two hexadecimal characters into one character */
sscanf(tempNumBuf, "%x", &asciiCharacter);
/* Ensure we aren't going to overflow */
- assert(strlen(decodedOut) < bufferSize);
+ assert((int)strlen(decodedOut) < bufferSize);
/* Concatenate this character onto the output */
strncat(decodedOut, (char *)&asciiCharacter, 1);
diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp
index 758938e879e..2620bcc075d 100644
--- a/intern/ghost/intern/GHOST_EventPrinter.cpp
+++ b/intern/ghost/intern/GHOST_EventPrinter.cpp
@@ -12,7 +12,7 @@
#include "GHOST_EventKey.h"
#include <iostream>
-#include <stdio.h>
+#include <cstdio>
bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
{
@@ -20,9 +20,9 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
GHOST_ASSERT(event, "event==0");
- if (event->getType() == GHOST_kEventWindowUpdate)
+ if (event->getType() == GHOST_kEventWindowUpdate) {
return false;
-
+ }
std::cout << "GHOST_EventPrinter::processEvent, time: " << (int32_t)event->getTime()
<< ", type: ";
switch (event->getType()) {
@@ -106,8 +106,9 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
std::cout << " type : GHOST_kDragnDropTypeFilenames,";
std::cout << "\n Received " << strArray->count << " filename"
<< (strArray->count > 1 ? "s:" : ":");
- for (i = 0; i < strArray->count; i++)
+ for (i = 0; i < strArray->count; i++) {
std::cout << "\n File[" << i << "] : " << strArray->strings[i];
+ }
} break;
default:
break;
@@ -117,10 +118,12 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
case GHOST_kEventOpenMainFile: {
GHOST_TEventDataPtr eventData = ((GHOST_IEvent *)event)->getData();
- if (eventData)
+ if (eventData) {
std::cout << "GHOST_kEventOpenMainFile for path : " << (char *)eventData;
- else
+ }
+ else {
std::cout << "GHOST_kEventOpenMainFile with no path specified!!";
+ }
} break;
case GHOST_kEventQuitRequest:
@@ -167,7 +170,7 @@ void GHOST_EventPrinter::getKeyString(GHOST_TKey key, char str[32]) const
sprintf(str, "F%d", key - GHOST_kKeyF1 + 1);
}
else {
- const char *tstr = NULL;
+ const char *tstr = nullptr;
switch (key) {
case GHOST_kKeyBackSpace:
tstr = "BackSpace";
diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp
index 87111306ec7..745d5faeed4 100644
--- a/intern/ghost/intern/GHOST_ISystem.cpp
+++ b/intern/ghost/intern/GHOST_ISystem.cpp
@@ -31,6 +31,8 @@
GHOST_ISystem *GHOST_ISystem::m_system = nullptr;
+GHOST_TBacktraceFn GHOST_ISystem::m_backtrace_fn = nullptr;
+
GHOST_TSuccess GHOST_ISystem::createSystem()
{
GHOST_TSuccess success;
@@ -89,3 +91,13 @@ GHOST_ISystem *GHOST_ISystem::getSystem()
{
return m_system;
}
+
+GHOST_TBacktraceFn GHOST_ISystem::getBacktraceFn()
+{
+ return GHOST_ISystem::m_backtrace_fn;
+}
+
+void GHOST_ISystem::setBacktraceFn(GHOST_TBacktraceFn backtrace_fn)
+{
+ GHOST_ISystem::m_backtrace_fn = backtrace_fn;
+}
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index 7f6b5f53316..2298ba86521 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -6,10 +6,10 @@
#include "GHOST_EventNDOF.h"
#include "GHOST_WindowManager.h"
-#include <limits.h>
-#include <math.h>
-#include <stdio.h> /* For error/info reporting. */
-#include <string.h> /* For memory functions. */
+#include <climits>
+#include <cmath>
+#include <cstdio> /* For error/info reporting. */
+#include <cstring> /* For memory functions. */
#ifdef DEBUG_NDOF_MOTION
/* Printable version of each GHOST_TProgress value. */
@@ -255,8 +255,9 @@ bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ
printf("ndof: unknown device %04hx:%04hx\n", vendor_id, product_id);
}
- if (m_buttonMask == 0)
+ if (m_buttonMask == 0) {
m_buttonMask = (int)~(UINT_MAX << m_buttonCount);
+ }
#ifdef DEBUG_NDOF_BUTTONS
printf("ndof: %d buttons -> hex:%X\n", m_buttonCount, m_buttonMask);
diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
index 7e53ce45f70..7770f5f39ce 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
@@ -32,10 +32,11 @@ GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys)
char line[MAX_LINE_LENGTH] = {0};
while (fgets(line, MAX_LINE_LENGTH, command_output)) {
unsigned short vendor_id = 0, product_id = 0;
- if (sscanf(line, "Bus %*d Device %*d: ID %hx:%hx", &vendor_id, &product_id) == 2)
+ if (sscanf(line, "Bus %*d Device %*d: ID %hx:%hx", &vendor_id, &product_id) == 2) {
if (setDevice(vendor_id, product_id)) {
break; /* stop looking once the first 3D mouse is found */
}
+ }
}
pclose(command_output);
}
@@ -44,8 +45,9 @@ GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys)
GHOST_NDOFManagerUnix::~GHOST_NDOFManagerUnix()
{
- if (m_available)
+ if (m_available) {
spnav_close();
+ }
}
bool GHOST_NDOFManagerUnix::available()
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 1ddf884bbc5..cc8d0915c5a 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -158,7 +158,7 @@ GHOST_TSuccess GHOST_System::updateFullScreen(const GHOST_DisplaySetting &settin
return success;
}
-GHOST_TSuccess GHOST_System::endFullScreen(void)
+GHOST_TSuccess GHOST_System::endFullScreen()
{
GHOST_TSuccess success = GHOST_kFailure;
GHOST_ASSERT(m_windowManager, "GHOST_System::endFullScreen(): invalid window manager");
@@ -177,7 +177,7 @@ GHOST_TSuccess GHOST_System::endFullScreen(void)
return success;
}
-bool GHOST_System::getFullScreen(void)
+bool GHOST_System::getFullScreen()
{
bool fullScreen;
if (m_windowManager) {
@@ -289,7 +289,7 @@ void GHOST_System::setTabletAPI(GHOST_TTabletAPI api)
m_tabletAPI = api;
}
-GHOST_TTabletAPI GHOST_System::getTabletAPI(void)
+GHOST_TTabletAPI GHOST_System::getTabletAPI()
{
return m_tabletAPI;
}
@@ -319,9 +319,7 @@ GHOST_TSuccess GHOST_System::init()
if (m_timerManager && m_windowManager && m_eventManager) {
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_System::exit()
@@ -357,10 +355,12 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
{
GHOST_GLSettings glSettings = {0};
- if (stereoVisual)
+ if (stereoVisual) {
glSettings.flags |= GHOST_glStereoVisual;
- if (alphaBackground)
+ }
+ if (alphaBackground) {
glSettings.flags |= GHOST_glAlphaBackground;
+ }
/* NOTE: don't use #getCurrentDisplaySetting() because on X11 we may
* be zoomed in and the desktop may be bigger than the viewport. */
@@ -390,6 +390,16 @@ void GHOST_System::useWindowFocus(const bool use_focus)
m_windowFocus = use_focus;
}
+bool GHOST_System::supportsCursorWarp()
+{
+ return true;
+}
+
+bool GHOST_System::supportsWindowPosition()
+{
+ return true;
+}
+
void GHOST_System::initDebug(GHOST_Debug debug)
{
m_is_debug_enabled = debug.flags & GHOST_kDebugDefault;
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index 4a3cded1fbd..b60ce09f743 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -151,10 +151,14 @@ class GHOST_System : public GHOST_ISystem {
bool useNativePixel(void);
bool m_nativePixel;
+ bool supportsCursorWarp(void);
+ bool supportsWindowPosition(void);
+
/**
* Focus window after opening, or put them in the background.
*/
void useWindowFocus(const bool use_focus);
+
bool m_windowFocus;
/**
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 7e74287d6e3..2b0abd2cc41 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -29,7 +29,10 @@
#include "GHOST_WaylandCursorSettings.h"
#include <pointer-constraints-client-protocol.h>
#include <relative-pointer-client-protocol.h>
+#include <tablet-client-protocol.h>
#include <wayland-cursor.h>
+#include <xdg-output-client-protocol.h>
+
#include <xkbcommon/xkbcommon.h>
#include <fcntl.h>
@@ -37,6 +40,13 @@
#include <unistd.h>
#include <cstring>
+#include <mutex>
+
+static GHOST_WindowWayland *window_from_surface(struct wl_surface *surface);
+
+/* -------------------------------------------------------------------- */
+/** \name Private Types & Defines
+ * \{ */
/**
* Selected input event code defines from `linux/input-event-codes.h`
@@ -53,102 +63,155 @@
#define BTN_BACK 0x116
// #define BTN_TASK 0x117 /* UNUSED. */
+/**
+ * Tablet events, also from `linux/input-event-codes.h`.
+ */
+#define BTN_STYLUS 0x14b /* Use as right-mouse. */
+#define BTN_STYLUS2 0x14c /* Use as middle-mouse. */
+/* NOTE(@campbellbarton): Map to an additional button (not sure which hardware uses this). */
+#define BTN_STYLUS3 0x149
+
struct buffer_t {
- void *data;
- size_t size;
+ void *data = nullptr;
+ size_t size = 0;
};
struct cursor_t {
- bool visible;
- struct wl_surface *surface = nullptr;
- struct wl_buffer *buffer;
- struct wl_cursor_image image;
+ bool visible = false;
+ struct wl_surface *wl_surface = nullptr;
+ struct wl_buffer *wl_buffer = nullptr;
+ struct wl_cursor_image wl_image = {0};
+ struct wl_cursor_theme *wl_theme = nullptr;
struct buffer_t *file_buffer = nullptr;
- struct wl_cursor_theme *theme = nullptr;
- int size;
+ int size = 0;
std::string theme_name;
- // outputs on which the cursor is visible
+ /** Outputs on which the cursor is visible. */
std::unordered_set<const output_t *> outputs;
int scale = 1;
};
+/**
+ * A single tablet can have multiple tools (pen, eraser, brush... etc).
+ * WAYLAND exposes tools via #zwp_tablet_tool_v2.
+ * Since are no API's to access properties of the tool, store the values here.
+ */
+struct tablet_tool_input_t {
+ struct input_t *input = nullptr;
+ struct wl_surface *cursor_surface = nullptr;
+
+ GHOST_TabletData data = GHOST_TABLET_DATA_NONE;
+};
+
struct data_offer_t {
std::unordered_set<std::string> types;
- uint32_t source_actions;
- uint32_t dnd_action;
- struct wl_data_offer *id;
- std::atomic<bool> in_use;
+ uint32_t source_actions = 0;
+ uint32_t dnd_action = 0;
+ struct wl_data_offer *id = nullptr;
+ std::atomic<bool> in_use = false;
struct {
- int x, y;
+ /** Compatible with #input_t.xy coordinates. */
+ wl_fixed_t xy[2] = {0, 0};
} dnd;
};
struct data_source_t {
- struct wl_data_source *data_source;
- /** Last device that was active. */
- uint32_t source_serial;
- char *buffer_out;
+ struct wl_data_source *data_source = nullptr;
+ char *buffer_out = nullptr;
};
struct key_repeat_payload_t {
- GHOST_SystemWayland *system;
- GHOST_IWindow *window;
- GHOST_TKey key;
- GHOST_TEventKeyData key_data;
+ GHOST_SystemWayland *system = nullptr;
+ GHOST_IWindow *window = nullptr;
+ GHOST_TEventKeyData key_data = {GHOST_kKeyUnknown};
};
struct input_t {
- GHOST_SystemWayland *system;
+ GHOST_SystemWayland *system = nullptr;
std::string name;
- struct wl_seat *seat;
- struct wl_pointer *pointer = nullptr;
- struct wl_keyboard *keyboard = nullptr;
-
- uint32_t pointer_serial;
- int x, y;
- GHOST_Buttons buttons;
+ struct wl_seat *wl_seat = nullptr;
+ struct wl_pointer *wl_pointer = nullptr;
+ struct wl_keyboard *wl_keyboard = nullptr;
+ struct zwp_tablet_seat_v2 *tablet_seat = nullptr;
+
+ /** All currently active tablet tools (needed for changing the cursor). */
+ std::unordered_set<zwp_tablet_tool_v2 *> tablet_tools;
+
+ uint32_t pointer_serial = 0;
+ uint32_t tablet_serial = 0;
+
+ /** Use to check if the last cursor input was tablet or pointer. */
+ uint32_t cursor_serial = 0;
+
+ /**
+ * High precision mouse coordinates (pointer or tablet).
+ *
+ * The following example converts these values to screen coordinates.
+ * \code{.cc}
+ * const wl_fixed_t scale = win->scale();
+ * const int event_xy[2] = {
+ * wl_fixed_to_int(scale * input->xy[0]),
+ * wl_fixed_to_int(scale * input->xy[1]),
+ * };
+ * \endcode
+ */
+ wl_fixed_t xy[2] = {0, 0};
+ GHOST_Buttons buttons = GHOST_Buttons();
struct cursor_t cursor;
- struct zwp_relative_pointer_v1 *relative_pointer;
- struct zwp_locked_pointer_v1 *locked_pointer;
+ struct zwp_relative_pointer_v1 *relative_pointer = nullptr;
+ struct zwp_locked_pointer_v1 *locked_pointer = nullptr;
+ struct zwp_confined_pointer_v1 *confined_pointer = nullptr;
- struct xkb_context *xkb_context;
- struct xkb_state *xkb_state;
+ struct xkb_context *xkb_context = nullptr;
+ struct xkb_state *xkb_state = nullptr;
struct {
- /* Key repetition in character per second. */
- int32_t rate;
- /* Time (milliseconds) after which to start repeating keys. */
- int32_t delay;
- /* Timer for key repeats. */
+ /** Key repetition in character per second. */
+ int32_t rate = 0;
+ /** Time (milliseconds) after which to start repeating keys. */
+ int32_t delay = 0;
+ /** Timer for key repeats. */
GHOST_ITimerTask *timer = nullptr;
} key_repeat;
+ struct wl_surface *focus_tablet = nullptr;
struct wl_surface *focus_pointer = nullptr;
struct wl_surface *focus_keyboard = nullptr;
+ struct wl_surface *focus_dnd = nullptr;
struct wl_data_device *data_device = nullptr;
- struct data_offer_t *data_offer_dnd; /* Drag & Drop. */
- struct data_offer_t *data_offer_copy_paste; /* Copy & Paste. */
+ /** Drag & Drop. */
+ struct data_offer_t *data_offer_dnd = nullptr;
+ std::mutex data_offer_dnd_mutex;
+
+ /** Copy & Paste. */
+ struct data_offer_t *data_offer_copy_paste = nullptr;
+ std::mutex data_offer_copy_paste_mutex;
+
+ struct data_source_t *data_source = nullptr;
+ std::mutex data_source_mutex;
- struct data_source_t *data_source;
+ /** Last device that was active. */
+ uint32_t data_source_serial = 0;
};
struct display_t {
- GHOST_SystemWayland *system;
+ GHOST_SystemWayland *system = nullptr;
- struct wl_display *display;
+ struct wl_display *display = nullptr;
struct wl_compositor *compositor = nullptr;
struct xdg_wm_base *xdg_shell = nullptr;
struct zxdg_decoration_manager_v1 *xdg_decoration_manager = nullptr;
+ struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
struct wl_shm *shm = nullptr;
std::vector<output_t *> outputs;
std::vector<input_t *> inputs;
struct {
std::string theme;
- int size;
+ int size = 0;
} cursor;
struct wl_data_device_manager *data_device_manager = nullptr;
+ struct zwp_tablet_manager_v2 *tablet_manager = nullptr;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr;
struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr;
@@ -156,56 +219,105 @@ struct display_t {
std::vector<struct wl_egl_window *> os_egl_windows;
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Private Utility Functions
+ * \{ */
+
static GHOST_WindowManager *window_manager = nullptr;
+/** Check this lock before accessing `GHOST_SystemWayland::selection` from a thread. */
+static std::mutex system_selection_mutex;
+
+/**
+ * Callback for WAYLAND to run when there is an error.
+ *
+ * \note It's useful to set a break-point on this function as some errors are fatal
+ * (for all intents and purposes) but don't crash the process.
+ */
+static void ghost_wayland_log_handler(const char *msg, va_list arg)
+{
+ fprintf(stderr, "GHOST/Wayland: ");
+ vfprintf(stderr, msg, arg); /* Includes newline. */
+
+ GHOST_TBacktraceFn backtrace_fn = GHOST_ISystem::getBacktraceFn();
+ if (backtrace_fn) {
+ backtrace_fn(stderr); /* Includes newline. */
+ }
+}
+
static void display_destroy(display_t *d)
{
if (d->data_device_manager) {
wl_data_device_manager_destroy(d->data_device_manager);
}
+ if (d->tablet_manager) {
+ zwp_tablet_manager_v2_destroy(d->tablet_manager);
+ }
+
for (output_t *output : d->outputs) {
- wl_output_destroy(output->output);
+ wl_output_destroy(output->wl_output);
delete output;
}
for (input_t *input : d->inputs) {
- if (input->data_source) {
- free(input->data_source->buffer_out);
- if (input->data_source->data_source) {
- wl_data_source_destroy(input->data_source->data_source);
+
+ /* First handle members that require locking.
+ * While highly unlikely, it's possible they are being used while this function runs. */
+ {
+ std::lock_guard lock{input->data_source_mutex};
+ if (input->data_source) {
+ free(input->data_source->buffer_out);
+ if (input->data_source->data_source) {
+ wl_data_source_destroy(input->data_source->data_source);
+ }
+ delete input->data_source;
}
- delete input->data_source;
}
- if (input->data_offer_copy_paste) {
- wl_data_offer_destroy(input->data_offer_copy_paste->id);
- delete input->data_offer_copy_paste;
+
+ {
+ std::lock_guard lock{input->data_offer_dnd_mutex};
+ if (input->data_offer_dnd) {
+ wl_data_offer_destroy(input->data_offer_dnd->id);
+ delete input->data_offer_dnd;
+ }
}
+
+ {
+ std::lock_guard lock{input->data_offer_copy_paste_mutex};
+ if (input->data_offer_copy_paste) {
+ wl_data_offer_destroy(input->data_offer_copy_paste->id);
+ delete input->data_offer_copy_paste;
+ }
+ }
+
if (input->data_device) {
wl_data_device_release(input->data_device);
}
- if (input->pointer) {
+ if (input->wl_pointer) {
if (input->cursor.file_buffer) {
munmap(input->cursor.file_buffer->data, input->cursor.file_buffer->size);
delete input->cursor.file_buffer;
}
- if (input->cursor.surface) {
- wl_surface_destroy(input->cursor.surface);
+ if (input->cursor.wl_surface) {
+ wl_surface_destroy(input->cursor.wl_surface);
}
- if (input->cursor.theme) {
- wl_cursor_theme_destroy(input->cursor.theme);
+ if (input->cursor.wl_theme) {
+ wl_cursor_theme_destroy(input->cursor.wl_theme);
}
- if (input->pointer) {
- wl_pointer_destroy(input->pointer);
+ if (input->wl_pointer) {
+ wl_pointer_destroy(input->wl_pointer);
}
}
- if (input->keyboard) {
+ if (input->wl_keyboard) {
if (input->key_repeat.timer) {
delete static_cast<key_repeat_payload_t *>(input->key_repeat.timer->getUserData());
input->system->removeTimer(input->key_repeat.timer);
input->key_repeat.timer = nullptr;
}
- wl_keyboard_destroy(input->keyboard);
+ wl_keyboard_destroy(input->wl_keyboard);
}
if (input->xkb_state) {
xkb_state_unref(input->xkb_state);
@@ -213,7 +325,7 @@ static void display_destroy(display_t *d)
if (input->xkb_context) {
xkb_context_unref(input->xkb_context);
}
- wl_seat_destroy(input->seat);
+ wl_seat_destroy(input->wl_seat);
delete input;
}
@@ -361,6 +473,27 @@ static GHOST_TKey xkb_map_gkey(const xkb_keysym_t &sym)
return gkey;
}
+static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wl_tablet_tool_type)
+{
+ switch (wl_tablet_tool_type) {
+ case ZWP_TABLET_TOOL_V2_TYPE_ERASER: {
+ return GHOST_kTabletModeEraser;
+ }
+ case ZWP_TABLET_TOOL_V2_TYPE_PEN:
+ case ZWP_TABLET_TOOL_V2_TYPE_BRUSH:
+ case ZWP_TABLET_TOOL_V2_TYPE_PENCIL:
+ case ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH:
+ case ZWP_TABLET_TOOL_V2_TYPE_FINGER:
+ case ZWP_TABLET_TOOL_V2_TYPE_MOUSE:
+ case ZWP_TABLET_TOOL_V2_TYPE_LENS: {
+ return GHOST_kTabletModeStylus;
+ }
+ }
+
+ GHOST_PRINT("unknown tablet tool: " << wl_tablet_tool_type << std::endl);
+ return GHOST_kTabletModeStylus;
+}
+
static const int default_cursor_size = 24;
static const std::unordered_map<GHOST_TStandardCursor, std::string> cursors = {
@@ -429,14 +562,16 @@ static const std::vector<std::string> mime_send = {
"text/plain",
};
+/** \} */
+
/* -------------------------------------------------------------------- */
-/** \name Interface Callbacks
+/** \name Listener (Relative Motion), #zwp_relative_pointer_v1_listener
*
* These callbacks are registered for Wayland interfaces and called when
* an event is received from the compositor.
* \{ */
-static void relative_pointer_relative_motion(
+static void relative_pointer_handle_relative_motion(
void *data,
struct zwp_relative_pointer_v1 * /*zwp_relative_pointer_v1*/,
uint32_t /*utime_hi*/,
@@ -447,42 +582,56 @@ static void relative_pointer_relative_motion(
wl_fixed_t /*dy_unaccel*/)
{
input_t *input = static_cast<input_t *>(data);
-
- input->x += wl_fixed_to_int(dx);
- input->y += wl_fixed_to_int(dy);
-
- GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
- wl_surface_get_user_data(input->focus_pointer));
+ GHOST_WindowWayland *win = window_from_surface(input->focus_pointer);
+ if (!win) {
+ return;
+ }
+ const wl_fixed_t scale = win->scale();
+ input->xy[0] += dx / scale;
+ input->xy[1] += dy / scale;
input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
- input->x,
- input->y,
+ wl_fixed_to_int(scale * input->xy[0]),
+ wl_fixed_to_int(scale * input->xy[1]),
GHOST_TABLET_DATA_NONE));
}
static const zwp_relative_pointer_v1_listener relative_pointer_listener = {
- relative_pointer_relative_motion,
+ relative_pointer_handle_relative_motion,
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Data Source), #wl_data_source_listener
+ * \{ */
+
static void dnd_events(const input_t *const input, const GHOST_TEventType event)
{
+ /* NOTE: `input->data_offer_dnd_mutex` must already be locked. */
const uint64_t time = input->system->getMilliSeconds();
- GHOST_IWindow *const window = static_cast<GHOST_WindowWayland *>(
- wl_surface_get_user_data(input->focus_pointer));
+ GHOST_WindowWayland *const win = static_cast<GHOST_WindowWayland *>(
+ wl_surface_get_user_data(input->focus_dnd));
+ if (!win) {
+ return;
+ }
+ const wl_fixed_t scale = win->scale();
+ const int event_xy[2] = {
+ wl_fixed_to_int(scale * input->data_offer_dnd->dnd.xy[0]),
+ wl_fixed_to_int(scale * input->data_offer_dnd->dnd.xy[1]),
+ };
+
for (const std::string &type : mime_preference_order) {
- input->system->pushEvent(new GHOST_EventDragnDrop(time,
- event,
- mime_dnd.at(type),
- window,
- input->data_offer_dnd->dnd.x,
- input->data_offer_dnd->dnd.y,
- nullptr));
+ input->system->pushEvent(new GHOST_EventDragnDrop(
+ time, event, mime_dnd.at(type), win, event_xy[0], event_xy[1], nullptr));
}
}
-static std::string read_pipe(data_offer_t *data_offer, const std::string mime_receive)
+static std::string read_pipe(data_offer_t *data_offer,
+ const std::string mime_receive,
+ std::mutex *mutex)
{
int pipefd[2];
if (pipe(pipefd) != 0) {
@@ -491,6 +640,13 @@ static std::string read_pipe(data_offer_t *data_offer, const std::string mime_re
wl_data_offer_receive(data_offer->id, mime_receive.c_str(), pipefd[1]);
close(pipefd[1]);
+ data_offer->in_use.store(false);
+
+ if (mutex) {
+ mutex->unlock();
+ }
+ /* WARNING: `data_offer` may be freed from now on. */
+
std::string data;
ssize_t len;
char buffer[4096];
@@ -498,7 +654,6 @@ static std::string read_pipe(data_offer_t *data_offer, const std::string mime_re
data.insert(data.end(), buffer, buffer + len);
}
close(pipefd[0]);
- data_offer->in_use.store(false);
return data;
}
@@ -509,26 +664,29 @@ static std::string read_pipe(data_offer_t *data_offer, const std::string mime_re
* Sent when a target accepts pointer_focus or motion events. If
* a target does not accept any of the offered types, type is nullptr.
*/
-static void data_source_target(void * /*data*/,
- struct wl_data_source * /*wl_data_source*/,
- const char * /*mime_type*/)
+static void data_source_handle_target(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/,
+ const char * /*mime_type*/)
{
/* pass */
}
-static void data_source_send(void *data,
- struct wl_data_source * /*wl_data_source*/,
- const char * /*mime_type*/,
- int32_t fd)
+static void data_source_handle_send(void *data,
+ struct wl_data_source * /*wl_data_source*/,
+ const char * /*mime_type*/,
+ int32_t fd)
{
- const char *const buffer = static_cast<char *>(data);
+ input_t *input = static_cast<input_t *>(data);
+ std::lock_guard lock{input->data_source_mutex};
+
+ const char *const buffer = input->data_source->buffer_out;
if (write(fd, buffer, strlen(buffer)) < 0) {
GHOST_PRINT("error writing to clipboard: " << std::strerror(errno) << std::endl);
}
close(fd);
}
-static void data_source_cancelled(void * /*data*/, struct wl_data_source *wl_data_source)
+static void data_source_handle_cancelled(void * /*data*/, struct wl_data_source *wl_data_source)
{
wl_data_source_destroy(wl_data_source);
}
@@ -540,8 +698,8 @@ static void data_source_cancelled(void * /*data*/, struct wl_data_source *wl_dat
* indicate acceptance, #wl_data_source.cancelled may still be
* emitted afterwards if the drop destination does not accept any mime type.
*/
-static void data_source_dnd_drop_performed(void * /*data*/,
- struct wl_data_source * /*wl_data_source*/)
+static void data_source_handle_dnd_drop_performed(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/)
{
/* pass */
}
@@ -553,7 +711,8 @@ static void data_source_dnd_drop_performed(void * /*data*/,
* source, so the client is now free to destroy this data source
* and free all associated data.
*/
-static void data_source_dnd_finished(void * /*data*/, struct wl_data_source * /*wl_data_source*/)
+static void data_source_handle_dnd_finished(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/)
{
/* pass */
}
@@ -565,73 +724,87 @@ static void data_source_dnd_finished(void * /*data*/, struct wl_data_source * /*
* after matching the source/destination side actions. Only one
* action (or none) will be offered here.
*/
-static void data_source_action(void * /*data*/,
- struct wl_data_source * /*wl_data_source*/,
- uint32_t /*dnd_action*/)
+static void data_source_handle_action(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/,
+ uint32_t /*dnd_action*/)
{
/* pass */
}
static const struct wl_data_source_listener data_source_listener = {
- data_source_target,
- data_source_send,
- data_source_cancelled,
- data_source_dnd_drop_performed,
- data_source_dnd_finished,
- data_source_action,
+ data_source_handle_target,
+ data_source_handle_send,
+ data_source_handle_cancelled,
+ data_source_handle_dnd_drop_performed,
+ data_source_handle_dnd_finished,
+ data_source_handle_action,
};
-static void data_offer_offer(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- const char *mime_type)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Data Offer), #wl_data_offer_listener
+ * \{ */
+
+static void data_offer_handle_offer(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ const char *mime_type)
{
static_cast<data_offer_t *>(data)->types.insert(mime_type);
}
-static void data_offer_source_actions(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- uint32_t source_actions)
+static void data_offer_handle_source_actions(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ uint32_t source_actions)
{
static_cast<data_offer_t *>(data)->source_actions = source_actions;
}
-static void data_offer_action(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- uint32_t dnd_action)
+static void data_offer_handle_action(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ uint32_t dnd_action)
{
static_cast<data_offer_t *>(data)->dnd_action = dnd_action;
}
static const struct wl_data_offer_listener data_offer_listener = {
- data_offer_offer,
- data_offer_source_actions,
- data_offer_action,
+ data_offer_handle_offer,
+ data_offer_handle_source_actions,
+ data_offer_handle_action,
};
-static void data_device_data_offer(void * /*data*/,
- struct wl_data_device * /*wl_data_device*/,
- struct wl_data_offer *id)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Data Device), #wl_data_device_listener
+ * \{ */
+
+static void data_device_handle_data_offer(void * /*data*/,
+ struct wl_data_device * /*wl_data_device*/,
+ struct wl_data_offer *id)
{
data_offer_t *data_offer = new data_offer_t;
data_offer->id = id;
wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
}
-static void data_device_enter(void *data,
- struct wl_data_device * /*wl_data_device*/,
- uint32_t serial,
- struct wl_surface * /*surface*/,
- wl_fixed_t x,
- wl_fixed_t y,
- struct wl_data_offer *id)
+static void data_device_handle_enter(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ uint32_t serial,
+ struct wl_surface *surface,
+ wl_fixed_t x,
+ wl_fixed_t y,
+ struct wl_data_offer *id)
{
input_t *input = static_cast<input_t *>(data);
+ std::lock_guard lock{input->data_offer_dnd_mutex};
+
input->data_offer_dnd = static_cast<data_offer_t *>(wl_data_offer_get_user_data(id));
data_offer_t *data_offer = input->data_offer_dnd;
data_offer->in_use.store(true);
- data_offer->dnd.x = wl_fixed_to_int(x);
- data_offer->dnd.y = wl_fixed_to_int(y);
+ data_offer->dnd.xy[0] = x;
+ data_offer->dnd.xy[1] = y;
wl_data_offer_set_actions(id,
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
@@ -642,14 +815,17 @@ static void data_device_enter(void *data,
wl_data_offer_accept(id, serial, type.c_str());
}
+ input->focus_dnd = surface;
dnd_events(input, GHOST_kEventDraggingEntered);
}
-static void data_device_leave(void *data, struct wl_data_device * /*wl_data_device*/)
+static void data_device_handle_leave(void *data, struct wl_data_device * /*wl_data_device*/)
{
input_t *input = static_cast<input_t *>(data);
+ std::lock_guard lock{input->data_offer_dnd_mutex};
dnd_events(input, GHOST_kEventDraggingExited);
+ input->focus_dnd = nullptr;
if (input->data_offer_dnd && !input->data_offer_dnd->in_use.load()) {
wl_data_offer_destroy(input->data_offer_dnd->id);
@@ -658,21 +834,26 @@ static void data_device_leave(void *data, struct wl_data_device * /*wl_data_devi
}
}
-static void data_device_motion(void *data,
- struct wl_data_device * /*wl_data_device*/,
- uint32_t /*time*/,
- wl_fixed_t x,
- wl_fixed_t y)
+static void data_device_handle_motion(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ uint32_t /*time*/,
+ wl_fixed_t x,
+ wl_fixed_t y)
{
input_t *input = static_cast<input_t *>(data);
- input->data_offer_dnd->dnd.x = wl_fixed_to_int(x);
- input->data_offer_dnd->dnd.y = wl_fixed_to_int(y);
+ std::lock_guard lock{input->data_offer_dnd_mutex};
+
+ input->data_offer_dnd->dnd.xy[0] = x;
+ input->data_offer_dnd->dnd.xy[1] = y;
+
dnd_events(input, GHOST_kEventDraggingUpdated);
}
-static void data_device_drop(void *data, struct wl_data_device * /*wl_data_device*/)
+static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_data_device*/)
{
input_t *input = static_cast<input_t *>(data);
+ std::lock_guard lock{input->data_offer_dnd_mutex};
+
data_offer_t *data_offer = input->data_offer_dnd;
const std::string mime_receive = *std::find_first_of(mime_preference_order.begin(),
@@ -680,13 +861,13 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
data_offer->types.begin(),
data_offer->types.end());
- auto read_uris = [](input_t *const input,
- data_offer_t *data_offer,
- const std::string mime_receive) {
- const int x = data_offer->dnd.x;
- const int y = data_offer->dnd.y;
+ auto read_uris_fn = [](input_t *const input,
+ data_offer_t *data_offer,
+ wl_surface *surface,
+ const std::string mime_receive) {
+ const wl_fixed_t xy[2] = {data_offer->dnd.xy[0], data_offer->dnd.xy[1]};
- const std::string data = read_pipe(data_offer, mime_receive);
+ const std::string data = read_pipe(data_offer, mime_receive, nullptr);
wl_data_offer_finish(data_offer->id);
wl_data_offer_destroy(data_offer->id);
@@ -700,6 +881,9 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
static constexpr const char *file_proto = "file://";
static constexpr const char *crlf = "\r\n";
+ GHOST_WindowWayland *win = window_from_surface(surface);
+ GHOST_ASSERT(win != nullptr, "Unable to find window for drop event from surface");
+
std::vector<std::string> uris;
size_t pos = 0;
@@ -723,14 +907,14 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
flist->strings[i] = static_cast<uint8_t *>(malloc((uris[i].size() + 1) * sizeof(uint8_t)));
memcpy(flist->strings[i], uris[i].data(), uris[i].size() + 1);
}
- GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
- wl_surface_get_user_data(input->focus_pointer));
+
+ const wl_fixed_t scale = win->scale();
system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
GHOST_kEventDraggingDropDone,
GHOST_kDragnDropTypeFilenames,
win,
- x,
- y,
+ wl_fixed_to_int(scale * xy[0]),
+ wl_fixed_to_int(scale * xy[1]),
flist));
}
else if (mime_receive == mime_text_plain || mime_receive == mime_text_utf8) {
@@ -740,15 +924,20 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
wl_display_roundtrip(system->display());
};
- std::thread read_thread(read_uris, input, data_offer, mime_receive);
+ /* Pass in `input->focus_dnd` instead of accessing it from `input` since the leave callback
+ * (#data_device_leave) will clear the value once this function starts. */
+ std::thread read_thread(read_uris_fn, input, data_offer, input->focus_dnd, mime_receive);
read_thread.detach();
}
-static void data_device_selection(void *data,
- struct wl_data_device * /*wl_data_device*/,
- struct wl_data_offer *id)
+static void data_device_handle_selection(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ struct wl_data_offer *id)
{
input_t *input = static_cast<input_t *>(data);
+
+ std::lock_guard lock{input->data_offer_copy_paste_mutex};
+
data_offer_t *data_offer = input->data_offer_copy_paste;
/* Delete old data offer. */
@@ -766,59 +955,76 @@ static void data_device_selection(void *data,
data_offer = static_cast<data_offer_t *>(wl_data_offer_get_user_data(id));
input->data_offer_copy_paste = data_offer;
- std::string mime_receive;
- for (const std::string type : {mime_text_utf8, mime_text_plain}) {
- if (data_offer->types.count(type)) {
- mime_receive = type;
- break;
+ auto read_selection_fn = [](input_t *input) {
+ GHOST_SystemWayland *const system = input->system;
+ input->data_offer_copy_paste_mutex.lock();
+
+ data_offer_t *data_offer = input->data_offer_copy_paste;
+ std::string mime_receive;
+ for (const std::string type : {mime_text_utf8, mime_text_plain}) {
+ if (data_offer->types.count(type)) {
+ mime_receive = type;
+ break;
+ }
}
- }
+ const std::string data = read_pipe(
+ data_offer, mime_receive, &input->data_offer_copy_paste_mutex);
- auto read_selection = [](GHOST_SystemWayland *const system,
- data_offer_t *data_offer,
- const std::string mime_receive) {
- const std::string data = read_pipe(data_offer, mime_receive);
- system->setSelection(data);
+ {
+ std::lock_guard lock{system_selection_mutex};
+ system->setSelection(data);
+ }
};
- std::thread read_thread(read_selection, input->system, data_offer, mime_receive);
+ std::thread read_thread(read_selection_fn, input);
read_thread.detach();
}
static const struct wl_data_device_listener data_device_listener = {
- data_device_data_offer,
- data_device_enter,
- data_device_leave,
- data_device_motion,
- data_device_drop,
- data_device_selection,
+ data_device_handle_data_offer,
+ data_device_handle_enter,
+ data_device_handle_leave,
+ data_device_handle_motion,
+ data_device_handle_drop,
+ data_device_handle_selection,
};
-static void cursor_buffer_release(void *data, struct wl_buffer *wl_buffer)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Buffer), #wl_buffer_listener
+ * \{ */
+
+static void cursor_buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
{
cursor_t *cursor = static_cast<cursor_t *>(data);
wl_buffer_destroy(wl_buffer);
- if (wl_buffer == cursor->buffer) {
+ if (wl_buffer == cursor->wl_buffer) {
/* the mapped buffer was from a custom cursor */
- cursor->buffer = nullptr;
+ cursor->wl_buffer = nullptr;
}
}
const struct wl_buffer_listener cursor_buffer_listener = {
- cursor_buffer_release,
+ cursor_buffer_handle_release,
};
-static GHOST_IWindow *get_window(struct wl_surface *surface)
-{
- if (!surface) {
- return nullptr;
- }
+/** \} */
- for (GHOST_IWindow *win : window_manager->getWindows()) {
- if (surface == static_cast<const GHOST_WindowWayland *>(win)->surface()) {
- return win;
+/* -------------------------------------------------------------------- */
+/** \name Listener (Surface), #wl_surface_listener
+ * \{ */
+
+static GHOST_WindowWayland *window_from_surface(struct wl_surface *surface)
+{
+ if (surface) {
+ for (GHOST_IWindow *iwin : window_manager->getWindows()) {
+ GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(iwin);
+ if (surface == win->surface()) {
+ return win;
+ }
}
}
return nullptr;
@@ -835,34 +1041,34 @@ static bool update_cursor_scale(cursor_t &cursor, wl_shm *shm)
if (scale > 0 && cursor.scale != scale) {
cursor.scale = scale;
- wl_surface_set_buffer_scale(cursor.surface, scale);
- wl_cursor_theme_destroy(cursor.theme);
- cursor.theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm);
+ wl_surface_set_buffer_scale(cursor.wl_surface, scale);
+ wl_cursor_theme_destroy(cursor.wl_theme);
+ cursor.wl_theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm);
return true;
}
return false;
}
-static void cursor_surface_enter(void *data,
- struct wl_surface * /*wl_surface*/,
- struct wl_output *output)
+static void cursor_surface_handle_enter(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
{
input_t *input = static_cast<input_t *>(data);
for (const output_t *reg_output : input->system->outputs()) {
- if (reg_output->output == output) {
+ if (reg_output->wl_output == output) {
input->cursor.outputs.insert(reg_output);
}
}
update_cursor_scale(input->cursor, input->system->shm());
}
-static void cursor_surface_leave(void *data,
- struct wl_surface * /*wl_surface*/,
- struct wl_output *output)
+static void cursor_surface_handle_leave(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
{
input_t *input = static_cast<input_t *>(data);
for (const output_t *reg_output : input->system->outputs()) {
- if (reg_output->output == output) {
+ if (reg_output->wl_output == output) {
input->cursor.outputs.erase(reg_output);
}
}
@@ -870,19 +1076,24 @@ static void cursor_surface_leave(void *data,
}
struct wl_surface_listener cursor_surface_listener = {
- cursor_surface_enter,
- cursor_surface_leave,
+ cursor_surface_handle_enter,
+ cursor_surface_handle_leave,
};
-static void pointer_enter(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t serial,
- struct wl_surface *surface,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
-{
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(surface));
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Listener (Pointer), #wl_pointer_listener
+ * \{ */
+
+static void pointer_handle_enter(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t serial,
+ struct wl_surface *surface,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
+{
+ GHOST_WindowWayland *win = window_from_surface(surface);
if (!win) {
return;
}
@@ -891,27 +1102,28 @@ static void pointer_enter(void *data,
input_t *input = static_cast<input_t *>(data);
input->pointer_serial = serial;
- input->x = win->scale() * wl_fixed_to_int(surface_x);
- input->y = win->scale() * wl_fixed_to_int(surface_y);
+ input->cursor_serial = serial;
+ input->xy[0] = surface_x;
+ input->xy[1] = surface_y;
input->focus_pointer = surface;
win->setCursorShape(win->getCursorShape());
+ const wl_fixed_t scale = win->scale();
input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
GHOST_kEventCursorMove,
static_cast<GHOST_WindowWayland *>(win),
- input->x,
- input->y,
+ wl_fixed_to_int(scale * input->xy[0]),
+ wl_fixed_to_int(scale * input->xy[1]),
GHOST_TABLET_DATA_NONE));
}
-static void pointer_leave(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t /*serial*/,
- struct wl_surface *surface)
+static void pointer_handle_leave(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*serial*/,
+ struct wl_surface *surface)
{
- GHOST_IWindow *win = get_window(surface);
-
+ GHOST_IWindow *win = window_from_surface(surface);
if (!win) {
return;
}
@@ -920,42 +1132,39 @@ static void pointer_leave(void *data,
static_cast<GHOST_WindowWayland *>(win)->deactivate();
}
-static void pointer_motion(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t /*time*/,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
+static void pointer_handle_motion(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*time*/,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
{
input_t *input = static_cast<input_t *>(data);
-
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_pointer));
-
+ GHOST_WindowWayland *win = window_from_surface(input->focus_pointer);
if (!win) {
return;
}
- input->x = win->scale() * wl_fixed_to_int(surface_x);
- input->y = win->scale() * wl_fixed_to_int(surface_y);
+ input->xy[0] = surface_x;
+ input->xy[1] = surface_y;
+ const wl_fixed_t scale = win->scale();
input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
- input->x,
- input->y,
+ wl_fixed_to_int(scale * input->xy[0]),
+ wl_fixed_to_int(scale * input->xy[1]),
GHOST_TABLET_DATA_NONE));
}
-static void pointer_button(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t serial,
- uint32_t /*time*/,
- uint32_t button,
- uint32_t state)
+static void pointer_handle_button(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t serial,
+ uint32_t /*time*/,
+ uint32_t button,
+ uint32_t state)
{
input_t *input = static_cast<input_t *>(data);
-
- GHOST_IWindow *win = get_window(input->focus_pointer);
-
+ GHOST_IWindow *win = window_from_surface(input->focus_pointer);
if (!win) {
return;
}
@@ -995,22 +1204,20 @@ static void pointer_button(void *data,
break;
}
- input->data_source->source_serial = serial;
+ input->data_source_serial = serial;
input->buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED);
input->system->pushEvent(new GHOST_EventButton(
input->system->getMilliSeconds(), etype, win, ebutton, GHOST_TABLET_DATA_NONE));
}
-static void pointer_axis(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t /*time*/,
- uint32_t axis,
- wl_fixed_t value)
+static void pointer_handle_axis(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*time*/,
+ uint32_t axis,
+ wl_fixed_t value)
{
input_t *input = static_cast<input_t *>(data);
-
- GHOST_IWindow *win = get_window(input->focus_pointer);
-
+ GHOST_IWindow *win = window_from_surface(input->focus_pointer);
if (!win) {
return;
}
@@ -1024,14 +1231,358 @@ static void pointer_axis(void *data,
}
static const struct wl_pointer_listener pointer_listener = {
- pointer_enter,
- pointer_leave,
- pointer_motion,
- pointer_button,
- pointer_axis,
+ pointer_handle_enter,
+ pointer_handle_leave,
+ pointer_handle_motion,
+ pointer_handle_button,
+ pointer_handle_axis,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Tablet Tool), #zwp_tablet_tool_v2_listener
+ * \{ */
+
+static void tablet_tool_handle_type(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t tool_type)
+{
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+
+ tool_input->data.Active = tablet_tool_map_type((enum zwp_tablet_tool_v2_type)tool_type);
+}
+
+static void tablet_tool_handle_hardware_serial(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t /*hardware_serial_hi*/,
+ uint32_t /*hardware_serial_lo*/)
+{
+}
+
+static void tablet_tool_handle_hardware_id_wacom(
+ void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t /*hardware_id_hi*/,
+ uint32_t /*hardware_id_lo*/)
+{
+}
+
+static void tablet_tool_handle_capability(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t /*capability*/)
+{
+}
+
+static void tablet_tool_handle_done(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+{
+}
+static void tablet_tool_handle_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2)
+{
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+
+ if (tool_input->cursor_surface) {
+ wl_surface_destroy(tool_input->cursor_surface);
+ }
+ input->tablet_tools.erase(zwp_tablet_tool_v2);
+
+ delete tool_input;
+}
+static void tablet_tool_handle_proximity_in(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t serial,
+ struct zwp_tablet_v2 * /*tablet*/,
+ struct wl_surface *surface)
+{
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+
+ input->focus_tablet = surface;
+ input->tablet_serial = serial;
+ input->cursor_serial = serial;
+
+ input->data_source_serial = serial;
+
+ /* Update #GHOST_TabletData. */
+ GHOST_TabletData &td = tool_input->data;
+ /* Reset, to avoid using stale tilt/pressure. */
+ td.Xtilt = 0.0f;
+ td.Ytilt = 0.0f;
+ /* In case pressure isn't supported. */
+ td.Pressure = 1.0f;
+
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
+ if (!win) {
+ return;
+ }
+ win->activate();
+
+ win->setCursorShape(win->getCursorShape());
+}
+static void tablet_tool_handle_proximity_out(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+{
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+ input->focus_tablet = nullptr;
+
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
+ if (!win) {
+ return;
+ }
+ win->setCursorShape(win->getCursorShape());
+}
+
+static void tablet_tool_handle_down(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t serial)
+{
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
+ if (!win) {
+ return;
+ }
+
+ const GHOST_TEventType etype = GHOST_kEventButtonDown;
+ const GHOST_TButtonMask ebutton = GHOST_kButtonMaskLeft;
+ input->data_source_serial = serial;
+ input->buttons.set(ebutton, true);
+ input->system->pushEvent(new GHOST_EventButton(
+ input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data));
+}
+
+static void tablet_tool_handle_up(void *data, struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+{
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
+ if (!win) {
+ return;
+ }
+
+ const GHOST_TEventType etype = GHOST_kEventButtonUp;
+ const GHOST_TButtonMask ebutton = GHOST_kButtonMaskLeft;
+ input->buttons.set(ebutton, false);
+ input->system->pushEvent(new GHOST_EventButton(
+ input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data));
+}
+
+static void tablet_tool_handle_motion(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
+ if (!win) {
+ return;
+ }
+
+ input->xy[0] = x;
+ input->xy[1] = y;
+
+ const wl_fixed_t scale = win->scale();
+ input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ win,
+ wl_fixed_to_int(scale * input->xy[0]),
+ wl_fixed_to_int(scale * input->xy[1]),
+ tool_input->data));
+}
+
+static void tablet_tool_handle_pressure(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t pressure)
+{
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
+ if (!win) {
+ return;
+ }
+
+ GHOST_TabletData &td = tool_input->data;
+ td.Pressure = (float)pressure / 65535;
+}
+static void tablet_tool_handle_distance(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t /*distance*/)
+{
+}
+static void tablet_tool_handle_tilt(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ wl_fixed_t tilt_x,
+ wl_fixed_t tilt_y)
+{
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
+ if (!win) {
+ return;
+ }
+
+ GHOST_TabletData &td = tool_input->data;
+ /* Map degrees to `-1.0..1.0`. */
+ td.Xtilt = wl_fixed_to_double(tilt_x) / 90.0f;
+ td.Ytilt = wl_fixed_to_double(tilt_y) / 90.0f;
+ td.Xtilt = td.Xtilt < -1.0f ? -1.0f : (td.Xtilt > 1.0f ? 1.0f : td.Xtilt);
+ td.Ytilt = td.Ytilt < -1.0f ? -1.0f : (td.Ytilt > 1.0f ? 1.0f : td.Ytilt);
+}
+
+static void tablet_tool_handle_rotation(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ wl_fixed_t /*degrees*/)
+{
+ /* Pass. */
+}
+
+static void tablet_tool_handle_slider(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ int32_t /*position*/)
+{
+ /* Pass. */
+}
+static void tablet_tool_handle_wheel(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ wl_fixed_t /*degrees*/,
+ int32_t clicks)
+{
+ if (clicks == 0) {
+ return;
+ }
+
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
+ if (!win) {
+ return;
+ }
+
+ input->system->pushEvent(new GHOST_EventWheel(input->system->getMilliSeconds(), win, clicks));
+}
+static void tablet_tool_handle_button(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t serial,
+ uint32_t button,
+ uint32_t state)
+{
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
+ if (!win) {
+ return;
+ }
+
+ GHOST_TEventType etype = GHOST_kEventUnknown;
+ switch (state) {
+ case WL_POINTER_BUTTON_STATE_RELEASED:
+ etype = GHOST_kEventButtonUp;
+ break;
+ case WL_POINTER_BUTTON_STATE_PRESSED:
+ etype = GHOST_kEventButtonDown;
+ break;
+ }
+
+ GHOST_TButtonMask ebutton = GHOST_kButtonMaskLeft;
+ switch (button) {
+ case BTN_STYLUS:
+ ebutton = GHOST_kButtonMaskRight;
+ break;
+ case BTN_STYLUS2:
+ ebutton = GHOST_kButtonMaskMiddle;
+ break;
+ case BTN_STYLUS3:
+ ebutton = GHOST_kButtonMaskButton4;
+ break;
+ }
+
+ input->data_source_serial = serial;
+ input->buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED);
+ input->system->pushEvent(new GHOST_EventButton(
+ input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data));
+}
+static void tablet_tool_handle_frame(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t /*time*/)
+{
+}
+
+static const struct zwp_tablet_tool_v2_listener tablet_tool_listner = {
+ tablet_tool_handle_type,
+ tablet_tool_handle_hardware_serial,
+ tablet_tool_handle_hardware_id_wacom,
+ tablet_tool_handle_capability,
+ tablet_tool_handle_done,
+ tablet_tool_handle_removed,
+ tablet_tool_handle_proximity_in,
+ tablet_tool_handle_proximity_out,
+ tablet_tool_handle_down,
+ tablet_tool_handle_up,
+ tablet_tool_handle_motion,
+ tablet_tool_handle_pressure,
+ tablet_tool_handle_distance,
+ tablet_tool_handle_tilt,
+ tablet_tool_handle_rotation,
+ tablet_tool_handle_slider,
+ tablet_tool_handle_wheel,
+ tablet_tool_handle_button,
+ tablet_tool_handle_frame,
};
-static void keyboard_keymap(
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Table Seat), #zwp_tablet_seat_v2_listener
+ * \{ */
+
+static void tablet_seat_handle_tablet_added(void * /*data*/,
+ struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
+ struct zwp_tablet_v2 * /*id*/)
+{
+ /* Pass. */
+}
+
+static void tablet_seat_handle_tool_added(void *data,
+ struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
+ struct zwp_tablet_tool_v2 *id)
+{
+ input_t *input = static_cast<input_t *>(data);
+ tablet_tool_input_t *tool_input = new tablet_tool_input_t();
+ tool_input->input = input;
+
+ /* Every tool has it's own cursor surface. */
+ tool_input->cursor_surface = wl_compositor_create_surface(input->system->compositor());
+ wl_surface_add_listener(tool_input->cursor_surface, &cursor_surface_listener, (void *)input);
+
+ zwp_tablet_tool_v2_add_listener(id, &tablet_tool_listner, tool_input);
+
+ input->tablet_tools.insert(id);
+}
+
+static void tablet_seat_handle_pad_added(void * /*data*/,
+ struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
+ struct zwp_tablet_pad_v2 * /*id*/)
+{
+ /* Pass. */
+}
+
+const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
+ tablet_seat_handle_tablet_added,
+ tablet_seat_handle_tool_added,
+ tablet_seat_handle_pad_added,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Keyboard), #wl_keyboard_listener
+ * \{ */
+
+static void keyboard_handle_keymap(
void *data, struct wl_keyboard * /*wl_keyboard*/, uint32_t format, int32_t fd, uint32_t size)
{
input_t *input = static_cast<input_t *>(data);
@@ -1056,8 +1607,13 @@ static void keyboard_keymap(
return;
}
- input->xkb_state = xkb_state_new(keymap);
-
+ struct xkb_state *xkb_state_next = xkb_state_new(keymap);
+ if (xkb_state_next) {
+ if (input->xkb_state) {
+ xkb_state_unref(input->xkb_state);
+ }
+ input->xkb_state = xkb_state_next;
+ }
xkb_keymap_unref(keymap);
}
@@ -1067,11 +1623,11 @@ static void keyboard_keymap(
* Notification that this seat's keyboard focus is on a certain
* surface.
*/
-static void keyboard_enter(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t /*serial*/,
- struct wl_surface *surface,
- struct wl_array * /*keys*/)
+static void keyboard_handle_enter(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ struct wl_surface *surface,
+ struct wl_array * /*keys*/)
{
if (surface != nullptr) {
static_cast<input_t *>(data)->focus_keyboard = surface;
@@ -1084,10 +1640,10 @@ static void keyboard_enter(void *data,
* Notification that this seat's keyboard focus is no longer on a
* certain surface.
*/
-static void keyboard_leave(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t /*serial*/,
- struct wl_surface *surface)
+static void keyboard_handle_leave(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ struct wl_surface *surface)
{
if (surface != nullptr) {
static_cast<input_t *>(data)->focus_keyboard = nullptr;
@@ -1120,12 +1676,12 @@ static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers(struct xkb_state
return sym;
}
-static void keyboard_key(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t serial,
- uint32_t /*time*/,
- uint32_t key,
- uint32_t state)
+static void keyboard_handle_key(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t serial,
+ uint32_t /*time*/,
+ uint32_t key,
+ uint32_t state)
{
input_t *input = static_cast<input_t *>(data);
@@ -1144,7 +1700,6 @@ static void keyboard_key(void *data,
if (sym == XKB_KEY_NoSymbol) {
return;
}
- const GHOST_TKey gkey = xkb_map_gkey(sym);
/* Delete previous timer. */
if (xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key + 8) &&
@@ -1154,7 +1709,9 @@ static void keyboard_key(void *data,
input->key_repeat.timer = nullptr;
}
- GHOST_TEventKeyData key_data;
+ GHOST_TEventKeyData key_data = {
+ .key = xkb_map_gkey(sym),
+ };
if (etype == GHOST_kEventKeyDown) {
xkb_state_key_get_utf8(
@@ -1164,12 +1721,12 @@ static void keyboard_key(void *data,
key_data.utf8_buf[0] = '\0';
}
- input->data_source->source_serial = serial;
+ input->data_source_serial = serial;
GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
wl_surface_get_user_data(input->focus_keyboard));
input->system->pushEvent(new GHOST_EventKey(
- input->system->getMilliSeconds(), etype, win, gkey, '\0', key_data.utf8_buf, false));
+ input->system->getMilliSeconds(), etype, win, key_data.key, '\0', key_data.utf8_buf, false));
/* Start timer for repeating key, if applicable. */
if (input->key_repeat.rate > 0 &&
@@ -1179,33 +1736,32 @@ static void keyboard_key(void *data,
key_repeat_payload_t *payload = new key_repeat_payload_t({
.system = input->system,
.window = win,
- .key = gkey,
.key_data = key_data,
});
- auto cb = [](GHOST_ITimerTask *task, uint64_t /*time*/) {
+ auto key_repeat_fn = [](GHOST_ITimerTask *task, uint64_t /*time*/) {
struct key_repeat_payload_t *payload = static_cast<key_repeat_payload_t *>(
task->getUserData());
payload->system->pushEvent(new GHOST_EventKey(payload->system->getMilliSeconds(),
GHOST_kEventKeyDown,
payload->window,
- payload->key,
+ payload->key_data.key,
'\0',
payload->key_data.utf8_buf,
true));
};
input->key_repeat.timer = input->system->installTimer(
- input->key_repeat.delay, 1000 / input->key_repeat.rate, cb, payload);
+ input->key_repeat.delay, 1000 / input->key_repeat.rate, key_repeat_fn, payload);
}
}
-static void keyboard_modifiers(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t /*serial*/,
- uint32_t mods_depressed,
- uint32_t mods_latched,
- uint32_t mods_locked,
- uint32_t group)
+static void keyboard_handle_modifiers(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ uint32_t mods_depressed,
+ uint32_t mods_latched,
+ uint32_t mods_locked,
+ uint32_t group)
{
xkb_state_update_mask(static_cast<input_t *>(data)->xkb_state,
mods_depressed,
@@ -1216,10 +1772,10 @@ static void keyboard_modifiers(void *data,
group);
}
-static void keyboard_repeat_info(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- int32_t rate,
- int32_t delay)
+static void keyboard_repeat_handle_info(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ int32_t rate,
+ int32_t delay)
{
input_t *input = static_cast<input_t *>(data);
@@ -1228,79 +1784,172 @@ static void keyboard_repeat_info(void *data,
}
static const struct wl_keyboard_listener keyboard_listener = {
- keyboard_keymap,
- keyboard_enter,
- keyboard_leave,
- keyboard_key,
- keyboard_modifiers,
- keyboard_repeat_info,
+ keyboard_handle_keymap,
+ keyboard_handle_enter,
+ keyboard_handle_leave,
+ keyboard_handle_key,
+ keyboard_handle_modifiers,
+ keyboard_repeat_handle_info,
};
-static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Seat), #wl_seat_listener
+ * \{ */
+
+static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
{
input_t *input = static_cast<input_t *>(data);
- input->pointer = nullptr;
- input->keyboard = nullptr;
+ input->wl_pointer = nullptr;
+ input->wl_keyboard = nullptr;
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
- input->pointer = wl_seat_get_pointer(wl_seat);
- input->cursor.surface = wl_compositor_create_surface(input->system->compositor());
+ input->wl_pointer = wl_seat_get_pointer(wl_seat);
+ input->cursor.wl_surface = wl_compositor_create_surface(input->system->compositor());
input->cursor.visible = true;
- input->cursor.buffer = nullptr;
+ input->cursor.wl_buffer = nullptr;
input->cursor.file_buffer = new buffer_t;
if (!get_cursor_settings(input->cursor.theme_name, input->cursor.size)) {
input->cursor.theme_name = std::string();
input->cursor.size = default_cursor_size;
}
- wl_pointer_add_listener(input->pointer, &pointer_listener, data);
- wl_surface_add_listener(input->cursor.surface, &cursor_surface_listener, data);
+ wl_pointer_add_listener(input->wl_pointer, &pointer_listener, data);
+ wl_surface_add_listener(input->cursor.wl_surface, &cursor_surface_listener, data);
}
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
- input->keyboard = wl_seat_get_keyboard(wl_seat);
- wl_keyboard_add_listener(input->keyboard, &keyboard_listener, data);
+ input->wl_keyboard = wl_seat_get_keyboard(wl_seat);
+ wl_keyboard_add_listener(input->wl_keyboard, &keyboard_listener, data);
}
}
-static void seat_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
+static void seat_handle_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
{
static_cast<input_t *>(data)->name = std::string(name);
}
static const struct wl_seat_listener seat_listener = {
- seat_capabilities,
- seat_name,
+ seat_handle_capabilities,
+ seat_handle_name,
};
-static void output_geometry(void *data,
- struct wl_output * /*wl_output*/,
- int32_t /*x*/,
- int32_t /*y*/,
- int32_t physical_width,
- int32_t physical_height,
- int32_t /*subpixel*/,
- const char *make,
- const char *model,
- int32_t transform)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Output), #zxdg_output_v1_listener
+ * \{ */
+
+static void xdg_output_handle_logical_position(void *data,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ int32_t x,
+ int32_t y)
+{
+ output_t *output = static_cast<output_t *>(data);
+ output->position_logical[0] = x;
+ output->position_logical[1] = y;
+ output->has_position_logical = true;
+}
+
+static void xdg_output_handle_logical_size(void *data,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ int32_t width,
+ int32_t height)
+{
+ output_t *output = static_cast<output_t *>(data);
+
+ if (output->size_logical[0] != 0 && output->size_logical[1] != 0) {
+ /* Original comment from SDL. */
+ /* FIXME(@flibit): GNOME has a bug where the logical size does not account for
+ * scale, resulting in bogus viewport sizes.
+ *
+ * Until this is fixed, validate that _some_ kind of scaling is being
+ * done (we can't match exactly because fractional scaling can't be
+ * detected otherwise), then override if necessary. */
+ if ((output->size_logical[0] == width) && (output->scale_fractional == wl_fixed_from_int(1))) {
+ GHOST_PRINT("xdg_output scale did not match, overriding with wl_output scale");
+ return;
+ }
+ }
+
+ output->size_logical[0] = width;
+ output->size_logical[1] = height;
+ output->has_size_logical = true;
+}
+
+static void xdg_output_handle_done(void * /*data*/, struct zxdg_output_v1 * /*xdg_output*/)
+{
+ /* NOTE: `xdg-output.done` events are deprecated and only apply below version 3 of the protocol.
+ * `wl-output.done` event will be emitted in version 3 or higher. */
+}
+
+static void xdg_output_handle_name(void * /*data*/,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ const char * /*name*/)
+{
+ /* Pass. */
+}
+
+static void xdg_output_handle_description(void * /*data*/,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ const char * /*description*/)
+{
+ /* Pass. */
+}
+
+static const struct zxdg_output_v1_listener xdg_output_listener = {
+ xdg_output_handle_logical_position,
+ xdg_output_handle_logical_size,
+ xdg_output_handle_done,
+ xdg_output_handle_name,
+ xdg_output_handle_description,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Output), #wl_output_listener
+ * \{ */
+
+static void output_handle_geometry(void *data,
+ struct wl_output * /*wl_output*/,
+ int32_t /*x*/,
+ int32_t /*y*/,
+ int32_t physical_width,
+ int32_t physical_height,
+ int32_t /*subpixel*/,
+ const char *make,
+ const char *model,
+ int32_t transform)
{
output_t *output = static_cast<output_t *>(data);
output->transform = transform;
output->make = std::string(make);
output->model = std::string(model);
- output->width_mm = physical_width;
- output->height_mm = physical_height;
+ output->size_mm[0] = physical_width;
+ output->size_mm[1] = physical_height;
}
-static void output_mode(void *data,
- struct wl_output * /*wl_output*/,
- uint32_t /*flags*/,
- int32_t width,
- int32_t height,
- int32_t /*refresh*/)
+static void output_handle_mode(void *data,
+ struct wl_output * /*wl_output*/,
+ uint32_t flags,
+ int32_t width,
+ int32_t height,
+ int32_t /*refresh*/)
{
output_t *output = static_cast<output_t *>(data);
- output->width_pxl = width;
- output->height_pxl = height;
+
+ if (flags & WL_OUTPUT_MODE_CURRENT) {
+ output->size_native[0] = width;
+ output->size_native[1] = height;
+
+ /* Don't rotate this yet, `wl-output` coordinates are transformed in
+ * handle_done and `xdg-output` coordinates are pre-transformed. */
+ if (!output->has_size_logical) {
+ output->size_logical[0] = width;
+ output->size_logical[1] = height;
+ }
+ }
}
/**
@@ -1311,36 +1960,71 @@ static void output_mode(void *data,
* changes done after that. This allows changes to the output
* properties to be seen as atomic, even if they happen via multiple events.
*/
-static void output_done(void * /*data*/, struct wl_output * /*wl_output*/)
+static void output_handle_done(void *data, struct wl_output * /*wl_output*/)
{
+ output_t *output = static_cast<output_t *>(data);
+ int32_t size_native[2];
+ if (output->transform & WL_OUTPUT_TRANSFORM_90) {
+ size_native[0] = output->size_native[1];
+ size_native[1] = output->size_native[1];
+ }
+ else {
+ size_native[0] = output->size_native[0];
+ size_native[1] = output->size_native[1];
+ }
+
+ /* If `xdg-output` is present, calculate the true scale of the desktop */
+ if (output->has_size_logical) {
+
+ /* NOTE: it's not necessary to divide these values by their greatest-common-denominator
+ * as even a 64k screen resolution doesn't approach overflowing an `int32_t`. */
+
+ GHOST_ASSERT(size_native[0] && output->size_logical[0],
+ "Screen size values were not set when they were expected to be.");
+
+ output->scale_fractional = wl_fixed_from_int(size_native[0]) / output->size_logical[0];
+ output->has_scale_fractional = true;
+ }
}
-static void output_scale(void *data, struct wl_output * /*wl_output*/, int32_t factor)
+static void output_handle_scale(void *data, struct wl_output * /*wl_output*/, int32_t factor)
{
static_cast<output_t *>(data)->scale = factor;
}
static const struct wl_output_listener output_listener = {
- output_geometry,
- output_mode,
- output_done,
- output_scale,
+ output_handle_geometry,
+ output_handle_mode,
+ output_handle_done,
+ output_handle_scale,
};
-static void shell_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG WM Base), #xdg_wm_base_listener
+ * \{ */
+
+static void shell_handle_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
{
xdg_wm_base_pong(xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener shell_listener = {
- shell_ping,
+ shell_handle_ping,
};
-static void global_add(void *data,
- struct wl_registry *wl_registry,
- uint32_t name,
- const char *interface,
- uint32_t /*version*/)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Registry), #wl_registry_listener
+ * \{ */
+
+static void global_handle_add(void *data,
+ struct wl_registry *wl_registry,
+ uint32_t name,
+ const char *interface,
+ uint32_t /*version*/)
{
struct display_t *display = static_cast<struct display_t *>(data);
if (!strcmp(interface, wl_compositor_interface.name)) {
@@ -1356,30 +2040,37 @@ static void global_add(void *data,
display->xdg_decoration_manager = static_cast<zxdg_decoration_manager_v1 *>(
wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1));
}
+ else if (!strcmp(interface, zxdg_output_manager_v1_interface.name)) {
+ display->xdg_output_manager = static_cast<zxdg_output_manager_v1 *>(
+ wl_registry_bind(wl_registry, name, &zxdg_output_manager_v1_interface, 3));
+ for (output_t *output : display->outputs) {
+ output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
+ output->wl_output);
+ zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
+ }
+ }
else if (!strcmp(interface, wl_output_interface.name)) {
output_t *output = new output_t;
- output->scale = 1;
- output->output = static_cast<wl_output *>(
+ output->wl_output = static_cast<wl_output *>(
wl_registry_bind(wl_registry, name, &wl_output_interface, 2));
display->outputs.push_back(output);
- wl_output_add_listener(output->output, &output_listener, output);
+ wl_output_add_listener(output->wl_output, &output_listener, output);
+
+ if (display->xdg_output_manager) {
+ output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
+ output->wl_output);
+ zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
+ }
}
else if (!strcmp(interface, wl_seat_interface.name)) {
input_t *input = new input_t;
input->system = display->system;
input->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
- input->xkb_state = nullptr;
- input->data_offer_dnd = nullptr;
- input->data_offer_copy_paste = nullptr;
input->data_source = new data_source_t;
- input->data_source->data_source = nullptr;
- input->data_source->buffer_out = nullptr;
- input->relative_pointer = nullptr;
- input->locked_pointer = nullptr;
- input->seat = static_cast<wl_seat *>(
+ input->wl_seat = static_cast<wl_seat *>(
wl_registry_bind(wl_registry, name, &wl_seat_interface, 4));
display->inputs.push_back(input);
- wl_seat_add_listener(input->seat, &seat_listener, input);
+ wl_seat_add_listener(input->wl_seat, &seat_listener, input);
}
else if (!strcmp(interface, wl_shm_interface.name)) {
display->shm = static_cast<wl_shm *>(
@@ -1387,7 +2078,11 @@ static void global_add(void *data,
}
else if (!strcmp(interface, wl_data_device_manager_interface.name)) {
display->data_device_manager = static_cast<wl_data_device_manager *>(
- wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 1));
+ wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 3));
+ }
+ else if (!strcmp(interface, zwp_tablet_manager_v2_interface.name)) {
+ display->tablet_manager = static_cast<zwp_tablet_manager_v2 *>(
+ wl_registry_bind(wl_registry, name, &zwp_tablet_manager_v2_interface, 1));
}
else if (!strcmp(interface, zwp_relative_pointer_manager_v1_interface.name)) {
display->relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>(
@@ -1408,13 +2103,15 @@ static void global_add(void *data,
* name is no longer available. If the client bound to the global
* using the bind request, the client should now destroy that object.
*/
-static void global_remove(void * /*data*/, struct wl_registry * /*wl_registry*/, uint32_t /*name*/)
+static void global_handle_remove(void * /*data*/,
+ struct wl_registry * /*wl_registry*/,
+ uint32_t /*name*/)
{
}
static const struct wl_registry_listener registry_listener = {
- global_add,
- global_remove,
+ global_handle_add,
+ global_handle_remove,
};
/** \} */
@@ -1427,6 +2124,8 @@ static const struct wl_registry_listener registry_listener = {
GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t)
{
+ wl_log_set_handler_client(ghost_wayland_log_handler);
+
d->system = this;
/* Connect to the Wayland server. */
d->display = wl_display_connect(nullptr);
@@ -1453,10 +2152,18 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t)
if (d->data_device_manager) {
for (input_t *input : d->inputs) {
input->data_device = wl_data_device_manager_get_data_device(d->data_device_manager,
- input->seat);
+ input->wl_seat);
wl_data_device_add_listener(input->data_device, &data_device_listener, input);
}
}
+
+ if (d->tablet_manager) {
+ for (input_t *input : d->inputs) {
+ input->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(d->tablet_manager,
+ input->wl_seat);
+ zwp_tablet_seat_v2_add_listener(input->tablet_seat, &tablet_seat_listener, input);
+ }
+ }
}
GHOST_SystemWayland::~GHOST_SystemWayland()
@@ -1485,42 +2192,47 @@ int GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*actio
GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const
{
- if (!d->inputs.empty()) {
- static const xkb_state_component mods_all = xkb_state_component(
- XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_MODS_LOCKED |
- XKB_STATE_MODS_EFFECTIVE);
-
- keys.set(GHOST_kModifierKeyLeftShift,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) ==
- 1);
- keys.set(GHOST_kModifierKeyRightShift,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) ==
- 1);
- keys.set(GHOST_kModifierKeyLeftAlt,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LAlt", mods_all) == 1);
- keys.set(GHOST_kModifierKeyRightAlt,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RAlt", mods_all) == 1);
- keys.set(GHOST_kModifierKeyLeftControl,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LControl", mods_all) == 1);
- keys.set(GHOST_kModifierKeyRightControl,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RControl", mods_all) == 1);
- keys.set(GHOST_kModifierKeyOS,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "Super", mods_all) == 1);
- keys.set(GHOST_kModifierKeyNumMasks,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "NumLock", mods_all) == 1);
-
- return GHOST_kSuccess;
+ if (d->inputs.empty()) {
+ return GHOST_kFailure;
}
- return GHOST_kFailure;
+
+ static const xkb_state_component mods_all = xkb_state_component(
+ XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_MODS_LOCKED |
+ XKB_STATE_MODS_EFFECTIVE);
+
+ bool val;
+
+ /* NOTE: XKB doesn't seem to differentiate between left/right modifiers. */
+
+ val = xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) == 1;
+ keys.set(GHOST_kModifierKeyLeftShift, val);
+ keys.set(GHOST_kModifierKeyRightShift, val);
+
+ val = xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_ALT, mods_all) == 1;
+ keys.set(GHOST_kModifierKeyLeftAlt, val);
+ keys.set(GHOST_kModifierKeyRightAlt, val);
+
+ val = xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_CTRL, mods_all) == 1;
+ keys.set(GHOST_kModifierKeyLeftControl, val);
+ keys.set(GHOST_kModifierKeyRightControl, val);
+
+ val = xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_LOGO, mods_all) == 1;
+ keys.set(GHOST_kModifierKeyOS, val);
+
+ val = xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_NUM, mods_all) == 1;
+ keys.set(GHOST_kModifierKeyNumMasks, val);
+
+ return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const
{
- if (!d->inputs.empty()) {
- buttons = d->inputs[0]->buttons;
- return GHOST_kSuccess;
+ if (d->inputs.empty()) {
+ return GHOST_kFailure;
}
- return GHOST_kFailure;
+
+ buttons = d->inputs[0]->buttons;
+ return GHOST_kSuccess;
}
char *GHOST_SystemWayland::getClipboard(bool /*selection*/) const
@@ -1536,25 +2248,29 @@ void GHOST_SystemWayland::putClipboard(const char *buffer, bool /*selection*/) c
return;
}
- data_source_t *data_source = d->inputs[0]->data_source;
+ input_t *input = d->inputs[0];
+
+ std::lock_guard lock{input->data_source_mutex};
+
+ data_source_t *data_source = input->data_source;
/* Copy buffer. */
+ free(data_source->buffer_out);
const size_t buffer_size = strlen(buffer) + 1;
data_source->buffer_out = static_cast<char *>(malloc(buffer_size));
std::memcpy(data_source->buffer_out, buffer, buffer_size);
data_source->data_source = wl_data_device_manager_create_data_source(d->data_device_manager);
- wl_data_source_add_listener(
- data_source->data_source, &data_source_listener, data_source->buffer_out);
+ wl_data_source_add_listener(data_source->data_source, &data_source_listener, input);
for (const std::string &type : mime_send) {
wl_data_source_offer(data_source->data_source, type.c_str());
}
- if (!d->inputs.empty() && d->inputs[0]->data_device) {
+ if (input->data_device) {
wl_data_device_set_selection(
- d->inputs[0]->data_device, data_source->data_source, data_source->source_serial);
+ input->data_device, data_source->data_source, input->data_source_serial);
}
}
@@ -1565,12 +2281,30 @@ uint8_t GHOST_SystemWayland::getNumDisplays() const
GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) const
{
- if (d->inputs.empty() || (d->inputs[0]->focus_pointer == nullptr)) {
+ if (d->inputs.empty()) {
return GHOST_kFailure;
}
- x = d->inputs[0]->x;
- y = d->inputs[0]->y;
+ input_t *input = d->inputs[0];
+ struct wl_surface *surface = nullptr;
+ if (input->pointer_serial == input->cursor_serial) {
+ surface = input->focus_pointer;
+ }
+ else if (input->tablet_serial == input->cursor_serial) {
+ surface = input->focus_tablet;
+ }
+ if (!surface) {
+ return GHOST_kFailure;
+ }
+
+ GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface));
+ if (!win) {
+ return GHOST_kFailure;
+ }
+
+ const wl_fixed_t scale = win->scale();
+ x = wl_fixed_to_int(scale * input->xy[0]);
+ y = wl_fixed_to_int(scale * input->xy[1]);
return GHOST_kSuccess;
}
@@ -1583,8 +2317,8 @@ void GHOST_SystemWayland::getMainDisplayDimensions(uint32_t &width, uint32_t &he
{
if (getNumDisplays() > 0) {
/* We assume first output as main. */
- width = uint32_t(d->outputs[0]->width_pxl) / d->outputs[0]->scale;
- height = uint32_t(d->outputs[0]->height_pxl) / d->outputs[0]->scale;
+ width = uint32_t(d->outputs[0]->size_native[0]) / d->outputs[0]->scale;
+ height = uint32_t(d->outputs[0]->size_native[1]) / d->outputs[0]->scale;
}
}
@@ -1705,12 +2439,12 @@ wl_compositor *GHOST_SystemWayland::compositor()
return d->compositor;
}
-xdg_wm_base *GHOST_SystemWayland::shell()
+xdg_wm_base *GHOST_SystemWayland::xdg_shell()
{
return d->xdg_shell;
}
-zxdg_decoration_manager_v1 *GHOST_SystemWayland::decoration_manager()
+zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decoration_manager()
{
return d->xdg_decoration_manager;
}
@@ -1736,16 +2470,45 @@ static void set_cursor_buffer(input_t *input, wl_buffer *buffer)
c->visible = (buffer != nullptr);
- wl_surface_attach(c->surface, buffer, 0, 0);
+ const int32_t image_size_x = int32_t(c->wl_image.width);
+ const int32_t image_size_y = int32_t(c->wl_image.height);
+
+ const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / c->scale;
+ const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / c->scale;
+
+ if (buffer) {
+ wl_surface_set_buffer_scale(c->wl_surface, c->scale);
+ wl_surface_attach(c->wl_surface, buffer, 0, 0);
+ wl_surface_damage(c->wl_surface, 0, 0, image_size_x, image_size_y);
+ wl_surface_commit(c->wl_surface);
+ }
- wl_surface_damage(c->surface, 0, 0, int32_t(c->image.width), int32_t(c->image.height));
- wl_pointer_set_cursor(input->pointer,
+ wl_pointer_set_cursor(input->wl_pointer,
input->pointer_serial,
- c->visible ? c->surface : nullptr,
- int32_t(c->image.hotspot_x) / c->scale,
- int32_t(c->image.hotspot_y) / c->scale);
+ c->visible ? c->wl_surface : nullptr,
+ hotspot_x,
+ hotspot_y);
+
+ /* Set the cursor for all tablet tools as well. */
+ for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : input->tablet_tools) {
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(
+ zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
+
+ if (buffer) {
+ /* FIXME: for some reason cursor scale is applied twice (when the scale isn't 1x),
+ * this happens both in gnome-shell & KDE. Setting the surface scale here doesn't help. */
+ wl_surface_set_buffer_scale(tool_input->cursor_surface, c->scale);
+ wl_surface_attach(tool_input->cursor_surface, buffer, 0, 0);
+ wl_surface_damage(tool_input->cursor_surface, 0, 0, image_size_x, image_size_y);
+ wl_surface_commit(tool_input->cursor_surface);
+ }
- wl_surface_commit(c->surface);
+ zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
+ input->tablet_serial,
+ c->visible ? tool_input->cursor_surface : nullptr,
+ hotspot_x,
+ hotspot_y);
+ }
}
GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
@@ -1759,12 +2522,13 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
input_t *input = d->inputs[0];
cursor_t *c = &input->cursor;
- if (!c->theme) {
+ if (!c->wl_theme) {
/* The cursor surface hasn't entered an output yet. Initialize theme with scale 1. */
- c->theme = wl_cursor_theme_load(c->theme_name.c_str(), c->size, d->inputs[0]->system->shm());
+ c->wl_theme = wl_cursor_theme_load(
+ c->theme_name.c_str(), c->size, d->inputs[0]->system->shm());
}
- wl_cursor *cursor = wl_cursor_theme_get_cursor(c->theme, cursor_name.c_str());
+ wl_cursor *cursor = wl_cursor_theme_get_cursor(c->wl_theme, cursor_name.c_str());
if (!cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
@@ -1777,8 +2541,8 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
return GHOST_kFailure;
}
- c->buffer = buffer;
- c->image = *image;
+ c->wl_buffer = buffer;
+ c->wl_image = *image;
set_cursor_buffer(input, buffer);
@@ -1884,11 +2648,11 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
}
}
- cursor->buffer = buffer;
- cursor->image.width = uint32_t(sizex);
- cursor->image.height = uint32_t(sizey);
- cursor->image.hotspot_x = uint32_t(hotX);
- cursor->image.hotspot_y = uint32_t(hotY);
+ cursor->wl_buffer = buffer;
+ cursor->wl_image.width = uint32_t(sizex);
+ cursor->wl_image.height = uint32_t(sizey);
+ cursor->wl_image.hotspot_x = uint32_t(hotX);
+ cursor->wl_image.hotspot_y = uint32_t(hotY);
set_cursor_buffer(d->inputs[0], buffer);
@@ -1906,7 +2670,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
cursor_t *cursor = &input->cursor;
if (visible) {
if (!cursor->visible) {
- set_cursor_buffer(input, cursor->buffer);
+ set_cursor_buffer(input, cursor->wl_buffer);
}
}
else {
@@ -1918,9 +2682,21 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
return GHOST_kSuccess;
}
+bool GHOST_SystemWayland::supportsCursorWarp()
+{
+ /* WAYLAND doesn't support setting the cursor position directly,
+ * this is an intentional choice, forcing us to use a software cursor in this case. */
+ return false;
+}
+
+bool GHOST_SystemWayland::supportsWindowPosition()
+{
+ /* WAYLAND doesn't support accessing the window position. */
+ return false;
+}
+
GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode,
const GHOST_TGrabCursorMode mode_current,
-
wl_surface *surface)
{
/* ignore, if the required protocols are not supported */
@@ -1939,42 +2715,123 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
input_t *input = d->inputs[0];
- if (mode_current == GHOST_kGrabHide) {
+#define MODE_NEEDS_LOCK(m) ((m) == GHOST_kGrabWrap || (m) == GHOST_kGrabHide)
+#define MODE_NEEDS_HIDE(m) ((m) == GHOST_kGrabHide)
+#define MODE_NEEDS_CONFINE(m) ((m) == GHOST_kGrabNormal)
+
+ const bool was_lock = MODE_NEEDS_LOCK(mode_current);
+ const bool use_lock = MODE_NEEDS_LOCK(mode);
+
+ /* Check for wrap as #supportsCursorWarp isn't supported. */
+ const bool was_hide = MODE_NEEDS_HIDE(mode_current) || (mode_current == GHOST_kGrabWrap);
+ const bool use_hide = MODE_NEEDS_HIDE(mode) || (mode == GHOST_kGrabWrap);
+
+ const bool was_confine = MODE_NEEDS_CONFINE(mode_current);
+ const bool use_confine = MODE_NEEDS_CONFINE(mode);
+
+#undef MODE_NEEDS_LOCK
+#undef MODE_NEEDS_HIDE
+#undef MODE_NEEDS_CONFINE
+
+ if (!use_hide) {
setCursorVisibility(true);
}
- if ((mode == GHOST_kGrabDisable) ||
- /* Switching from one grab mode to another,
- * in this case disable the current locks as it makes logic confusing,
- * postpone changing the cursor to avoid flickering. */
- (mode_current != GHOST_kGrabDisable)) {
+ /* Switching from one grab mode to another,
+ * in this case disable the current locks as it makes logic confusing,
+ * postpone changing the cursor to avoid flickering. */
+ if (!use_lock) {
if (input->relative_pointer) {
zwp_relative_pointer_v1_destroy(input->relative_pointer);
input->relative_pointer = nullptr;
}
if (input->locked_pointer) {
+ /* Request location to restore to. */
+ if (mode_current == GHOST_kGrabWrap) {
+ /* The chance this fails is _very_ low. */
+ GHOST_WindowWayland *win = window_from_surface(surface);
+ if (!win) {
+ GHOST_PRINT("could not find window from surface when un-grabbing!" << std::endl);
+ }
+ else {
+ GHOST_Rect bounds;
+ int32_t xy_new[2] = {input->xy[0], input->xy[1]};
+
+ /* Fallback to window bounds. */
+ if (win->getCursorGrabBounds(bounds) == GHOST_kFailure) {
+ win->getClientBounds(bounds);
+ }
+
+ const int scale = win->scale();
+
+ bounds.m_l = wl_fixed_from_int(bounds.m_l) / scale;
+ bounds.m_t = wl_fixed_from_int(bounds.m_t) / scale;
+ bounds.m_r = wl_fixed_from_int(bounds.m_r) / scale;
+ bounds.m_b = wl_fixed_from_int(bounds.m_b) / scale;
+
+ bounds.wrapPoint(xy_new[0], xy_new[1], 0, win->getCursorGrabAxis());
+
+ /* Push an event so the new location is registered. */
+ if ((xy_new[0] != input->xy[0]) || (xy_new[1] != input->xy[1])) {
+ input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ win,
+ wl_fixed_to_int(scale * xy_new[0]),
+ wl_fixed_to_int(scale * xy_new[1]),
+ GHOST_TABLET_DATA_NONE));
+ }
+ input->xy[0] = xy_new[0];
+ input->xy[1] = xy_new[1];
+
+ zwp_locked_pointer_v1_set_cursor_position_hint(
+ input->locked_pointer, xy_new[0], xy_new[1]);
+ wl_surface_commit(surface);
+ }
+ }
+
zwp_locked_pointer_v1_destroy(input->locked_pointer);
input->locked_pointer = nullptr;
}
}
+ if (!use_confine) {
+ if (input->confined_pointer) {
+ zwp_confined_pointer_v1_destroy(input->confined_pointer);
+ input->confined_pointer = nullptr;
+ }
+ }
+
if (mode != GHOST_kGrabDisable) {
- /* TODO(@campbellbarton): As WAYLAND does not support warping the pointer it may not be
- * possible to support #GHOST_kGrabWrap by pragmatically settings it's coordinates.
- * An alternative could be to draw the cursor in software (and hide the real cursor),
- * or just accept a locked cursor on WAYLAND. */
- input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
- d->relative_pointer_manager, input->pointer);
- zwp_relative_pointer_v1_add_listener(
- input->relative_pointer, &relative_pointer_listener, input);
- input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
- d->pointer_constraints,
- surface,
- input->pointer,
- nullptr,
- ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
-
- if (mode == GHOST_kGrabHide) {
+ if (use_lock) {
+ if (!was_lock) {
+ /* TODO(@campbellbarton): As WAYLAND does not support warping the pointer it may not be
+ * possible to support #GHOST_kGrabWrap by pragmatically settings it's coordinates.
+ * An alternative could be to draw the cursor in software (and hide the real cursor),
+ * or just accept a locked cursor on WAYLAND. */
+ input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
+ d->relative_pointer_manager, input->wl_pointer);
+ zwp_relative_pointer_v1_add_listener(
+ input->relative_pointer, &relative_pointer_listener, input);
+ input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
+ d->pointer_constraints,
+ surface,
+ input->wl_pointer,
+ nullptr,
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+ }
+ }
+ else if (use_confine) {
+ if (!was_confine) {
+ input->confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
+ d->pointer_constraints,
+ surface,
+ input->wl_pointer,
+ nullptr,
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+ }
+ }
+
+ if (use_hide && !was_hide) {
setCursorVisibility(false);
}
}
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index eeb65eb4fc3..762ceb80e38 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -22,11 +22,32 @@ class GHOST_WindowWayland;
struct display_t;
struct output_t {
- struct wl_output *output;
- int32_t width_pxl, height_pxl; /* Dimensions in pixel. */
- int32_t width_mm, height_mm; /* Dimensions in millimeter. */
- int transform;
- int scale;
+ struct wl_output *wl_output = nullptr;
+ struct zxdg_output_v1 *xdg_output = nullptr;
+ /** Dimensions in pixels. */
+ int32_t size_native[2] = {0, 0};
+ /** Dimensions in millimeter. */
+ int32_t size_mm[2] = {0, 0};
+
+ int32_t size_logical[2] = {0, 0};
+ bool has_size_logical = false;
+
+ int32_t position_logical[2] = {0, 0};
+ bool has_position_logical = false;
+
+ int transform = 0;
+ int scale = 1;
+ /**
+ * The integer `scale` value should be used in almost all cases,
+ * as this is what is used for most API calls.
+ * Only use fractional scaling to calculate the DPI.
+ *
+ * \note Internally an #wl_fixed_t is used to store the scale of the display,
+ * so use the same value here (avoid floating point arithmetic in general).
+ */
+ wl_fixed_t scale_fractional = wl_fixed_from_int(1);
+ bool has_scale_fractional = false;
+
std::string make;
std::string model;
};
@@ -79,9 +100,9 @@ class GHOST_SystemWayland : public GHOST_System {
wl_compositor *compositor();
- xdg_wm_base *shell();
+ xdg_wm_base *xdg_shell();
- zxdg_decoration_manager_v1 *decoration_manager();
+ zxdg_decoration_manager_v1 *xdg_decoration_manager();
const std::vector<output_t *> &outputs() const;
@@ -103,6 +124,9 @@ class GHOST_SystemWayland : public GHOST_System {
GHOST_TSuccess setCursorVisibility(bool visible);
+ bool supportsCursorWarp();
+ bool supportsWindowPosition();
+
GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode,
const GHOST_TGrabCursorMode mode_current,
wl_surface *surface);
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index e93a56cc8d4..bed9cd6c784 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -506,8 +506,9 @@ static void destroyIMCallback(XIM /*xim*/, XPointer ptr, XPointer /*data*/)
{
GHOST_PRINT("XIM server died\n");
- if (ptr)
+ if (ptr) {
*(XIM *)ptr = nullptr;
+ }
}
bool GHOST_SystemX11::openX11_IM()
@@ -519,8 +520,9 @@ bool GHOST_SystemX11::openX11_IM()
XSetLocaleModifiers("");
m_xim = XOpenIM(m_display, nullptr, (char *)GHOST_X11_RES_NAME, (char *)GHOST_X11_RES_CLASS);
- if (!m_xim)
+ if (!m_xim) {
return false;
+ }
XIMCallback destroy;
destroy.callback = (XIMProc)destroyIMCallback;
@@ -641,10 +643,11 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
SleepTillEvent(m_display, -1);
}
else {
- int64_t maxSleep = next - getMilliSeconds();
+ const int64_t maxSleep = next - getMilliSeconds();
- if (maxSleep >= 0)
+ if (maxSleep >= 0) {
SleepTillEvent(m_display, next - getMilliSeconds());
+ }
}
}
@@ -692,8 +695,9 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
}
else if (xevent.type == KeyPress) {
if ((xevent.xkey.keycode == m_last_release_keycode) &&
- ((xevent.xkey.time <= m_last_release_time)))
+ ((xevent.xkey.time <= m_last_release_time))) {
continue;
+ }
}
processEvent(&xevent);
@@ -733,7 +737,7 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
XK_Super_R,
};
- for (int i = 0; i < (sizeof(modifiers) / sizeof(*modifiers)); i++) {
+ for (int i = 0; i < (int)(sizeof(modifiers) / sizeof(*modifiers)); i++) {
KeyCode kc = XKeysymToKeycode(m_display, modifiers[i]);
if (kc != 0 && ((xevent.xkeymap.key_vector[kc >> 3] >> (kc & 7)) & 1) != 0) {
pushEvent(new GHOST_EventKey(getMilliSeconds(),
@@ -1233,36 +1237,46 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* process wheel mouse events and break, only pass on press events */
if (xbe.button == Button4) {
- if (xbe.type == ButtonPress)
+ if (xbe.type == ButtonPress) {
g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
+ }
break;
}
- else if (xbe.button == Button5) {
- if (xbe.type == ButtonPress)
+ if (xbe.button == Button5) {
+ if (xbe.type == ButtonPress) {
g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
+ }
break;
}
/* process rest of normal mouse buttons */
- if (xbe.button == Button1)
+ if (xbe.button == Button1) {
gbmask = GHOST_kButtonMaskLeft;
- else if (xbe.button == Button2)
+ }
+ else if (xbe.button == Button2) {
gbmask = GHOST_kButtonMaskMiddle;
- else if (xbe.button == Button3)
+ }
+ else if (xbe.button == Button3) {
gbmask = GHOST_kButtonMaskRight;
- /* It seems events 6 and 7 are for horizontal scrolling.
- * you can re-order button mapping like this... (swaps 6,7 with 8,9)
- * `xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7"` */
- else if (xbe.button == 6)
+ /* It seems events 6 and 7 are for horizontal scrolling.
+ * you can re-order button mapping like this... (swaps 6,7 with 8,9)
+ * `xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7"` */
+ }
+ else if (xbe.button == 6) {
gbmask = GHOST_kButtonMaskButton6;
- else if (xbe.button == 7)
+ }
+ else if (xbe.button == 7) {
gbmask = GHOST_kButtonMaskButton7;
- else if (xbe.button == 8)
+ }
+ else if (xbe.button == 8) {
gbmask = GHOST_kButtonMaskButton4;
- else if (xbe.button == 9)
+ }
+ else if (xbe.button == 9) {
gbmask = GHOST_kButtonMaskButton5;
- else
+ }
+ else {
break;
+ }
g_event = new GHOST_EventButton(
getMilliSeconds(), type, window, gbmask, window->GetTabletData());
@@ -1326,8 +1340,9 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
if (XGetWindowAttributes(m_display, xcme.window, &attr) == True) {
if (XGetInputFocus(m_display, &fwin, &revert_to) == True) {
if (attr.map_state == IsViewable) {
- if (fwin != xcme.window)
+ if (fwin != xcme.window) {
XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]);
+ }
}
}
}
@@ -1376,10 +1391,12 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
// printf("X: %s window %d\n",
// xce.type == EnterNotify ? "entering" : "leaving", (int) xce.window);
- if (xce.type == EnterNotify)
+ if (xce.type == EnterNotify) {
m_windowManager->setActiveWindow(window);
- else
+ }
+ else {
m_windowManager->setWindowInactive(window);
+ }
break;
}
@@ -1645,10 +1662,10 @@ static GHOST_TSuccess getCursorPosition_impl(Display *display,
&mask_return) == False) {
return GHOST_kFailure;
}
- else {
- x = rx;
- y = ry;
- }
+
+ x = rx;
+ y = ry;
+
return GHOST_kSuccess;
}
@@ -1955,18 +1972,19 @@ void GHOST_SystemX11::getClipboard_xcout(const XEvent *evt,
return;
case XCLIB_XCOUT_SENTCONVSEL:
- if (evt->type != SelectionNotify)
+ if (evt->type != SelectionNotify) {
return;
+ }
if (target == m_atom.UTF8_STRING && evt->xselection.property == None) {
*context = XCLIB_XCOUT_FALLBACK_UTF8;
return;
}
- else if (target == m_atom.COMPOUND_TEXT && evt->xselection.property == None) {
+ if (target == m_atom.COMPOUND_TEXT && evt->xselection.property == None) {
*context = XCLIB_XCOUT_FALLBACK_COMP;
return;
}
- else if (target == m_atom.TEXT && evt->xselection.property == None) {
+ if (target == m_atom.TEXT && evt->xselection.property == None) {
*context = XCLIB_XCOUT_FALLBACK_TEXT;
return;
}
@@ -2042,12 +2060,14 @@ void GHOST_SystemX11::getClipboard_xcout(const XEvent *evt,
* then read it, delete it, etc. */
/* make sure that the event is relevant */
- if (evt->type != PropertyNotify)
+ if (evt->type != PropertyNotify) {
return;
+ }
/* skip unless the property has a new value */
- if (evt->xproperty.state != PropertyNewValue)
+ if (evt->xproperty.state != PropertyNewValue) {
return;
+ }
/* check size and format of the property */
XGetWindowProperty(m_display,
@@ -2121,7 +2141,6 @@ void GHOST_SystemX11::getClipboard_xcout(const XEvent *evt,
XFlush(m_display);
return;
}
- return;
}
char *GHOST_SystemX11::getClipboard(bool selection) const
@@ -2136,10 +2155,12 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
XEvent evt;
unsigned int context = XCLIB_XCOUT_NONE;
- if (selection == True)
+ if (selection == True) {
sseln = m_atom.PRIMARY;
- else
+ }
+ else {
sseln = m_atom.CLIPBOARD;
+ }
const vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
vector<GHOST_IWindow *>::const_iterator win_it = win_vec.begin();
@@ -2154,20 +2175,18 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
strcpy(sel_buf, txt_cut_buffer);
return sel_buf;
}
- else {
- sel_buf = (char *)malloc(strlen(txt_select_buffer) + 1);
- strcpy(sel_buf, txt_select_buffer);
- return sel_buf;
- }
+ sel_buf = (char *)malloc(strlen(txt_select_buffer) + 1);
+ strcpy(sel_buf, txt_select_buffer);
+ return sel_buf;
}
- else if (owner == None) {
+ if (owner == None) {
return nullptr;
}
/* Restore events so copy doesn't swallow other event types (keyboard/mouse). */
vector<XEvent> restore_events;
- while (1) {
+ while (true) {
/* only get an event if xcout() is doing something */
bool restore_this_event = false;
if (context != XCLIB_XCOUT_NONE) {
@@ -2188,26 +2207,27 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
target = m_atom.STRING;
continue;
}
- else if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
+ if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
/* utf8 fail, move to compound text. */
context = XCLIB_XCOUT_NONE;
target = m_atom.COMPOUND_TEXT;
continue;
}
- else if (context == XCLIB_XCOUT_FALLBACK_COMP) {
+ if (context == XCLIB_XCOUT_FALLBACK_COMP) {
/* Compound text fail, move to text. */
context = XCLIB_XCOUT_NONE;
target = m_atom.TEXT;
continue;
}
- else if (context == XCLIB_XCOUT_FALLBACK_TEXT) {
+ if (context == XCLIB_XCOUT_FALLBACK_TEXT) {
/* Text fail, nothing else to try, break. */
context = XCLIB_XCOUT_NONE;
}
/* Only continue if #xcout() is doing something. */
- if (context == XCLIB_XCOUT_NONE)
+ if (context == XCLIB_XCOUT_NONE) {
break;
+ }
}
while (!restore_events.empty()) {
@@ -2221,10 +2241,12 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
memcpy(tmp_data, (char *)sel_buf, sel_len);
tmp_data[sel_len] = '\0';
- if (sseln == m_atom.STRING)
+ if (sseln == m_atom.STRING) {
XFree(sel_buf);
- else
+ }
+ else {
free(sel_buf);
+ }
return tmp_data;
}
@@ -2244,8 +2266,9 @@ void GHOST_SystemX11::putClipboard(const char *buffer, bool selection) const
if (selection == False) {
XSetSelectionOwner(m_display, m_atom.CLIPBOARD, m_window, CurrentTime);
owner = XGetSelectionOwner(m_display, m_atom.CLIPBOARD);
- if (txt_cut_buffer)
+ if (txt_cut_buffer) {
free((void *)txt_cut_buffer);
+ }
txt_cut_buffer = (char *)malloc(strlen(buffer) + 1);
strcpy(txt_cut_buffer, buffer);
@@ -2253,15 +2276,17 @@ void GHOST_SystemX11::putClipboard(const char *buffer, bool selection) const
else {
XSetSelectionOwner(m_display, m_atom.PRIMARY, m_window, CurrentTime);
owner = XGetSelectionOwner(m_display, m_atom.PRIMARY);
- if (txt_select_buffer)
+ if (txt_select_buffer) {
free((void *)txt_select_buffer);
+ }
txt_select_buffer = (char *)malloc(strlen(buffer) + 1);
strcpy(txt_select_buffer, buffer);
}
- if (owner != m_window)
+ if (owner != m_window) {
fprintf(stderr, "failed to own primary\n");
+ }
}
}
@@ -2374,7 +2399,7 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
const char *help_label,
const char *continue_label,
const char *link,
- GHOST_DialogOptions) const
+ GHOST_DialogOptions /*dialog_options*/) const
{
char **text_splitted = nullptr;
int textLines = 0;
@@ -2557,18 +2582,23 @@ static bool match_token(const char *haystack, const char *needle)
{
const char *h, *n;
for (h = haystack; *h;) {
- while (*h && is_filler_char(*h))
+ while (*h && is_filler_char(*h)) {
h++;
- if (!*h)
+ }
+ if (!*h) {
break;
+ }
- for (n = needle; *n && *h && tolower(*h) == tolower(*n); n++)
+ for (n = needle; *n && *h && tolower(*h) == tolower(*n); n++) {
h++;
- if (!*n && (is_filler_char(*h) || !*h))
+ }
+ if (!*n && (is_filler_char(*h) || !*h)) {
return true;
+ }
- while (*h && !is_filler_char(*h))
+ while (*h && !is_filler_char(*h)) {
h++;
+ }
}
return false;
}
diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp
index 954f0bc244d..de7c5422d3f 100644
--- a/intern/ghost/intern/GHOST_Window.cpp
+++ b/intern/ghost/intern/GHOST_Window.cpp
@@ -155,10 +155,31 @@ GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode,
GHOST_TSuccess GHOST_Window::getCursorGrabBounds(GHOST_Rect &bounds)
{
+ if (m_cursorGrab != GHOST_kGrabWrap) {
+ return GHOST_kFailure;
+ }
bounds = m_cursorGrabBounds;
return (bounds.m_l == -1 && bounds.m_r == -1) ? GHOST_kFailure : GHOST_kSuccess;
}
+void GHOST_Window::getCursorGrabState(GHOST_TGrabCursorMode &mode,
+ GHOST_TAxisFlag &wrap_axis,
+ GHOST_Rect &bounds)
+{
+ mode = m_cursorGrab;
+ if (m_cursorGrab == GHOST_kGrabWrap) {
+ bounds = m_cursorGrabBounds;
+ wrap_axis = m_cursorGrabAxis;
+ }
+ else {
+ bounds.m_l = -1;
+ bounds.m_r = -1;
+ bounds.m_t = -1;
+ bounds.m_b = -1;
+ wrap_axis = GHOST_kGrabAxisNone;
+ }
+}
+
GHOST_TSuccess GHOST_Window::setCursorShape(GHOST_TStandardCursor cursorShape)
{
if (setWindowCursorShape(cursorShape)) {
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 794e834d5c7..adbc29eb84e 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -152,6 +152,10 @@ class GHOST_Window : public GHOST_IWindow {
*/
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds);
+ void getCursorGrabState(GHOST_TGrabCursorMode &mode,
+ GHOST_TAxisFlag &axis_flag,
+ GHOST_Rect &bounds);
+
/**
* Sets the progress bar value displayed in the window/application icon
* \param progress: The progress percentage (0.0 to 1.0).
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index f9f168f772d..21e3793d3b1 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -15,41 +15,117 @@
#include <wayland-egl.h>
+#include <algorithm> /* For `std::find`. */
+
static constexpr size_t base_dpi = 96;
struct window_t {
- GHOST_WindowWayland *w;
- wl_surface *surface;
- /* Outputs on which the window is currently shown on. */
- std::unordered_set<const output_t *> outputs;
- uint16_t dpi = 0;
- int scale = 1;
- struct xdg_surface *xdg_surface;
- struct xdg_toplevel *xdg_toplevel;
+ GHOST_WindowWayland *w = nullptr;
+ struct wl_surface *wl_surface = nullptr;
+ /**
+ * Outputs on which the window is currently shown on.
+ *
+ * This is an ordered set (whoever adds to this is responsible for keeping members unique).
+ * In practice this is rarely manipulated and is limited by the number of physical displays.
+ */
+ std::vector<output_t *> outputs;
+
+ /** The scale value written to #wl_surface_set_buffer_scale. */
+ int scale = 0;
+ /**
+ * The DPI, either:
+ * - `scale * base_dpi`
+ * - `wl_fixed_to_int(scale_fractional * base_dpi)`
+ * When fractional scaling is available.
+ */
+ uint32_t dpi = 0;
+
+ struct xdg_surface *xdg_surface = nullptr;
+ struct xdg_toplevel *xdg_toplevel = nullptr;
struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration = nullptr;
- enum zxdg_toplevel_decoration_v1_mode decoration_mode;
- wl_egl_window *egl_window;
- int32_t pending_width, pending_height;
- bool is_maximised;
- bool is_fullscreen;
- bool is_active;
- bool is_dialog;
- int32_t width, height;
+ enum zxdg_toplevel_decoration_v1_mode decoration_mode = (enum zxdg_toplevel_decoration_v1_mode)0;
+ wl_egl_window *egl_window = nullptr;
+ bool is_maximised = false;
+ bool is_fullscreen = false;
+ bool is_active = false;
+ bool is_dialog = false;
+
+ int32_t size[2] = {0, 0};
+ int32_t size_pending[2] = {0, 0};
};
/* -------------------------------------------------------------------- */
-/** \name Wayland Interface Callbacks
- *
- * These callbacks are registered for Wayland interfaces and called when
- * an event is received from the compositor.
+/** \name Internal Utilities
+ * \{ */
+
+/**
+ * Return -1 if `output_a` has a scale smaller than `output_b`, 0 when there equal, otherwise 1.
+ */
+static int output_scale_cmp(const output_t *output_a, const output_t *output_b)
+{
+ if (output_a->scale < output_b->scale) {
+ return -1;
+ }
+ if (output_a->scale > output_b->scale) {
+ return 1;
+ }
+ if (output_a->has_scale_fractional || output_b->has_scale_fractional) {
+ const wl_fixed_t scale_fractional_a = output_a->has_scale_fractional ?
+ output_a->scale_fractional :
+ wl_fixed_from_int(output_a->scale);
+ const wl_fixed_t scale_fractional_b = output_b->has_scale_fractional ?
+ output_b->scale_fractional :
+ wl_fixed_from_int(output_b->scale);
+ if (scale_fractional_a < scale_fractional_b) {
+ return -1;
+ }
+ if (scale_fractional_a > scale_fractional_b) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int outputs_max_scale_or_default(const std::vector<output_t *> &outputs,
+ const int32_t scale_default,
+ uint32_t *r_dpi)
+{
+ const output_t *output_max = nullptr;
+ for (const output_t *reg_output : outputs) {
+ if (!output_max || (output_scale_cmp(output_max, reg_output) == -1)) {
+ output_max = reg_output;
+ }
+ }
+
+ if (output_max) {
+ if (r_dpi) {
+ *r_dpi = output_max->has_scale_fractional ?
+ /* Fractional DPI. */
+ wl_fixed_to_int(output_max->scale_fractional * base_dpi) :
+ /* Simple non-fractional DPI. */
+ (output_max->scale * base_dpi);
+ }
+ return output_max->scale;
+ }
+
+ if (r_dpi) {
+ *r_dpi = scale_default * base_dpi;
+ }
+ return scale_default;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Top Level), #xdg_toplevel_listener
* \{ */
-static void toplevel_configure(
+static void xdg_toplevel_handle_configure(
void *data, xdg_toplevel * /*xdg_toplevel*/, int32_t width, int32_t height, wl_array *states)
{
window_t *win = static_cast<window_t *>(data);
- win->pending_width = width;
- win->pending_height = height;
+ win->size_pending[0] = win->scale * width;
+ win->size_pending[1] = win->scale * height;
win->is_maximised = false;
win->is_fullscreen = false;
@@ -77,17 +153,23 @@ static void toplevel_configure(
}
}
-static void toplevel_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
+static void xdg_toplevel_handle_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
{
static_cast<window_t *>(data)->w->close();
}
static const xdg_toplevel_listener toplevel_listener = {
- toplevel_configure,
- toplevel_close,
+ xdg_toplevel_handle_configure,
+ xdg_toplevel_handle_close,
};
-static void toplevel_decoration_configure(
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Decoration Listener), #zxdg_toplevel_decoration_v1_listener
+ * \{ */
+
+static void xdg_toplevel_decoration_handle_configure(
void *data,
struct zxdg_toplevel_decoration_v1 * /*zxdg_toplevel_decoration_v1*/,
uint32_t mode)
@@ -96,10 +178,16 @@ static void toplevel_decoration_configure(
}
static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listener = {
- toplevel_decoration_configure,
+ xdg_toplevel_decoration_handle_configure,
};
-static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t serial)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Surface Handle Configure), #xdg_surface_listener
+ * \{ */
+
+static void xdg_surface_handle_configure(void *data, xdg_surface *xdg_surface, uint32_t serial)
{
window_t *win = static_cast<window_t *>(data);
@@ -107,12 +195,12 @@ static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t ser
return;
}
- if (win->pending_width != 0 && win->pending_height != 0) {
- win->width = win->scale * win->pending_width;
- win->height = win->scale * win->pending_height;
- wl_egl_window_resize(win->egl_window, win->width, win->height, 0, 0);
- win->pending_width = 0;
- win->pending_height = 0;
+ if (win->size_pending[0] != 0 && win->size_pending[1] != 0) {
+ win->size[0] = win->size_pending[0];
+ win->size[1] = win->size_pending[1];
+ wl_egl_window_resize(win->egl_window, win->size[0], win->size[1], 0, 0);
+ win->size_pending[0] = 0;
+ win->size_pending[1] = 0;
win->w->notify_size();
}
@@ -126,55 +214,49 @@ static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t ser
xdg_surface_ack_configure(xdg_surface, serial);
}
-static const xdg_surface_listener surface_listener = {
- surface_configure,
+static const xdg_surface_listener xdg_surface_listener = {
+ xdg_surface_handle_configure,
};
-static bool update_scale(GHOST_WindowWayland *window)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Surface), #wl_surface_listener
+ * \{ */
+
+static void surface_handle_enter(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
{
- int scale = 0;
- for (const output_t *output : window->outputs_active()) {
- if (output->scale > scale) {
- scale = output->scale;
- }
+ GHOST_WindowWayland *w = static_cast<GHOST_WindowWayland *>(data);
+ output_t *reg_output = w->output_find_by_wl(output);
+ if (reg_output == nullptr) {
+ return;
}
- if (scale > 0 && window->scale() != scale) {
- window->scale() = scale;
- /* Using the real DPI will cause wrong scaling of the UI
- * use a multiplier for the default DPI as workaround. */
- window->dpi() = scale * base_dpi;
- wl_surface_set_buffer_scale(window->surface(), scale);
- return true;
+ if (w->outputs_enter(reg_output)) {
+ w->outputs_changed_update_scale();
}
- return false;
}
-static void surface_enter(void *data, struct wl_surface * /*wl_surface*/, struct wl_output *output)
+static void surface_handle_leave(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
{
GHOST_WindowWayland *w = static_cast<GHOST_WindowWayland *>(data);
- for (const output_t *reg_output : w->outputs()) {
- if (reg_output->output == output) {
- w->outputs_active().insert(reg_output);
- }
+ output_t *reg_output = w->output_find_by_wl(output);
+ if (reg_output == nullptr) {
+ return;
}
- update_scale(w);
-}
-static void surface_leave(void *data, struct wl_surface * /*wl_surface*/, struct wl_output *output)
-{
- GHOST_WindowWayland *w = static_cast<GHOST_WindowWayland *>(data);
- for (const output_t *reg_output : w->outputs()) {
- if (reg_output->output == output) {
- w->outputs_active().erase(reg_output);
- }
+ if (w->outputs_leave(reg_output)) {
+ w->outputs_changed_update_scale();
}
- update_scale(w);
}
struct wl_surface_listener wl_surface_listener = {
- surface_enter,
- surface_leave,
+ surface_handle_enter,
+ surface_handle_leave,
};
/** \} */
@@ -208,32 +290,51 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
{
w->w = this;
- w->width = int32_t(width);
- w->height = int32_t(height);
+ w->size[0] = int32_t(width);
+ w->size[1] = int32_t(height);
w->is_dialog = is_dialog;
+ /* NOTE(@campbellbarton): The scale set here to avoid flickering on startup.
+ * When all monitors use the same scale (which is quite common) there aren't any problems.
+ *
+ * When monitors have different scales there may still be a visible window resize on startup.
+ * Ideally it would be possible to know the scale this window will use however that's only
+ * known once #surface_enter callback runs (which isn't guaranteed to run at all).
+ *
+ * Using the maximum scale is best as it results in the window first being smaller,
+ * avoiding a large window flashing before it's made smaller. */
+ w->scale = outputs_max_scale_or_default(this->m_system->outputs(), 1, &w->dpi);
+
/* Window surfaces. */
- w->surface = wl_compositor_create_surface(m_system->compositor());
- wl_surface_add_listener(w->surface, &wl_surface_listener, this);
+ w->wl_surface = wl_compositor_create_surface(m_system->compositor());
+ wl_surface_set_buffer_scale(this->surface(), w->scale);
+
+ wl_surface_add_listener(w->wl_surface, &wl_surface_listener, this);
- w->egl_window = wl_egl_window_create(w->surface, int(width), int(height));
+ w->egl_window = wl_egl_window_create(w->wl_surface, int(w->size[0]), int(w->size[1]));
- w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->shell(), w->surface);
+ w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->xdg_shell(), w->wl_surface);
w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
- if (m_system->decoration_manager()) {
+ /* NOTE: The limit is in points (not pixels) so Hi-DPI will limit to larger number of pixels.
+ * This has the advantage that the size limit is the same when moving the window between monitors
+ * with different scales set. If it was important to limit in pixels it could be re-calculated
+ * when the `w->scale` changed. */
+ xdg_toplevel_set_min_size(w->xdg_toplevel, 320, 240);
+
+ if (m_system->xdg_decoration_manager()) {
w->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
- m_system->decoration_manager(), w->xdg_toplevel);
+ m_system->xdg_decoration_manager(), w->xdg_toplevel);
zxdg_toplevel_decoration_v1_add_listener(
w->xdg_toplevel_decoration, &toplevel_decoration_v1_listener, w);
zxdg_toplevel_decoration_v1_set_mode(w->xdg_toplevel_decoration,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
- wl_surface_set_user_data(w->surface, this);
+ wl_surface_set_user_data(w->wl_surface, this);
- xdg_surface_add_listener(w->xdg_surface, &surface_listener, w);
+ xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
if (parentWindow && is_dialog) {
@@ -242,7 +343,7 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
}
/* Call top-level callbacks. */
- wl_surface_commit(w->surface);
+ wl_surface_commit(w->wl_surface);
wl_display_roundtrip(m_system->display());
#ifdef GHOST_OPENGL_ALPHA
@@ -296,32 +397,92 @@ GHOST_TSuccess GHOST_WindowWayland::notify_size()
wl_surface *GHOST_WindowWayland::surface() const
{
- return w->surface;
+ return w->wl_surface;
}
-const std::vector<output_t *> &GHOST_WindowWayland::outputs() const
+const std::vector<output_t *> &GHOST_WindowWayland::outputs()
{
- return m_system->outputs();
+ return w->outputs;
}
-std::unordered_set<const output_t *> &GHOST_WindowWayland::outputs_active()
+output_t *GHOST_WindowWayland::output_find_by_wl(struct wl_output *output)
{
- return w->outputs;
+ for (output_t *reg_output : this->m_system->outputs()) {
+ if (reg_output->wl_output == output) {
+ return reg_output;
+ }
+ }
+ return nullptr;
}
-uint16_t &GHOST_WindowWayland::dpi()
+bool GHOST_WindowWayland::outputs_changed_update_scale()
+{
+ uint32_t dpi_next;
+ const int scale_next = outputs_max_scale_or_default(this->outputs(), 0, &dpi_next);
+ if (scale_next == 0) {
+ return false;
+ }
+
+ window_t *win = this->w;
+ const uint32_t dpi_curr = win->dpi;
+ const int scale_curr = win->scale;
+ bool changed = false;
+
+ if (scale_next != scale_curr) {
+ /* Unlikely but possible there is a pending size change is set. */
+ win->size_pending[0] = (win->size_pending[0] / scale_curr) * scale_next;
+ win->size_pending[1] = (win->size_pending[1] / scale_curr) * scale_next;
+
+ win->scale = scale_next;
+ wl_surface_set_buffer_scale(this->surface(), scale_next);
+ changed = true;
+ }
+
+ if (dpi_next != dpi_curr) {
+ /* Using the real DPI will cause wrong scaling of the UI
+ * use a multiplier for the default DPI as workaround. */
+ win->dpi = dpi_next;
+ changed = true;
+ }
+
+ return changed;
+}
+
+bool GHOST_WindowWayland::outputs_enter(output_t *reg_output)
+{
+ std::vector<output_t *> &outputs = w->outputs;
+ auto it = std::find(outputs.begin(), outputs.end(), reg_output);
+ if (it != outputs.end()) {
+ return false;
+ }
+ outputs.push_back(reg_output);
+ return true;
+}
+
+bool GHOST_WindowWayland::outputs_leave(output_t *reg_output)
+{
+ std::vector<output_t *> &outputs = w->outputs;
+ auto it = std::find(outputs.begin(), outputs.end(), reg_output);
+ if (it == outputs.end()) {
+ return false;
+ }
+ outputs.erase(it);
+ return true;
+}
+
+uint16_t GHOST_WindowWayland::dpi()
{
return w->dpi;
}
-int &GHOST_WindowWayland::scale()
+int GHOST_WindowWayland::scale()
{
return w->scale;
}
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
{
- return m_system->setCursorGrab(mode, m_cursorGrab, w->surface);
+ return m_system->setCursorGrab(mode, m_cursorGrab, w->wl_surface);
}
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor shape)
@@ -356,22 +517,32 @@ void GHOST_WindowWayland::getWindowBounds(GHOST_Rect &bounds) const
void GHOST_WindowWayland::getClientBounds(GHOST_Rect &bounds) const
{
- bounds.set(0, 0, w->width, w->height);
+ bounds.set(0, 0, w->size[0], w->size[1]);
}
GHOST_TSuccess GHOST_WindowWayland::setClientWidth(uint32_t width)
{
- return setClientSize(width, uint32_t(w->height));
+ return setClientSize(width, uint32_t(w->size[1]));
}
GHOST_TSuccess GHOST_WindowWayland::setClientHeight(uint32_t height)
{
- return setClientSize(uint32_t(w->width), height);
+ return setClientSize(uint32_t(w->size[0]), height);
}
GHOST_TSuccess GHOST_WindowWayland::setClientSize(uint32_t width, uint32_t height)
{
wl_egl_window_resize(w->egl_window, int(width), int(height), 0, 0);
+
+ /* Override any pending size that may be set. */
+ w->size_pending[0] = 0;
+ w->size_pending[1] = 0;
+
+ w->size[0] = width;
+ w->size[1] = height;
+
+ notify_size();
+
return GHOST_kSuccess;
}
@@ -403,7 +574,7 @@ GHOST_WindowWayland::~GHOST_WindowWayland()
}
xdg_toplevel_destroy(w->xdg_toplevel);
xdg_surface_destroy(w->xdg_surface);
- wl_surface_destroy(w->surface);
+ wl_surface_destroy(w->wl_surface);
delete w;
}
@@ -494,7 +665,7 @@ void GHOST_WindowWayland::setOpaque() const
/* Make the window opaque. */
region = wl_compositor_create_region(m_system->compositor());
- wl_region_add(region, 0, 0, w->width, w->height);
+ wl_region_add(region, 0, 0, w->size[0], w->size[1]);
wl_surface_set_opaque_region(w->surface, region);
wl_region_destroy(region);
}
diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h
index d5dd123014b..b6d9fa04079 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.h
+++ b/intern/ghost/intern/GHOST_WindowWayland.h
@@ -17,7 +17,6 @@ class GHOST_SystemWayland;
struct output_t;
struct window_t;
-struct wl_surface;
class GHOST_WindowWayland : public GHOST_Window {
public:
@@ -40,25 +39,8 @@ class GHOST_WindowWayland : public GHOST_Window {
uint16_t getDPIHint() override;
- GHOST_TSuccess close();
-
- GHOST_TSuccess activate();
-
- GHOST_TSuccess deactivate();
-
- GHOST_TSuccess notify_size();
+ /* Ghost API */
- wl_surface *surface() const;
-
- const std::vector<output_t *> &outputs() const;
-
- std::unordered_set<const output_t *> &outputs_active();
-
- uint16_t &dpi();
-
- int &scale();
-
- protected:
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override;
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override;
@@ -109,6 +91,30 @@ class GHOST_WindowWayland : public GHOST_Window {
void setOpaque() const;
#endif
+ /* WAYLAND utility functions. */
+
+ GHOST_TSuccess close();
+
+ GHOST_TSuccess activate();
+
+ GHOST_TSuccess deactivate();
+
+ GHOST_TSuccess notify_size();
+
+ struct wl_surface *surface() const;
+
+ output_t *output_find_by_wl(struct wl_output *output);
+
+ const std::vector<output_t *> &outputs();
+
+ bool outputs_enter(output_t *reg_output);
+ bool outputs_leave(output_t *reg_output);
+ bool outputs_changed_update_scale();
+
+ uint16_t dpi();
+
+ int scale();
+
private:
GHOST_SystemWayland *m_system;
struct window_t *w;
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 3569c9574f1..ac7a476c76f 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -1711,7 +1711,7 @@ uint16_t GHOST_WindowX11::getDPIHint()
XrmDestroyDatabase(xrdb);
}
- /* Fallback to calculating DPI using X reported DPI, set using xrandr --dpi */
+ /* Fallback to calculating DPI using X reported DPI, set using `xrandr --dpi`. */
XWindowAttributes attr;
if (!XGetWindowAttributes(m_display, m_window, &attr)) {
/* Failed to get window attributes, return X11 default DPI */
diff --git a/intern/ghost/intern/GHOST_Wintab.cpp b/intern/ghost/intern/GHOST_Wintab.cpp
index 974a07db9c3..b136acbe098 100644
--- a/intern/ghost/intern/GHOST_Wintab.cpp
+++ b/intern/ghost/intern/GHOST_Wintab.cpp
@@ -310,7 +310,7 @@ void GHOST_Wintab::getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo)
outWintabInfo.reserve(numPackets);
for (int i = 0; i < numPackets; i++) {
- PACKET pkt = m_pkts[i];
+ const PACKET pkt = m_pkts[i];
GHOST_WintabInfoWin32 out;
/* % 3 for multiple devices ("DualTrack"). */
@@ -367,11 +367,12 @@ void GHOST_Wintab::getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo)
/* Some Wintab libraries don't handle relative button input, so we track button presses
* manually. */
DWORD buttonsChanged = m_buttons ^ pkt.pkButtons;
- WORD buttonIndex = 0;
+ /* We only needed the prior button state to compare to current, so we can overwrite it now. */
+ m_buttons = pkt.pkButtons;
- while (buttonsChanged) {
+ /* Iterate over button flag indices until all flags are clear. */
+ for (WORD buttonIndex = 0; buttonsChanged; buttonIndex++, buttonsChanged >>= 1) {
if (buttonsChanged & 1) {
- /* Find the index for the changed button from the button map. */
GHOST_TButtonMask button = mapWintabToGhostButton(pkt.pkCursor, buttonIndex);
if (button != GHOST_kButtonMaskNone) {
@@ -381,15 +382,11 @@ void GHOST_Wintab::getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo)
}
out.button = button;
- out.type = buttonsChanged & pkt.pkButtons ? GHOST_kEventButtonDown :
- GHOST_kEventButtonUp;
- }
- m_buttons ^= 1 << buttonIndex;
+ DWORD buttonFlag = 1 << buttonIndex;
+ out.type = pkt.pkButtons & buttonFlag ? GHOST_kEventButtonDown : GHOST_kEventButtonUp;
+ }
}
-
- buttonsChanged >>= 1;
- buttonIndex++;
}
outWintabInfo.push_back(out);
diff --git a/intern/ghost/intern/GHOST_Wintab.h b/intern/ghost/intern/GHOST_Wintab.h
index 86a0143ecc0..80eacf1f3fa 100644
--- a/intern/ghost/intern/GHOST_Wintab.h
+++ b/intern/ghost/intern/GHOST_Wintab.h
@@ -187,7 +187,7 @@ class GHOST_Wintab {
bool m_focused = false;
/** Pressed button map. */
- uint8_t m_buttons = 0;
+ DWORD m_buttons = 0;
/** Range of a coordinate space. */
struct Range {
diff --git a/intern/ghost/intern/GHOST_XrAction.cpp b/intern/ghost/intern/GHOST_XrAction.cpp
index 587b1124848..0e725bf4075 100644
--- a/intern/ghost/intern/GHOST_XrAction.cpp
+++ b/intern/ghost/intern/GHOST_XrAction.cpp
@@ -332,23 +332,26 @@ void GHOST_XrAction::updateState(XrSession session,
break;
}
case GHOST_kXrActionTypePoseInput: {
- XrActionStatePose state{XR_TYPE_ACTION_STATE_POSE};
- CHECK_XR(
- xrGetActionStatePose(session, &state_info, &state),
- (std::string("Failed to get state for pose action \"") + action_name + "\".").data());
- if (state.isActive) {
- XrSpace pose_space = ((subaction != nullptr) && (subaction->space != nullptr)) ?
- subaction->space->getSpace() :
- XR_NULL_HANDLE;
- if (pose_space != XR_NULL_HANDLE) {
- XrSpaceLocation space_location{XR_TYPE_SPACE_LOCATION};
- CHECK_XR(
- xrLocateSpace(
- pose_space, reference_space, predicted_display_time, &space_location),
- (std::string("Failed to query pose space for action \"") + action_name + "\".")
- .data());
- copy_openxr_pose_to_ghost_pose(space_location.pose,
- ((GHOST_XrPose *)m_states)[subaction_idx]);
+ /* Check for valid display time to avoid an error in #xrLocateSpace(). */
+ if (predicted_display_time > 0) {
+ XrActionStatePose state{XR_TYPE_ACTION_STATE_POSE};
+ CHECK_XR(xrGetActionStatePose(session, &state_info, &state),
+ (std::string("Failed to get state for pose action \"") + action_name + "\".")
+ .data());
+ if (state.isActive) {
+ XrSpace pose_space = ((subaction != nullptr) && (subaction->space != nullptr)) ?
+ subaction->space->getSpace() :
+ XR_NULL_HANDLE;
+ if (pose_space != XR_NULL_HANDLE) {
+ XrSpaceLocation space_location{XR_TYPE_SPACE_LOCATION};
+ CHECK_XR(
+ xrLocateSpace(
+ pose_space, reference_space, predicted_display_time, &space_location),
+ (std::string("Failed to query pose space for action \"") + action_name + "\".")
+ .data());
+ copy_openxr_pose_to_ghost_pose(space_location.pose,
+ ((GHOST_XrPose *)m_states)[subaction_idx]);
+ }
}
}
break;
diff --git a/intern/ghost/test/gears/GHOST_C-Test.c b/intern/ghost/test/gears/GHOST_C-Test.c
index 71f3a6f43b4..46c8fda0665 100644
--- a/intern/ghost/test/gears/GHOST_C-Test.c
+++ b/intern/ghost/test/gears/GHOST_C-Test.c
@@ -31,7 +31,7 @@
#endif /* defined(WIN32) || defined(__APPLE__) */
static void gearsTimerProc(GHOST_TimerTaskHandle task, uint64_t time);
-int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData);
+bool processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData);
static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
static GLfloat fAngle = 0.0;
@@ -269,9 +269,9 @@ static void setViewPortGL(GHOST_WindowHandle hWindow)
GHOST_DisposeRectangle(hRect);
}
-int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
+bool processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
{
- int handled = 1;
+ bool handled = true;
int cursor;
int visibility;
GHOST_TEventKeyData *keyData = NULL;
@@ -389,10 +389,10 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
} break;
case GHOST_kEventWindowActivate:
- handled = 0;
+ handled = false;
break;
case GHOST_kEventWindowDeactivate:
- handled = 0;
+ handled = false;
break;
case GHOST_kEventWindowUpdate: {
GHOST_WindowHandle window2 = GHOST_GetEventWindow(hEvent);
@@ -404,7 +404,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
} break;
default:
- handled = 0;
+ handled = false;
break;
}
return handled;
diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c
index 35b1de65171..157e4f1b0f2 100644
--- a/intern/ghost/test/multitest/MultiTest.c
+++ b/intern/ghost/test/multitest/MultiTest.c
@@ -812,7 +812,7 @@ struct _MultiTestApp {
int exit;
};
-static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr data)
+static bool multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr data)
{
MultiTestApp *app = data;
GHOST_WindowHandle win;
@@ -820,7 +820,7 @@ static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr dat
win = GHOST_GetEventWindow(evt);
if (win && !GHOST_ValidWindow(app->sys, win)) {
loggerwindow_log(app->logger, "WARNING: bad event, non-valid window\n");
- return 1;
+ return true;
}
if (win) {
@@ -845,7 +845,7 @@ static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr dat
}
}
- return 1;
+ return true;
}
/**/
diff --git a/release/datafiles/alert_icons_update.py b/release/datafiles/alert_icons_update.py
index 8c5d66e803a..bb4140d1ec2 100755
--- a/release/datafiles/alert_icons_update.py
+++ b/release/datafiles/alert_icons_update.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This script updates icons from the SVG file
import os
import subprocess
diff --git a/release/datafiles/blender_icons_geom_update.py b/release/datafiles/blender_icons_geom_update.py
index 6f7508a8e7c..3fd3164c324 100755
--- a/release/datafiles/blender_icons_geom_update.py
+++ b/release/datafiles/blender_icons_geom_update.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This script updates icons from the BLEND file
import os
import subprocess
diff --git a/release/datafiles/blender_icons_update.py b/release/datafiles/blender_icons_update.py
index c1cf8d6fcb0..e2c72e1d0b7 100755
--- a/release/datafiles/blender_icons_update.py
+++ b/release/datafiles/blender_icons_update.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This script updates icons from the SVG file
import os
import subprocess
diff --git a/release/datafiles/brushicons/curves_sculpt_add.png b/release/datafiles/brushicons/curves_sculpt_add.png
new file mode 100644
index 00000000000..e8b81b73919
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_add.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_comb.png b/release/datafiles/brushicons/curves_sculpt_comb.png
new file mode 100644
index 00000000000..bdf49e413e3
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_comb.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_cut.png b/release/datafiles/brushicons/curves_sculpt_cut.png
new file mode 100644
index 00000000000..7f9e116fcd1
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_cut.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_delete.png b/release/datafiles/brushicons/curves_sculpt_delete.png
new file mode 100644
index 00000000000..361b8e335a5
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_delete.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_density.png b/release/datafiles/brushicons/curves_sculpt_density.png
new file mode 100644
index 00000000000..305fa02298f
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_density.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_grow_shrink.png b/release/datafiles/brushicons/curves_sculpt_grow_shrink.png
new file mode 100644
index 00000000000..e4a76c6d6e4
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_grow_shrink.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_pinch.png b/release/datafiles/brushicons/curves_sculpt_pinch.png
new file mode 100644
index 00000000000..cc98203ef57
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_pinch.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_puff.png b/release/datafiles/brushicons/curves_sculpt_puff.png
new file mode 100644
index 00000000000..e5b48b8a96c
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_puff.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_slide.png b/release/datafiles/brushicons/curves_sculpt_slide.png
new file mode 100644
index 00000000000..7627cf76791
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_slide.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_smooth.png b/release/datafiles/brushicons/curves_sculpt_smooth.png
new file mode 100644
index 00000000000..7c7fd8fef4a
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_smooth.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_snake_hook.png b/release/datafiles/brushicons/curves_sculpt_snake_hook.png
new file mode 100644
index 00000000000..468abe66c08
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_snake_hook.png
Binary files differ
diff --git a/release/datafiles/brushicons/paint_select.png b/release/datafiles/brushicons/paint_select.png
new file mode 100644
index 00000000000..38f9a1250b2
--- /dev/null
+++ b/release/datafiles/brushicons/paint_select.png
Binary files differ
diff --git a/release/datafiles/colormanagement/config.ocio b/release/datafiles/colormanagement/config.ocio
index df359d6c86c..8f7f2b9aaf4 100644
--- a/release/datafiles/colormanagement/config.ocio
+++ b/release/datafiles/colormanagement/config.ocio
@@ -162,7 +162,7 @@ colorspaces:
equalitygroup:
bitdepth: 32f
description: |
- Standard RGB Display Space
+ sRGB display space
isdata: false
to_reference: !<FileTransform> {src: srgb.spi1d, interpolation: linear}
from_reference: !<FileTransform> {src: srgb_inv.spi1d, interpolation: linear}
@@ -193,11 +193,11 @@ colorspaces:
- !<ColorSpace>
name: Filmic sRGB
- family: display
+ family:
equalitygroup:
bitdepth: 32f
description: |
- Filmic sRGB view transform
+ sRGB display space with Filmic view transform
isdata: false
from_reference: !<GroupTransform>
children:
diff --git a/release/datafiles/ctodata.py b/release/datafiles/ctodata.py
index dabdd6d4ea6..b6420d5c9a2 100755
--- a/release/datafiles/ctodata.py
+++ b/release/datafiles/ctodata.py
@@ -2,8 +2,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright 2009 Blender Foundation. All rights reserved.
-# <pep8 compliant>
-
import sys
argv = sys.argv[:]
diff --git a/release/datafiles/icons/ops.curves.sculpt_density.dat b/release/datafiles/icons/ops.curves.sculpt_density.dat
new file mode 100644
index 00000000000..f336de79082
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_density.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_slide.dat b/release/datafiles/icons/ops.curves.sculpt_slide.dat
new file mode 100644
index 00000000000..7f143ad92cc
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_slide.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_smooth.dat b/release/datafiles/icons/ops.curves.sculpt_smooth.dat
new file mode 100644
index 00000000000..ba4bd081f33
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_smooth.dat
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 71e0f87dd1ba4e0ed5f619b031045a428e53423
+Subproject 9a85b13795157560b319235c63f5a13b0107ba4
diff --git a/release/datafiles/prvicons_update.py b/release/datafiles/prvicons_update.py
index d93a2cec113..0092942ea3b 100755
--- a/release/datafiles/prvicons_update.py
+++ b/release/datafiles/prvicons_update.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This script updates icons from the SVG file
import os
import subprocess
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index 19798e3f165..04ad04d4812 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -194,6 +194,15 @@ const bTheme U_theme_default = {
.text_sel = RGBA(0xffffffff),
.roundness = 0.2f,
},
+ .wcol_view_item = {
+ .outline = RGBA(0x2d2d2dff),
+ .inner = RGBA(0x303030ff),
+ .inner_sel = RGBA(0x4772b3ff),
+ .item = RGBA(0x4772b3ff),
+ .text = RGBA(0xccccccff),
+ .text_sel = RGBA(0xffffffff),
+ .roundness = 0.2f,
+ },
.wcol_pie_menu = {
.outline = RGBA(0x242424ff),
.inner = RGBA(0x181818ff),
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject bcb71eea69a7b83c44112a5872ccd67cae96ec6
+Subproject bdf75cb276dfd3b5266c909de4c099c00c68a65
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 61efd17f87b45c3049091127a5619219f9d2a82
+Subproject 95107484d076bc965239942e857c83433bfa86d
diff --git a/release/scripts/freestyle/modules/freestyle/shaders.py b/release/scripts/freestyle/modules/freestyle/shaders.py
index d2b10206b9f..f3e4a58d38e 100644
--- a/release/scripts/freestyle/modules/freestyle/shaders.py
+++ b/release/scripts/freestyle/modules/freestyle/shaders.py
@@ -726,7 +726,7 @@ class pyDiffusion2Shader(StrokeShader):
self._curvatureInfo = Curvature2DAngleF0D()
def shade(self, stroke):
- for i in range(1, self._nbIter):
+ for _i in range(1, self._nbIter):
it = Interface0DIterator(stroke)
for svert in it:
svert.point += self._normalInfo(it) * self._lambda * self._curvatureInfo(it)
@@ -911,7 +911,7 @@ class pyBluePrintCirclesShader(StrokeShader):
it = iter(stroke)
- for j in range(self.__turns):
+ for _j in range(self.__turns):
prev_radius = radius
prev_center = center
radius += randint(-R, R)
@@ -952,7 +952,7 @@ class pyBluePrintEllipsesShader(StrokeShader):
# for description of the line below, see pyBluePrintCirclesShader
directions = phase_to_direction(sv_nb)
it = iter(stroke)
- for j in range(self.__turns):
+ for _j in range(self.__turns):
prev_radius = radius
prev_center = center
radius = radius + Vector((randint(-R, R), randint(-R, R)))
@@ -1030,7 +1030,7 @@ class pyBluePrintSquaresShader(StrokeShader):
it = iter(stroke)
verticesToRemove = list()
- for j in range(self.__turns):
+ for _j in range(self.__turns):
for i, svert in zip(range(num_segments), it):
if i < first:
svert.point = points[0] + old_vecs[0] * i / (first - 1)
@@ -1125,7 +1125,7 @@ class pyBluePrintDirectedSquaresShader(StrokeShader):
it = iter(stroke)
verticesToRemove = list()
- for j in range(self.__turns):
+ for _j in range(self.__turns):
for i, svert in zip(range(num_segments), it):
if i < first:
svert.point = points[0] + old_vecs[0] * i / (first - 1)
diff --git a/release/scripts/freestyle/modules/freestyle/utils.py b/release/scripts/freestyle/modules/freestyle/utils.py
index 152dbca6f5e..309497430a8 100644
--- a/release/scripts/freestyle/modules/freestyle/utils.py
+++ b/release/scripts/freestyle/modules/freestyle/utils.py
@@ -151,7 +151,7 @@ def normal_at_I0D(it: Interface0DIterator) -> Vector:
# this case sometimes has a small difference with Normal2DF0D (1e-3 -ish)
it.decrement()
a = it.object
- curr, b = next(it), next(it)
+ _curr, b = next(it), next(it)
# give iterator back in original state
it.decrement()
return (b.point - a.point).orthogonal().normalized()
@@ -229,8 +229,6 @@ def simplifyDouglasPeucker(points, tolerance):
first_stack = []
last_stack = []
- new_points = []
-
markers[first] = 1
markers[last] = 1
diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py
index 5940f4f5cc8..d07532dfe54 100644
--- a/release/scripts/freestyle/modules/parameter_editor.py
+++ b/release/scripts/freestyle/modules/parameter_editor.py
@@ -1028,7 +1028,7 @@ class DashedLineShader(StrokeShader):
it = stroke.stroke_vertices_begin(sampling)
pattern_cycle = cycle(self.pattern)
pattern = next(pattern_cycle)
- for svert in it:
+ for _svert in it:
pos = it.t # curvilinear abscissa
if pos - start + sampling > pattern:
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py
index 3e823f2b6b7..9d820b8c9de 100644
--- a/release/scripts/modules/addon_utils.py
+++ b/release/scripts/modules/addon_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"paths",
"modules",
diff --git a/release/scripts/modules/animsys_refactor.py b/release/scripts/modules/animsys_refactor.py
index 35072885deb..0ab486efa11 100644
--- a/release/scripts/modules/animsys_refactor.py
+++ b/release/scripts/modules/animsys_refactor.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
This module has utility functions for renaming
rna values in fcurves and drivers.
diff --git a/release/scripts/modules/bl_app_override/__init__.py b/release/scripts/modules/bl_app_override/__init__.py
index e60c123ead5..4d6194e71cd 100644
--- a/release/scripts/modules/bl_app_override/__init__.py
+++ b/release/scripts/modules/bl_app_override/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
Module to manage overriding various parts of Blender.
diff --git a/release/scripts/modules/bl_app_override/helpers.py b/release/scripts/modules/bl_app_override/helpers.py
index dd17e8aa7c6..4759e0ae8e5 100644
--- a/release/scripts/modules/bl_app_override/helpers.py
+++ b/release/scripts/modules/bl_app_override/helpers.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
# -----------------------------------------------------------------------------
# AppOverrideState
diff --git a/release/scripts/modules/bl_app_template_utils.py b/release/scripts/modules/bl_app_template_utils.py
index 9d71664e513..985dbc22be6 100644
--- a/release/scripts/modules/bl_app_template_utils.py
+++ b/release/scripts/modules/bl_app_template_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
Similar to ``addon_utils``, except we can only have one active at a time.
diff --git a/release/scripts/modules/bl_console_utils/__init__.py b/release/scripts/modules/bl_console_utils/__init__.py
index 78800fa5703..ab95fe1e68a 100644
--- a/release/scripts/modules/bl_console_utils/__init__.py
+++ b/release/scripts/modules/bl_console_utils/__init__.py
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
"""
-Utilities relating to text mode console interations.
+Utilities relating to text mode console interactions.
"""
diff --git a/release/scripts/modules/bl_console_utils/autocomplete/__init__.py b/release/scripts/modules/bl_console_utils/autocomplete/__init__.py
index 5fa5b11f4bf..0da40331835 100644
--- a/release/scripts/modules/bl_console_utils/autocomplete/__init__.py
+++ b/release/scripts/modules/bl_console_utils/autocomplete/__init__.py
@@ -2,6 +2,4 @@
# Copyright (c) 2009 www.stani.be
-# <pep8 compliant>
-
"""Package for console specific modules."""
diff --git a/release/scripts/modules/bl_console_utils/autocomplete/complete_calltip.py b/release/scripts/modules/bl_console_utils/autocomplete/complete_calltip.py
index 6c7b0611ee2..07ccac81f91 100644
--- a/release/scripts/modules/bl_console_utils/autocomplete/complete_calltip.py
+++ b/release/scripts/modules/bl_console_utils/autocomplete/complete_calltip.py
@@ -2,8 +2,6 @@
# Copyright (c) 2009 www.stani.be
-# <pep8-80 compliant>
-
import inspect
import re
diff --git a/release/scripts/modules/bl_console_utils/autocomplete/complete_import.py b/release/scripts/modules/bl_console_utils/autocomplete/complete_import.py
index 2339e79c8f1..2f321fee0b2 100644
--- a/release/scripts/modules/bl_console_utils/autocomplete/complete_import.py
+++ b/release/scripts/modules/bl_console_utils/autocomplete/complete_import.py
@@ -10,8 +10,6 @@
# the file COPYING, distributed as part of this software.
# ****************************************************************************
-# <pep8 compliant>
-
"""Completer for import statements
Original code was from IPython/Extensions/ipy_completers.py. The following
diff --git a/release/scripts/modules/bl_console_utils/autocomplete/complete_namespace.py b/release/scripts/modules/bl_console_utils/autocomplete/complete_namespace.py
index 7bfa2aac1c1..4ba446d6832 100644
--- a/release/scripts/modules/bl_console_utils/autocomplete/complete_namespace.py
+++ b/release/scripts/modules/bl_console_utils/autocomplete/complete_namespace.py
@@ -2,8 +2,6 @@
# Copyright (c) 2009 www.stani.be
-# <pep8-80 compliant>
-
"""Autocomplete with the standard library"""
import re
diff --git a/release/scripts/modules/bl_console_utils/autocomplete/intellisense.py b/release/scripts/modules/bl_console_utils/autocomplete/intellisense.py
index 9484f825f9f..e53e38dbc53 100644
--- a/release/scripts/modules/bl_console_utils/autocomplete/intellisense.py
+++ b/release/scripts/modules/bl_console_utils/autocomplete/intellisense.py
@@ -2,8 +2,6 @@
# Copyright (c) 2009 www.stani.be
-# <pep8-80 compliant>
-
"""This module provides intellisense features such as:
* autocompletion
diff --git a/release/scripts/modules/bl_i18n_utils/__init__.py b/release/scripts/modules/bl_i18n_utils/__init__.py
index b07a993c12e..d4af1270369 100644
--- a/release/scripts/modules/bl_i18n_utils/__init__.py
+++ b/release/scripts/modules/bl_i18n_utils/__init__.py
@@ -1,5 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""Package for translation (i18n) tools."""
diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
index 604a577eec9..319fd3396a0 100644
--- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
+++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Populate a template file (POT format currently) from Blender RNA/py/C data.
# XXX: This script is meant to be used from inside Blender!
# You should not directly use this script, rather use update_msg.py!
diff --git a/release/scripts/modules/bl_i18n_utils/merge_po.py b/release/scripts/modules/bl_i18n_utils/merge_po.py
index d048f8f5c42..3cc5046fe3c 100755
--- a/release/scripts/modules/bl_i18n_utils/merge_po.py
+++ b/release/scripts/modules/bl_i18n_utils/merge_po.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Merge one or more .po files into the first dest one.
# If a msgkey is present in more than one merged po, the one in the first file wins, unless
# it’s marked as fuzzy and one later is not.
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index 57722d06ce5..408f8523b8d 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Global settings used by all scripts in this dir.
# XXX Before any use of the tools in this dir, please make a copy of this file
# named "setting.py"
@@ -58,7 +56,7 @@ LANGUAGES = (
(21, "Arabic (ﺔﻴﺑﺮﻌﻟﺍ)", "ar_EG"),
(22, "Bulgarian (Български)", "bg_BG"),
(23, "Greek (Ελληνικά)", "el_GR"),
- (24, "Korean (한국 언어)", "ko_KR"),
+ (24, "Korean (한국어)", "ko_KR"),
(25, "Nepali (नेपाली)", "ne_NP"),
# Using the utf8 flipped form of Persian (فارسی).
(26, "Persian (ﯽﺳﺭﺎﻓ)", "fa_IR"),
diff --git a/release/scripts/modules/bl_i18n_utils/settings_user.py b/release/scripts/modules/bl_i18n_utils/settings_user.py
index a7aa8a80af8..3c29a0d743a 100644
--- a/release/scripts/modules/bl_i18n_utils/settings_user.py
+++ b/release/scripts/modules/bl_i18n_utils/settings_user.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import settings
diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py
index ec5465549b3..b1e3fa07ac5 100644
--- a/release/scripts/modules/bl_i18n_utils/utils.py
+++ b/release/scripts/modules/bl_i18n_utils/utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Some misc utilities...
import collections
diff --git a/release/scripts/modules/bl_i18n_utils/utils_cli.py b/release/scripts/modules/bl_i18n_utils/utils_cli.py
index dd75ac11ac4..4b00816d132 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_cli.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_cli.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Some useful operations from utils' I18nMessages class exposed as a CLI.
import os
diff --git a/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py b/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py
index da4183d457c..833c46a732e 100755
--- a/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Update "languages" text file used by Blender at runtime to build translations menu.
diff --git a/release/scripts/modules/bl_i18n_utils/utils_rtl.py b/release/scripts/modules/bl_i18n_utils/utils_rtl.py
index beec2659df8..6e3d25cfc3f 100755
--- a/release/scripts/modules/bl_i18n_utils/utils_rtl.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_rtl.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Pre-process right-to-left languages.
# You can use it either standalone, or through import_po_from_branches or
# update_trunk.
diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
index f9208bbe3ee..74785c81bfd 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import enchant
import os
import pickle
diff --git a/release/scripts/modules/bl_keymap_utils/__init__.py b/release/scripts/modules/bl_keymap_utils/__init__.py
index e00776d3466..950314cd74c 100644
--- a/release/scripts/modules/bl_keymap_utils/__init__.py
+++ b/release/scripts/modules/bl_keymap_utils/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"io",
"keymap_from_toolbar",
diff --git a/release/scripts/modules/bl_keymap_utils/io.py b/release/scripts/modules/bl_keymap_utils/io.py
index 6631461eaba..5d74ffbcf56 100644
--- a/release/scripts/modules/bl_keymap_utils/io.py
+++ b/release/scripts/modules/bl_keymap_utils/io.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# -----------------------------------------------------------------------------
# Export Functions
diff --git a/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py b/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py
index 2cfba52d688..f75a38c1c66 100644
--- a/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py
+++ b/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Dynamically create a keymap which is used by the popup toolbar
# for accelerator key access.
diff --git a/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py b/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py
index 6389efba049..7172d7809f2 100644
--- a/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py
+++ b/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"generate",
)
@@ -90,6 +88,10 @@ _km_hierarchy = [
_km_expand_from_toolsystem('VIEW_3D', 'SCULPT'),
]),
+ ('Sculpt Curves', 'EMPTY', 'WINDOW', [
+ _km_expand_from_toolsystem('VIEW_3D', 'CURVES_SCULPT'),
+ ]),
+
('Particle', 'EMPTY', 'WINDOW', [
_km_expand_from_toolsystem('VIEW_3D', 'PARTICLE'),
]),
diff --git a/release/scripts/modules/bl_keymap_utils/versioning.py b/release/scripts/modules/bl_keymap_utils/versioning.py
index ba83892c12c..65febf2c399 100644
--- a/release/scripts/modules/bl_keymap_utils/versioning.py
+++ b/release/scripts/modules/bl_keymap_utils/versioning.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Update Blender version this key-map was written in:
#
# When the version is `(0, 0, 0)`, the key-map being loaded didn't contain any versioning information.
diff --git a/release/scripts/modules/bl_previews_utils/bl_previews_render.py b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
index bf2b9fe1a76..bafc62330ea 100644
--- a/release/scripts/modules/bl_previews_utils/bl_previews_render.py
+++ b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Populate a template file (POT format currently) from Blender RNA/py/C data.
# Note: This script is meant to be used from inside Blender!
diff --git a/release/scripts/modules/bl_rna_utils/data_path.py b/release/scripts/modules/bl_rna_utils/data_path.py
index e15d9bc2d1c..d0c1fa57db8 100644
--- a/release/scripts/modules/bl_rna_utils/data_path.py
+++ b/release/scripts/modules/bl_rna_utils/data_path.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"property_definition_from_data_path",
"decompose_data_path",
diff --git a/release/scripts/modules/bl_ui_utils/bug_report_url.py b/release/scripts/modules/bl_ui_utils/bug_report_url.py
index 28af7aaa013..6755c2bad9d 100644
--- a/release/scripts/modules/bl_ui_utils/bug_report_url.py
+++ b/release/scripts/modules/bl_ui_utils/bug_report_url.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
def url_prefill_from_blender(*, addon_info=None):
import bpy
diff --git a/release/scripts/modules/blend_render_info.py b/release/scripts/modules/blend_render_info.py
index f8d22052290..37c5f6dd3ba 100755
--- a/release/scripts/modules/blend_render_info.py
+++ b/release/scripts/modules/blend_render_info.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This module can get render info without running from inside blender.
#
# This struct won't change according to Ton.
@@ -14,24 +12,65 @@
# int SDNAnr, nr;
# } BHead;
+__all__ = (
+ "read_blend_rend_chunk",
+)
+
+
+class RawBlendFileReader:
+ """
+ Return a file handle to the raw blend file data (abstracting compressed formats).
+ """
+ __slots__ = (
+ # The path to load.
+ "_filepath",
+ # The file base file handler or None (only set for compressed formats).
+ "_blendfile_base",
+ # The file handler to return to the caller (always uncompressed data).
+ "_blendfile",
+ )
+
+ def __init__(self, filepath):
+ self._filepath = filepath
+ self._blendfile_base = None
+ self._blendfile = None
+
+ def __enter__(self):
+ blendfile = open(self._filepath, "rb")
+ blendfile_base = None
+ head = blendfile.read(4)
+ blendfile.seek(0)
+ if head[0:2] == b'\x1f\x8b': # GZIP magic.
+ import gzip
+ blendfile_base = blendfile
+ blendfile = gzip.open(blendfile, "rb")
+ elif head[0:4] == b'\x28\xb5\x2f\xfd': # Z-standard magic.
+ import zstandard
+ blendfile_base = blendfile
+ blendfile = zstandard.open(blendfile, "rb")
-def read_blend_rend_chunk(path):
+ self._blendfile_base = blendfile_base
+ self._blendfile = blendfile
- import struct
+ return self._blendfile
- blendfile = open(path, "rb")
+ def __exit__(self, exc_type, exc_value, exc_traceback):
+ self._blendfile.close()
+ if self._blendfile_base is not None:
+ self._blendfile_base.close()
- head = blendfile.read(7)
+ return False
- if head[0:2] == b'\x1f\x8b': # gzip magic
- import gzip
- blendfile.seek(0)
- blendfile = gzip.open(blendfile, "rb")
- head = blendfile.read(7)
+def _read_blend_rend_chunk_from_file(blendfile, filepath):
+ import struct
+ import sys
+
+ from os import SEEK_CUR
+
+ head = blendfile.read(7)
if head != b'BLENDER':
- print("not a blend file:", path)
- blendfile.close()
+ sys.stderr.write("Not a blend file: %s\n" % filepath)
return []
is_64_bit = (blendfile.read(1) == b'-')
@@ -39,47 +78,62 @@ def read_blend_rend_chunk(path):
# true for PPC, false for X86
is_big_endian = (blendfile.read(1) == b'V')
- # Now read the bhead chunk!!!
- blendfile.read(3) # skip the version
+ # Now read the bhead chunk!
+ blendfile.seek(3, SEEK_CUR) # Skip the version.
scenes = []
sizeof_bhead = 24 if is_64_bit else 20
- while blendfile.read(4) == b'REND':
- sizeof_bhead_left = sizeof_bhead - 4
+ # Should always be 4, but a malformed/corrupt file may be less.
+ while (bhead_id := blendfile.read(4)) != b'ENDB':
- struct.unpack('>i' if is_big_endian else '<i', blendfile.read(4))[0]
- sizeof_bhead_left -= 4
+ if len(bhead_id) != 4:
+ sys.stderr.write("Unable to read until ENDB block (corrupt file): %s\n" % filepath)
+ break
- # We don't care about the rest of the bhead struct
- blendfile.read(sizeof_bhead_left)
+ sizeof_data_left = struct.unpack('>i' if is_big_endian else '<i', blendfile.read(4))[0]
+ # 4 from the `head_id`, another 4 for the size of the BHEAD.
+ sizeof_bhead_left = sizeof_bhead - 8
- # Now we want the scene name, start and end frame. this is 32bites long
- start_frame, end_frame = struct.unpack('>2i' if is_big_endian else '<2i', blendfile.read(8))
+ # The remainder of the BHEAD struct is not used.
+ blendfile.seek(sizeof_bhead_left, SEEK_CUR)
- scene_name = blendfile.read(64)
+ if bhead_id == b'REND':
+ # Now we want the scene name, start and end frame. this is 32bits long.
+ start_frame, end_frame = struct.unpack('>2i' if is_big_endian else '<2i', blendfile.read(8))
+ sizeof_data_left -= 8
- scene_name = scene_name[:scene_name.index(b'\0')]
+ scene_name = blendfile.read(64)
+ sizeof_data_left -= 64
- try:
- scene_name = str(scene_name, "utf8")
- except TypeError:
- pass
+ scene_name = scene_name[:scene_name.index(b'\0')]
+ # It's possible old blend files are not UTF8 compliant, use `surrogateescape`.
+ scene_name = scene_name.decode("utf8", errors='surrogateescape')
- scenes.append((start_frame, end_frame, scene_name))
+ scenes.append((start_frame, end_frame, scene_name))
- blendfile.close()
+ if sizeof_data_left > 0:
+ blendfile.seek(sizeof_data_left, SEEK_CUR)
+ elif sizeof_data_left < 0:
+ # Very unlikely, but prevent attempting to further parse corrupt data.
+ sys.stderr.write("Error calculating next block (corrupt file): %s\n" % filepath)
+ break
return scenes
+def read_blend_rend_chunk(filepath):
+ with RawBlendFileReader(filepath) as blendfile:
+ return _read_blend_rend_chunk_from_file(blendfile, filepath)
+
+
def main():
import sys
- for arg in sys.argv[1:]:
- if arg.lower().endswith('.blend'):
- for value in read_blend_rend_chunk(arg):
- print("%d %d %s" % value)
+
+ for filepath in sys.argv[1:]:
+ for value in read_blend_rend_chunk(filepath):
+ print("%d %d %s" % value)
if __name__ == '__main__':
diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py
index 35848602f9d..fd7a573dc06 100644
--- a/release/scripts/modules/bpy/__init__.py
+++ b/release/scripts/modules/bpy/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
Give access to blender data and utility functions.
"""
diff --git a/release/scripts/modules/bpy/ops.py b/release/scripts/modules/bpy/ops.py
index e19128e41a9..cb6ea0318a4 100644
--- a/release/scripts/modules/bpy/ops.py
+++ b/release/scripts/modules/bpy/ops.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
# for slightly faster access
from _bpy import ops as _ops_module
diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py
index 88c34be6906..60b8159b896 100644
--- a/release/scripts/modules/bpy/path.py
+++ b/release/scripts/modules/bpy/path.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
This module has a similar scope to os.path, containing utility
functions for dealing with paths in Blender.
diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py
index 5cd2bd2f076..54fcb4cdc67 100644
--- a/release/scripts/modules/bpy/utils/__init__.py
+++ b/release/scripts/modules/bpy/utils/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
This module contains utility functions specific to blender but
not associated with blenders internal data.
diff --git a/release/scripts/modules/bpy/utils/previews.py b/release/scripts/modules/bpy/utils/previews.py
index 1f398176643..5826de725c8 100644
--- a/release/scripts/modules/bpy/utils/previews.py
+++ b/release/scripts/modules/bpy/utils/previews.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
This module contains utility functions to handle custom previews.
diff --git a/release/scripts/modules/bpy/utils/toolsystem.py b/release/scripts/modules/bpy/utils/toolsystem.py
index dbcf56900a1..6aa7f885239 100644
--- a/release/scripts/modules/bpy/utils/toolsystem.py
+++ b/release/scripts/modules/bpy/utils/toolsystem.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Until we untangle ToolDef from bl_ui internals,
# use this module to document ToolDef.
from bl_ui.space_toolsystem_common import ToolDef
diff --git a/release/scripts/modules/bpy_extras/__init__.py b/release/scripts/modules/bpy_extras/__init__.py
index 15a8d00cddc..f018789d858 100644
--- a/release/scripts/modules/bpy_extras/__init__.py
+++ b/release/scripts/modules/bpy_extras/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
Utility modules associated with the bpy module.
"""
diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py
index 1b1df41d2c6..f66dfd6eb0a 100644
--- a/release/scripts/modules/bpy_extras/anim_utils.py
+++ b/release/scripts/modules/bpy_extras/anim_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"bake_action",
"bake_action_objects",
diff --git a/release/scripts/modules/bpy_extras/asset_utils.py b/release/scripts/modules/bpy_extras/asset_utils.py
index 70c02272fd2..a6f2a709977 100644
--- a/release/scripts/modules/bpy_extras/asset_utils.py
+++ b/release/scripts/modules/bpy_extras/asset_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Helpers for asset management tasks.
"""
diff --git a/release/scripts/modules/bpy_extras/id_map_utils.py b/release/scripts/modules/bpy_extras/id_map_utils.py
index cf39f2185c6..9aa7cc9e07c 100644
--- a/release/scripts/modules/bpy_extras/id_map_utils.py
+++ b/release/scripts/modules/bpy_extras/id_map_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from typing import Dict, Set
import bpy
from bpy.types import ID
diff --git a/release/scripts/modules/bpy_extras/image_utils.py b/release/scripts/modules/bpy_extras/image_utils.py
index eaf5922a199..48a50d52e60 100644
--- a/release/scripts/modules/bpy_extras/image_utils.py
+++ b/release/scripts/modules/bpy_extras/image_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"load_image",
)
diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py
index 3a73603ba85..0497d69162e 100644
--- a/release/scripts/modules/bpy_extras/io_utils.py
+++ b/release/scripts/modules/bpy_extras/io_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"ExportHelper",
"ImportHelper",
diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py
index 1b8f3ac3fd8..b87641874cd 100644
--- a/release/scripts/modules/bpy_extras/keyconfig_utils.py
+++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# -----------------------------------------------------------------------------
# Add-on helpers to properly (un)register their own keymaps.
diff --git a/release/scripts/modules/bpy_extras/mesh_utils.py b/release/scripts/modules/bpy_extras/mesh_utils.py
index a6f71dc0a2a..f6dc33e4f02 100644
--- a/release/scripts/modules/bpy_extras/mesh_utils.py
+++ b/release/scripts/modules/bpy_extras/mesh_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"mesh_linked_uv_islands",
"mesh_linked_triangles",
diff --git a/release/scripts/modules/bpy_extras/node_shader_utils.py b/release/scripts/modules/bpy_extras/node_shader_utils.py
index 522357296fd..cda291c6c90 100644
--- a/release/scripts/modules/bpy_extras/node_shader_utils.py
+++ b/release/scripts/modules/bpy_extras/node_shader_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from mathutils import Color, Vector
__all__ = (
diff --git a/release/scripts/modules/bpy_extras/node_utils.py b/release/scripts/modules/bpy_extras/node_utils.py
index 639ebc46e16..3fec65db5a5 100644
--- a/release/scripts/modules/bpy_extras/node_utils.py
+++ b/release/scripts/modules/bpy_extras/node_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"find_node_input",
)
diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py
index 6829aed5565..ab678ba27c8 100644
--- a/release/scripts/modules/bpy_extras/object_utils.py
+++ b/release/scripts/modules/bpy_extras/object_utils.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
__all__ = (
diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py
index 7de363483e5..c661d017ca0 100644
--- a/release/scripts/modules/bpy_extras/view3d_utils.py
+++ b/release/scripts/modules/bpy_extras/view3d_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"region_2d_to_vector_3d",
"region_2d_to_origin_3d",
diff --git a/release/scripts/modules/bpy_extras/wm_utils/progress_report.py b/release/scripts/modules/bpy_extras/wm_utils/progress_report.py
index da9ef735e0d..637d60838db 100644
--- a/release/scripts/modules/bpy_extras/wm_utils/progress_report.py
+++ b/release/scripts/modules/bpy_extras/wm_utils/progress_report.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import time
diff --git a/release/scripts/modules/bpy_restrict_state.py b/release/scripts/modules/bpy_restrict_state.py
index 78d4b4be972..31a0c52ecf5 100644
--- a/release/scripts/modules/bpy_restrict_state.py
+++ b/release/scripts/modules/bpy_restrict_state.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
This module contains RestrictBlend context manager.
"""
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index 4c6e2508859..aaa2ae59a0d 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
from _bpy import types as bpy_types
StructRNA = bpy_types.bpy_struct
diff --git a/release/scripts/modules/console_python.py b/release/scripts/modules/console_python.py
index b7e86d5c673..2aa4caab7f6 100644
--- a/release/scripts/modules/console_python.py
+++ b/release/scripts/modules/console_python.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
import sys
import bpy
diff --git a/release/scripts/modules/console_shell.py b/release/scripts/modules/console_shell.py
index ff8a30557d2..194f636a97e 100644
--- a/release/scripts/modules/console_shell.py
+++ b/release/scripts/modules/console_shell.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import os
import bpy
diff --git a/release/scripts/modules/graphviz_export.py b/release/scripts/modules/graphviz_export.py
index a121cc3ed06..b6e73590386 100644
--- a/release/scripts/modules/graphviz_export.py
+++ b/release/scripts/modules/graphviz_export.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
header = '''
diff --git a/release/scripts/modules/keyingsets_utils.py b/release/scripts/modules/keyingsets_utils.py
index e48be9a95ea..b566889bfb9 100644
--- a/release/scripts/modules/keyingsets_utils.py
+++ b/release/scripts/modules/keyingsets_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
# This file defines a set of methods that are useful for various
# Relative Keying Set (RKS) related operations, such as: callbacks
# for polling, iterator callbacks, and also generate callbacks.
diff --git a/release/scripts/modules/nodeitems_utils.py b/release/scripts/modules/nodeitems_utils.py
index 819deec8cc0..231720ea519 100644
--- a/release/scripts/modules/nodeitems_utils.py
+++ b/release/scripts/modules/nodeitems_utils.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py
index 4788ed6a5fa..e2bbc4077a1 100644
--- a/release/scripts/modules/rna_info.py
+++ b/release/scripts/modules/rna_info.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# classes for extracting info from blenders internal classes
import bpy
diff --git a/release/scripts/modules/rna_keymap_ui.py b/release/scripts/modules/rna_keymap_ui.py
index 5da98cd783d..a7ad162ba66 100644
--- a/release/scripts/modules/rna_keymap_ui.py
+++ b/release/scripts/modules/rna_keymap_ui.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"draw_entry",
"draw_km",
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index a6842dc0005..8b8cfaaccc5 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from mathutils import Vector
diff --git a/release/scripts/modules/rna_xml.py b/release/scripts/modules/rna_xml.py
index d576aeec860..9e3e1a3430b 100644
--- a/release/scripts/modules/rna_xml.py
+++ b/release/scripts/modules/rna_xml.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py
index 80f518e4aee..a5bae1b97af 100644
--- a/release/scripts/modules/sys_info.py
+++ b/release/scripts/modules/sys_info.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# classes for extracting info from blenders internal classes
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 1cdb2c8e679..7d0929ef28f 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -463,6 +463,7 @@ def _template_items_tool_select(
# Always use the cursor operator where possible,
# needed for time-line views where we always want to be able to scrub time.
cursor_prioritize=False,
+ operator_props=(),
fallback=False,
):
if not params.legacy and not fallback:
@@ -479,11 +480,11 @@ def _template_items_tool_select(
if select_passthrough:
return [
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS'},
- {"properties": [("deselect_all", True), ("select_passthrough", True)]}),
+ {"properties": [("deselect_all", True), ("select_passthrough", True), *operator_props]}),
(operator, {"type": 'LEFTMOUSE', "value": 'CLICK'},
- {"properties": [("deselect_all", True)]}),
+ {"properties": [("deselect_all", True), *operator_props]}),
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
- {"properties": [("deselect_all", False), ("toggle", True)]}),
+ {"properties": [("deselect_all", False), ("toggle", True), *operator_props]}),
("transform.translate", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'},
{"properties": [("release_confirm", True)]}),
]
@@ -497,9 +498,9 @@ def _template_items_tool_select(
# the tool without selecting elements under the cursor.
return [
(operator, {"type": 'LEFTMOUSE', "value": 'CLICK' if fallback else 'PRESS'},
- {"properties": [("deselect_all", True)]}),
+ {"properties": [("deselect_all", True), *operator_props]}),
(operator, {"type": 'LEFTMOUSE', "value": 'CLICK' if fallback else 'PRESS', "shift": True},
- {"properties": [("toggle", True)]}),
+ {"properties": [("toggle", True), *operator_props]}),
# Fallback key-map must transform as the primary tool is expected
# to be accessed via gizmos in this case. See: T96885.
@@ -2222,6 +2223,7 @@ def km_file_browser(params):
("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None),
("file.bookmark_add", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
("file.start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
+ ("file.edit_directory_path", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "repeat": True},
{"properties": [("increment", 1)]}),
("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True, "repeat": True},
@@ -3012,7 +3014,7 @@ def km_sequencerpreview(params):
return keymap
-def km_sequencer_channels(params):
+def km_sequencer_channels(_params):
items = []
keymap = (
"Sequencer Channels",
@@ -5587,6 +5589,17 @@ def km_font(params):
return keymap
+# Curves edit mode.
+def km_curves(params):
+ items = []
+ keymap = (
+ "Curves",
+ {"space_type": 'EMPTY', "region_type": 'WINDOW'},
+ {"items": items},
+ )
+
+ return keymap
+
def km_sculpt_curves(params):
items = []
@@ -5923,6 +5936,8 @@ def km_standard_modal_map(_params):
("APPLY", {"type": 'NUMPAD_ENTER', "value": 'PRESS', "any": True}, None),
("SNAP", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": True}, None),
("SNAP_OFF", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": True}, None),
+ ("SNAP", {"type": 'RIGHT_CTRL', "value": 'PRESS', "any": True}, None),
+ ("SNAP_OFF", {"type": 'RIGHT_CTRL', "value": 'RELEASE', "any": True}, None),
])
return keymap
@@ -6069,10 +6084,16 @@ def km_view3d_fly_modal(_params):
("AXIS_LOCK_Z", {"type": 'Z', "value": 'PRESS'}, None),
("PRECISION_ENABLE", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
("PRECISION_DISABLE", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
+ ("PRECISION_ENABLE", {"type": 'RIGHT_ALT', "value": 'PRESS', "any": True}, None),
+ ("PRECISION_DISABLE", {"type": 'RIGHT_ALT', "value": 'RELEASE', "any": True}, None),
("PRECISION_ENABLE", {"type": 'LEFT_SHIFT', "value": 'PRESS', "any": True}, None),
("PRECISION_DISABLE", {"type": 'LEFT_SHIFT', "value": 'RELEASE', "any": True}, None),
+ ("PRECISION_ENABLE", {"type": 'RIGHT_SHIFT', "value": 'PRESS', "any": True}, None),
+ ("PRECISION_DISABLE", {"type": 'RIGHT_SHIFT', "value": 'RELEASE', "any": True}, None),
("FREELOOK_ENABLE", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": True}, None),
("FREELOOK_DISABLE", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": True}, None),
+ ("FREELOOK_ENABLE", {"type": 'RIGHT_CTRL', "value": 'PRESS', "any": True}, None),
+ ("FREELOOK_DISABLE", {"type": 'RIGHT_CTRL', "value": 'RELEASE', "any": True}, None),
])
return keymap
@@ -6094,8 +6115,12 @@ def km_view3d_walk_modal(_params):
("CONFIRM", {"type": 'NUMPAD_ENTER', "value": 'PRESS', "any": True}, None),
("FAST_ENABLE", {"type": 'LEFT_SHIFT', "value": 'PRESS', "any": True}, None),
("FAST_DISABLE", {"type": 'LEFT_SHIFT', "value": 'RELEASE', "any": True}, None),
+ ("FAST_ENABLE", {"type": 'RIGHT_SHIFT', "value": 'PRESS', "any": True}, None),
+ ("FAST_DISABLE", {"type": 'RIGHT_SHIFT', "value": 'RELEASE', "any": True}, None),
("SLOW_ENABLE", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
("SLOW_DISABLE", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
+ ("SLOW_ENABLE", {"type": 'RIGHT_ALT', "value": 'PRESS', "any": True}, None),
+ ("SLOW_DISABLE", {"type": 'RIGHT_ALT', "value": 'RELEASE', "any": True}, None),
("FORWARD", {"type": 'W', "value": 'PRESS', "any": True}, None),
("BACKWARD", {"type": 'S', "value": 'PRESS', "any": True}, None),
("LEFT", {"type": 'A', "value": 'PRESS', "any": True}, None),
@@ -6145,6 +6170,8 @@ def km_view3d_rotate_modal(_params):
("CONFIRM", {"type": 'ESC', "value": 'PRESS', "any": True}, None),
("AXIS_SNAP_ENABLE", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
("AXIS_SNAP_DISABLE", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
+ ("AXIS_SNAP_ENABLE", {"type": 'RIGHT_ALT', "value": 'PRESS', "any": True}, None),
+ ("AXIS_SNAP_DISABLE", {"type": 'RIGHT_ALT', "value": 'RELEASE', "any": True}, None),
])
return keymap
@@ -6234,6 +6261,7 @@ def km_sculpt_expand_modal(_params):
*((e, {"type": NUMBERS_1[i], "value": 'PRESS', "any": True}, None) for i, e in enumerate(
("FALLOFF_GEODESICS", "FALLOFF_TOPOLOGY", "FALLOFF_TOPOLOGY_DIAGONALS", "FALLOFF_SPHERICAL"))),
("SNAP_TOGGLE", {"type": 'LEFT_CTRL', "value": 'ANY'}, None),
+ ("SNAP_TOGGLE", {"type": 'RIGHT_CTRL', "value": 'ANY'}, None),
("LOOP_COUNT_INCREASE", {"type": 'W', "value": 'PRESS', "any": True, "repeat": True}, None),
("LOOP_COUNT_DECREASE", {"type": 'Q', "value": 'PRESS', "any": True, "repeat": True}, None),
("BRUSH_GRADIENT_TOGGLE", {"type": 'B', "value": 'PRESS', "any": True}, None),
@@ -6655,12 +6683,17 @@ def km_3d_view_tool_cursor(params):
def km_3d_view_tool_select(params, *, fallback):
+ if params.use_tweak_select_passthrough:
+ operator_props = (("vert_without_handles", True),)
+ else:
+ operator_props = ()
+
return (
_fallback_id("3D View Tool: Tweak", fallback),
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
*([] if (fallback and (params.select_mouse == 'RIGHTMOUSE')) else _template_items_tool_select(
- params, "view3d.select", "view3d.cursor3d", fallback=fallback)),
+ params, "view3d.select", "view3d.cursor3d", operator_props=operator_props, fallback=fallback)),
*([] if (not params.use_fallback_tool_rmb) else _template_view3d_select(
type=params.select_mouse,
value=params.select_mouse_value,
@@ -7992,6 +8025,7 @@ def generate_keymaps(params=None):
km_lattice(params),
km_particle(params),
km_font(params),
+ km_curves(params),
km_sculpt_curves(params),
km_object_non_modal(params),
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index bf7783ef958..14dc72336f6 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from __future__ import annotations
# support reloading sub-modules
diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py
index be5ce60af2f..90d1326e1a2 100644
--- a/release/scripts/startup/bl_operators/add_mesh_torus.py
+++ b/release/scripts/startup/bl_operators/add_mesh_torus.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
import bpy
diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py
index dfe3b3ba57c..539cf838f9c 100644
--- a/release/scripts/startup/bl_operators/anim.py
+++ b/release/scripts/startup/bl_operators/anim.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
if "bpy" in locals():
diff --git a/release/scripts/startup/bl_operators/assets.py b/release/scripts/startup/bl_operators/assets.py
index eaf44442c8a..088f4189ca5 100644
--- a/release/scripts/startup/bl_operators/assets.py
+++ b/release/scripts/startup/bl_operators/assets.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/release/scripts/startup/bl_operators/bmesh/find_adjacent.py b/release/scripts/startup/bl_operators/bmesh/find_adjacent.py
index 5e8b125e060..a6c4a3169d5 100644
--- a/release/scripts/startup/bl_operators/bmesh/find_adjacent.py
+++ b/release/scripts/startup/bl_operators/bmesh/find_adjacent.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Utilities to detect the next matching element (vert/edge/face)
# based on an existing pair of elements.
diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py
index 23bf8a5cb60..71617a76243 100644
--- a/release/scripts/startup/bl_operators/clip.py
+++ b/release/scripts/startup/bl_operators/clip.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Operator
from bpy.props import FloatProperty
diff --git a/release/scripts/startup/bl_operators/console.py b/release/scripts/startup/bl_operators/console.py
index 3982f140fec..eb8c4c371c5 100644
--- a/release/scripts/startup/bl_operators/console.py
+++ b/release/scripts/startup/bl_operators/console.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
import bpy
diff --git a/release/scripts/startup/bl_operators/constraint.py b/release/scripts/startup/bl_operators/constraint.py
index 444452ad2c5..6d040c29b62 100644
--- a/release/scripts/startup/bl_operators/constraint.py
+++ b/release/scripts/startup/bl_operators/constraint.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
from bpy.types import (
diff --git a/release/scripts/startup/bl_operators/file.py b/release/scripts/startup/bl_operators/file.py
index 0fafb09f672..490fab113c6 100644
--- a/release/scripts/startup/bl_operators/file.py
+++ b/release/scripts/startup/bl_operators/file.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Operator,
diff --git a/release/scripts/startup/bl_operators/freestyle.py b/release/scripts/startup/bl_operators/freestyle.py
index c5eda7249e1..02b784357b0 100644
--- a/release/scripts/startup/bl_operators/freestyle.py
+++ b/release/scripts/startup/bl_operators/freestyle.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py
index 42f7b1730a8..97308b6894f 100644
--- a/release/scripts/startup/bl_operators/image.py
+++ b/release/scripts/startup/bl_operators/image.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Operator
from bpy.props import StringProperty
diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py
index f3f69530c87..f68df9845ef 100644
--- a/release/scripts/startup/bl_operators/mesh.py
+++ b/release/scripts/startup/bl_operators/mesh.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Operator
diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py
index 60a684ae5e8..bad12ff4621 100644
--- a/release/scripts/startup/bl_operators/node.py
+++ b/release/scripts/startup/bl_operators/node.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
import bpy
@@ -131,6 +129,15 @@ class NodeAddOperator:
return result
+ @classmethod
+ def description(cls, _context, properties):
+ nodetype = properties["type"]
+ bl_rna = bpy.types.Node.bl_rna_get_subclass(nodetype)
+ if bl_rna is not None:
+ return bl_rna.description
+ else:
+ return ""
+
# Simple basic operator for adding a node
class NODE_OT_add_node(NodeAddOperator, Operator):
diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py
index 0b146d689f5..6e08d557353 100644
--- a/release/scripts/startup/bl_operators/object.py
+++ b/release/scripts/startup/bl_operators/object.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Operator
from bpy.props import (
@@ -598,6 +596,8 @@ class MakeDupliFace(Operator):
for obj in context.selected_objects:
if obj.type == 'MESH':
linked[obj.data].append(obj)
+ elif obj.type == 'EMPTY' and obj.instance_type == 'COLLECTION' and obj.instance_collection:
+ linked[obj.instance_collection].append(obj)
for data, objects in linked.items():
face_verts = [axis for obj in objects
@@ -623,7 +623,12 @@ class MakeDupliFace(Operator):
ob_new = bpy.data.objects.new(mesh.name, mesh)
context.collection.objects.link(ob_new)
- ob_inst = bpy.data.objects.new(data.name, data)
+ if type(data) is bpy.types.Collection:
+ ob_inst = bpy.data.objects.new(data.name, None)
+ ob_inst.instance_type = 'COLLECTION'
+ ob_inst.instance_collection = data
+ else:
+ ob_inst = bpy.data.objects.new(data.name, data)
context.collection.objects.link(ob_inst)
ob_new.instance_type = 'FACES'
@@ -857,6 +862,37 @@ class DupliOffsetFromCursor(Operator):
return {'FINISHED'}
+class DupliOffsetToCursor(Operator):
+ """Set cursor position to the offset used for collection instances"""
+ bl_idname = "object.instance_offset_to_cursor"
+ bl_label = "Set Cursor to Offset"
+ bl_options = {'INTERNAL', 'UNDO'}
+
+ def execute(self, context):
+ scene = context.scene
+ collection = context.collection
+ scene.cursor.location = collection.instance_offset
+ return {'FINISHED'}
+
+
+class DupliOffsetFromObject(Operator):
+ """Set offset used for collection instances based on the active object position"""
+ bl_idname = "object.instance_offset_from_object"
+ bl_label = "Set Offset from Object"
+ bl_options = {'INTERNAL', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None)
+
+ def execute(self, context):
+ ob_eval = context.active_object.evaluated_get(context.view_layer.depsgraph)
+ world_loc = ob_eval.matrix_world.to_translation()
+ collection = context.collection
+ collection.instance_offset = world_loc
+ return {'FINISHED'}
+
+
class LoadImageAsEmpty:
bl_options = {'REGISTER', 'UNDO'}
@@ -978,6 +1014,8 @@ class OBJECT_OT_assign_property_defaults(Operator):
classes = (
ClearAllRestrictRender,
DupliOffsetFromCursor,
+ DupliOffsetToCursor,
+ DupliOffsetFromObject,
IsolateTypeRender,
JoinUVs,
LoadBackgroundImage,
diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py
index f645d8618da..5171f088dd2 100644
--- a/release/scripts/startup/bl_operators/object_align.py
+++ b/release/scripts/startup/bl_operators/object_align.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
from bpy.types import Operator
from mathutils import Vector
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index 9f3dd75a316..cd9fd9af472 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
from mathutils import Vector
import bpy
from bpy.types import Operator
diff --git a/release/scripts/startup/bl_operators/object_randomize_transform.py b/release/scripts/startup/bl_operators/object_randomize_transform.py
index f1864174db7..0b8b2868349 100644
--- a/release/scripts/startup/bl_operators/object_randomize_transform.py
+++ b/release/scripts/startup/bl_operators/object_randomize_transform.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
from bpy.types import Operator
from mathutils import Vector
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index 704693a1469..cde4348977f 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Menu,
diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py
index 5aab842d672..fffd010b768 100644
--- a/release/scripts/startup/bl_operators/rigidbody.py
+++ b/release/scripts/startup/bl_operators/rigidbody.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Operator
from bpy.props import (
diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
index 78efe9c4af0..39c95e3ed5e 100644
--- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
+++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
# Originally written by Matt Ebb
import bpy
diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py
index 0d4cc53173d..8b12bbb78a9 100644
--- a/release/scripts/startup/bl_operators/sequencer.py
+++ b/release/scripts/startup/bl_operators/sequencer.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Operator
diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py
index 49bc2d0a2da..54de9c28144 100644
--- a/release/scripts/startup/bl_operators/userpref.py
+++ b/release/scripts/startup/bl_operators/userpref.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Operator,
diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
index fd5cf5303b3..a5c91f238d2 100644
--- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py
+++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import Operator
from bpy.props import (
diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
index f62b98462dc..93c72c97129 100644
--- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py
+++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Operator
import mathutils
diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
index 8089a65960c..a3c0b73fc0e 100644
--- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py
+++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
@@ -1,8 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright Campbell Barton.
-# <pep8 compliant>
-
def get_vcolor_layer_data(me):
for lay in me.vertex_colors:
diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py
index 50cdf1a530e..59e668d81ea 100644
--- a/release/scripts/startup/bl_operators/view3d.py
+++ b/release/scripts/startup/bl_operators/view3d.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Operator
from bpy.props import (
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 37d7ef19a28..50fc6bad720 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
@@ -1354,7 +1352,7 @@ class WM_OT_properties_edit(Operator):
items=rna_custom_property_type_items,
)
is_overridable_library: BoolProperty(
- name="Is Library Overridable",
+ name="Library Overridable",
description="Allow the property to be overridden when the data-block is linked",
default=False,
)
@@ -1365,7 +1363,7 @@ class WM_OT_properties_edit(Operator):
# Shared for integer and string properties.
use_soft_limits: BoolProperty(
- name="Use Soft Limits",
+ name="Soft Limits",
description=(
"Limits the Property Value slider to a range, "
"values outside the range must be inputted numerically"
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index b3b4ab8e52c..c61dde87d7c 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# note, properties_animviz is a helper module only.
# support reloading sub-modules
diff --git a/release/scripts/startup/bl_ui/properties_animviz.py b/release/scripts/startup/bl_ui/properties_animviz.py
index 9aac33eb5de..3062b84bd70 100644
--- a/release/scripts/startup/bl_ui/properties_animviz.py
+++ b/release/scripts/startup/bl_ui/properties_animviz.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Generic Panels (Independent of DataType)
# NOTE:
diff --git a/release/scripts/startup/bl_ui/properties_collection.py b/release/scripts/startup/bl_ui/properties_collection.py
index 88c6a4c217d..bd43ab32f37 100644
--- a/release/scripts/startup/bl_ui/properties_collection.py
+++ b/release/scripts/startup/bl_ui/properties_collection.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
-from bpy.types import Panel
+from bpy.types import Panel, Menu
class CollectionButtonsPanel:
@@ -44,6 +42,16 @@ class COLLECTION_PT_collection_flags(CollectionButtonsPanel, Panel):
col.prop(vlc, "indirect_only", toggle=False)
+class COLLECTION_MT_context_menu_instance_offset(Menu):
+ bl_label = "Instance Offset"
+
+ def draw(self, _context):
+ layout = self.layout
+ layout.operator("object.instance_offset_from_cursor")
+ layout.operator("object.instance_offset_from_object")
+ layout.operator("object.instance_offset_to_cursor")
+
+
class COLLECTION_PT_instancing(CollectionButtonsPanel, Panel):
bl_label = "Instancing"
@@ -53,8 +61,9 @@ class COLLECTION_PT_instancing(CollectionButtonsPanel, Panel):
layout.use_property_decorate = False
collection = context.collection
- row = layout.row()
+ row = layout.row(align=True)
row.prop(collection, "instance_offset")
+ row.menu("COLLECTION_MT_context_menu_instance_offset", icon='DOWNARROW_HLT', text="")
class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
@@ -82,6 +91,7 @@ class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
classes = (
+ COLLECTION_MT_context_menu_instance_offset,
COLLECTION_PT_collection_flags,
COLLECTION_PT_instancing,
COLLECTION_PT_lineart_collection,
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index bd63368bdfd..d949ee779e1 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py
index 58ccaffaf50..22d6a45c48c 100644
--- a/release/scripts/startup/bl_ui/properties_data_armature.py
+++ b/release/scripts/startup/bl_ui/properties_data_armature.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py
index 9a790663581..c842af9af88 100644
--- a/release/scripts/startup/bl_ui/properties_data_bone.py
+++ b/release/scripts/startup/bl_ui/properties_data_bone.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py
index 696143494fe..8213a865990 100644
--- a/release/scripts/startup/bl_ui/properties_data_camera.py
+++ b/release/scripts/startup/bl_ui/properties_data_camera.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index a421428c067..4da7cd0283b 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_curves.py b/release/scripts/startup/bl_ui/properties_data_curves.py
index cf7117f2c85..4a11c5edde6 100644
--- a/release/scripts/startup/bl_ui/properties_data_curves.py
+++ b/release/scripts/startup/bl_ui/properties_data_curves.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
@@ -46,6 +44,7 @@ class DATA_PT_curves_surface(DataButtonsPanel, Panel):
layout.use_property_split = True
layout.prop(ob.data, "surface")
+ layout.prop(ob.data, "surface_uv_map", text="UV Map")
class CURVES_MT_add_attribute(Menu):
@@ -78,12 +77,12 @@ class CURVES_MT_add_attribute(Menu):
class CURVES_UL_attributes(UIList):
- def filter_items(self, context, data, property):
+ def filter_items(self, _context, data, property):
attributes = getattr(data, property)
flags = []
indices = [i for i in range(len(attributes))]
- for index, item in enumerate(attributes):
+ for item in attributes:
flags.append(self.bitflag_filter_item if item.is_internal else 0)
return flags, indices
diff --git a/release/scripts/startup/bl_ui/properties_data_empty.py b/release/scripts/startup/bl_ui/properties_data_empty.py
index 6c5c94e9d6a..8dd7f8312ae 100644
--- a/release/scripts/startup/bl_ui/properties_data_empty.py
+++ b/release/scripts/startup/bl_ui/properties_data_empty.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py
index df72b1182df..9d95332a901 100644
--- a/release/scripts/startup/bl_ui/properties_data_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_lattice.py b/release/scripts/startup/bl_ui/properties_data_lattice.py
index b4bf09107c5..618f73ecc06 100644
--- a/release/scripts/startup/bl_ui/properties_data_lattice.py
+++ b/release/scripts/startup/bl_ui/properties_data_lattice.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_light.py b/release/scripts/startup/bl_ui/properties_data_light.py
index aab37ff89ad..df3ad43e6de 100644
--- a/release/scripts/startup/bl_ui/properties_data_light.py
+++ b/release/scripts/startup/bl_ui/properties_data_light.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_lightprobe.py b/release/scripts/startup/bl_ui/properties_data_lightprobe.py
index 64ef4c17150..60f8dcc0946 100644
--- a/release/scripts/startup/bl_ui/properties_data_lightprobe.py
+++ b/release/scripts/startup/bl_ui/properties_data_lightprobe.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 9c15dec9b94..0b043905713 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
@@ -66,6 +64,18 @@ class MESH_MT_shape_key_context_menu(Menu):
layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").type = 'BOTTOM'
+class MESH_MT_color_attribute_context_menu(Menu):
+ bl_label = "Color Attribute Specials"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator(
+ "geometry.color_attribute_duplicate",
+ icon='DUPLICATE',
+ )
+
+
class MESH_MT_attribute_context_menu(Menu):
bl_label = "Attribute Specials"
@@ -497,12 +507,12 @@ class MESH_UL_attributes(UIList):
'CORNER': "Face Corner",
}
- def filter_items(self, context, data, property):
+ def filter_items(self, _context, data, property):
attributes = getattr(data, property)
flags = []
indices = [i for i in range(len(attributes))]
- for index, item in enumerate(attributes):
+ for item in attributes:
flags.append(self.bitflag_filter_item if item.is_internal else 0)
return flags, indices
@@ -586,7 +596,7 @@ class ColorAttributesListBase():
'CORNER': "Face Corner",
}
- def filter_items(self, context, data, property):
+ def filter_items(self, _context, data, property):
attrs = getattr(data, property)
ret = []
idxs = []
@@ -662,12 +672,17 @@ class DATA_PT_vertex_colors(DATA_PT_mesh_attributes, Panel):
col.operator("geometry.color_attribute_add", icon='ADD', text="")
col.operator("geometry.color_attribute_remove", icon='REMOVE', text="")
+ col.separator()
+
+ col.menu("MESH_MT_color_attribute_context_menu", icon='DOWNARROW_HLT', text="")
+
self.draw_attribute_warnings(context, layout)
classes = (
MESH_MT_vertex_group_context_menu,
MESH_MT_shape_key_context_menu,
+ MESH_MT_color_attribute_context_menu,
MESH_MT_attribute_context_menu,
MESH_UL_vgroups,
MESH_UL_fmaps,
diff --git a/release/scripts/startup/bl_ui/properties_data_metaball.py b/release/scripts/startup/bl_ui/properties_data_metaball.py
index 6c56b44bcb2..defb6d55169 100644
--- a/release/scripts/startup/bl_ui/properties_data_metaball.py
+++ b/release/scripts/startup/bl_ui/properties_data_metaball.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index 8750bce5923..a2f0e3d410a 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
diff --git a/release/scripts/startup/bl_ui/properties_data_pointcloud.py b/release/scripts/startup/bl_ui/properties_data_pointcloud.py
index 88d686b32f9..8ef6ad63bba 100644
--- a/release/scripts/startup/bl_ui/properties_data_pointcloud.py
+++ b/release/scripts/startup/bl_ui/properties_data_pointcloud.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
@@ -67,12 +65,12 @@ class POINTCLOUD_MT_add_attribute(Menu):
class POINTCLOUD_UL_attributes(UIList):
- def filter_items(self, context, data, property):
+ def filter_items(self, _context, data, property):
attributes = getattr(data, property)
flags = []
indices = [i for i in range(len(attributes))]
- for index, item in enumerate(attributes):
+ for item in attributes:
flags.append(self.bitflag_filter_item if item.is_internal else 0)
return flags, indices
diff --git a/release/scripts/startup/bl_ui/properties_data_shaderfx.py b/release/scripts/startup/bl_ui/properties_data_shaderfx.py
index 4883a9a2a03..4bf41865177 100644
--- a/release/scripts/startup/bl_ui/properties_data_shaderfx.py
+++ b/release/scripts/startup/bl_ui/properties_data_shaderfx.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
diff --git a/release/scripts/startup/bl_ui/properties_data_speaker.py b/release/scripts/startup/bl_ui/properties_data_speaker.py
index 449ae9f1d25..7934aa0bc92 100644
--- a/release/scripts/startup/bl_ui/properties_data_speaker.py
+++ b/release/scripts/startup/bl_ui/properties_data_speaker.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_volume.py b/release/scripts/startup/bl_ui/properties_data_volume.py
index 98855d4b516..460fcd7124b 100644
--- a/release/scripts/startup/bl_ui/properties_data_volume.py
+++ b/release/scripts/startup/bl_ui/properties_data_volume.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel, UIList
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py
index 98fcf3247a1..e74e1725aa2 100644
--- a/release/scripts/startup/bl_ui/properties_freestyle.py
+++ b/release/scripts/startup/bl_ui/properties_freestyle.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
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 0f1652b9813..8e5050be07e 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Menu, UIList, Operator
from bpy.app.translations import pgettext_iface as iface_
diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py
index d9f833e391e..3131833454b 100644
--- a/release/scripts/startup/bl_ui/properties_mask_common.py
+++ b/release/scripts/startup/bl_ui/properties_mask_common.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
# panels get subclassed (not registered directly)
# menus are referenced `as is`
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index 9532d1d4ab0..44fa93054d3 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_material_gpencil.py b/release/scripts/startup/bl_ui/properties_material_gpencil.py
index 47c61984cbe..de1df732b7e 100644
--- a/release/scripts/startup/bl_ui/properties_material_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_material_gpencil.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py
index 44c30cf4372..904c2af3a5e 100644
--- a/release/scripts/startup/bl_ui/properties_object.py
+++ b/release/scripts/startup/bl_ui/properties_object.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bl_ui.properties_animviz import (
MotionPathButtonsPanel,
MotionPathButtonsPanel_display,
diff --git a/release/scripts/startup/bl_ui/properties_output.py b/release/scripts/startup/bl_ui/properties_output.py
index 312a580bf7d..b80a49cddbb 100644
--- a/release/scripts/startup/bl_ui/properties_output.py
+++ b/release/scripts/startup/bl_ui/properties_output.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from bl_ui.utils import PresetPanel
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index d7325257084..f0034a3d710 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Menu
@@ -1318,7 +1316,11 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False)
def brush_basic_gpencil_sculpt_settings(layout, _context, brush, *, compact=False):
+ if brush is None:
+ return
gp_settings = brush.gpencil_settings
+ if gp_settings is None:
+ return
tool = brush.gpencil_sculpt_tool
row = layout.row(align=True)
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index 3d6ad2ece9b..db4e609be65 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py
index c041534a652..dd1a1fb59d6 100644
--- a/release/scripts/startup/bl_ui/properties_physics_cloth.py
+++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
)
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index e9df4622cde..bb9fe6e114a 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Panel,
diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
index d9d2a529693..5ab96bdd2c5 100644
--- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
+++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
UIList,
diff --git a/release/scripts/startup/bl_ui/properties_physics_field.py b/release/scripts/startup/bl_ui/properties_physics_field.py
index 2e7e68f02ef..8a1bd1a0c54 100644
--- a/release/scripts/startup/bl_ui/properties_physics_field.py
+++ b/release/scripts/startup/bl_ui/properties_physics_field.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
)
diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py
index 88f8658035b..f1162d8935a 100644
--- a/release/scripts/startup/bl_ui/properties_physics_fluid.py
+++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Panel
from bl_ui.utils import PresetPanel
diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
index bf8ab90147b..ad8f539d62c 100644
--- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
+++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
)
diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
index 21c3b8b0805..5dc98674b99 100644
--- a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
)
diff --git a/release/scripts/startup/bl_ui/properties_physics_softbody.py b/release/scripts/startup/bl_ui/properties_physics_softbody.py
index 1b941100db2..bde7778e54c 100644
--- a/release/scripts/startup/bl_ui/properties_physics_softbody.py
+++ b/release/scripts/startup/bl_ui/properties_physics_softbody.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
)
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 2a904bf1084..c20992166ad 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
from bl_ui.space_view3d import (
VIEW3D_PT_shading_lighting,
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index 912f0c8bcaf..2e2d7fbe261 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Panel,
diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py
index 1f9362f02b5..106ea76ccc8 100644
--- a/release/scripts/startup/bl_ui/properties_texture.py
+++ b/release/scripts/startup/bl_ui/properties_texture.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Menu,
diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py
index 44d764f1a2d..01ded1ceb9b 100644
--- a/release/scripts/startup/bl_ui/properties_view_layer.py
+++ b/release/scripts/startup/bl_ui/properties_view_layer.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Menu, Panel, UIList
diff --git a/release/scripts/startup/bl_ui/properties_workspace.py b/release/scripts/startup/bl_ui/properties_workspace.py
index cb4f768ac4f..542d770c062 100644
--- a/release/scripts/startup/bl_ui/properties_workspace.py
+++ b/release/scripts/startup/bl_ui/properties_workspace.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import (
Panel,
diff --git a/release/scripts/startup/bl_ui/properties_world.py b/release/scripts/startup/bl_ui/properties_world.py
index 47e990e8573..eb0fc473e64 100644
--- a/release/scripts/startup/bl_ui/properties_world.py
+++ b/release/scripts/startup/bl_ui/properties_world.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index c1ecfaceee7..a806e9e0c33 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Panel, Header, Menu, UIList
from bpy.app.translations import pgettext_iface as iface_
@@ -201,7 +199,8 @@ class CLIP_HT_header(Header):
row = layout.row(align=True)
row.prop(dopesheet, "sort_method", text="")
row.prop(dopesheet, "use_invert_sort",
- text="Invert", toggle=True)
+ text="", toggle=True,
+ icon='SORT_DESC' if dopesheet.use_invert_sort else 'SORT_ASC')
def _draw_masking(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py
index 323bee8a125..e9d1fc516ae 100644
--- a/release/scripts/startup/bl_ui/space_console.py
+++ b/release/scripts/startup/bl_ui/space_console.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Header, Menu
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 437f20b9473..3d792eec3e0 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Header,
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index e69a1024712..96ce731306f 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Header, Panel, Menu, UIList
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index a78ad72cada..a5ad13ad5d8 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import Header, Menu, Panel
from bl_ui.space_dopesheet import (
DopesheetFilterPopoverBase,
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index d61055c9024..1f02e0f64d4 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Header,
Menu,
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index 41c8b99b78c..3a9e4841749 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Header, Menu
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index 77a472d844e..5157a215f34 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import Header, Menu, Panel
from bpy.app.translations import contexts as i18n_contexts
from bl_ui.space_dopesheet import (
@@ -153,7 +151,7 @@ class NLA_MT_marker(Menu):
class NLA_MT_marker_select(Menu):
bl_label = 'Select'
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("marker.select_all", text="All").action = 'SELECT'
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 813a799db24..427d0696c20 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext_iface as iface_
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index f953095b9bb..fff252ade01 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
diff --git a/release/scripts/startup/bl_ui/space_properties.py b/release/scripts/startup/bl_ui/space_properties.py
index c15611fd375..28342d28ac8 100644
--- a/release/scripts/startup/bl_ui/space_properties.py
+++ b/release/scripts/startup/bl_ui/space_properties.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Header, Panel
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 40da0b03f76..2db30ac1450 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import (
Header,
@@ -2089,10 +2087,9 @@ class SEQUENCER_PT_adjust_transform(SequencerButtonsPanel, Panel):
col = layout.column(align=True)
col.prop(strip.transform, "origin")
- row = layout.row(heading="Mirror")
- sub = row.row(align=True)
- sub.prop(strip, "use_flip_x", text="X", toggle=True)
- sub.prop(strip, "use_flip_y", text="Y", toggle=True)
+ col = layout.column(heading="Mirror", align=True)
+ col.prop(strip, "use_flip_x", text="X", toggle=True)
+ col.prop(strip, "use_flip_y", text="Y", toggle=True)
class SEQUENCER_PT_adjust_video(SequencerButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/space_statusbar.py b/release/scripts/startup/bl_ui/space_statusbar.py
index 90e685ac559..a281492aba8 100644
--- a/release/scripts/startup/bl_ui/space_statusbar.py
+++ b/release/scripts/startup/bl_ui/space_statusbar.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Header
diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py
index 18c309a3456..52d66e48d1c 100644
--- a/release/scripts/startup/bl_ui/space_text.py
+++ b/release/scripts/startup/bl_ui/space_text.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext_iface as iface_
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 13ab6e67b00..115f61a7c19 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py
index 36d801154ca..0c796b899af 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_common.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import (
Menu,
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 1c526cc89e4..5831aa52cc1 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# For documentation on tool definitions: see "bl_ui.space_toolsystem_common.ToolDef"
# where there are comments for each field and their use.
@@ -263,9 +261,15 @@ class _defs_annotate:
class _defs_transform:
+ def draw_transform_sculpt_tool_settings(context, layout):
+ if context.mode != 'SCULPT':
+ return
+ layout.prop(context.tool_settings.sculpt, "transform_mode")
+
@ToolDef.from_fn
def translate():
def draw_settings(context, layout, _tool):
+ _defs_transform.draw_transform_sculpt_tool_settings(context, layout)
_template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 1)
return dict(
idname="builtin.move",
@@ -281,6 +285,7 @@ class _defs_transform:
@ToolDef.from_fn
def rotate():
def draw_settings(context, layout, _tool):
+ _defs_transform.draw_transform_sculpt_tool_settings(context, layout)
_template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 2)
return dict(
idname="builtin.rotate",
@@ -296,6 +301,7 @@ class _defs_transform:
@ToolDef.from_fn
def scale():
def draw_settings(context, layout, _tool):
+ _defs_transform.draw_transform_sculpt_tool_settings(context, layout)
_template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 3)
return dict(
idname="builtin.scale",
@@ -351,6 +357,7 @@ class _defs_transform:
props = tool.gizmo_group_properties("VIEW3D_GGT_xform_gizmo")
layout.prop(props, "drag_action")
+ _defs_transform.draw_transform_sculpt_tool_settings(context, layout)
_template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 1)
return dict(
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index 2cf50bdbf95..d8bd724f554 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
@@ -455,8 +453,13 @@ class TOPBAR_MT_file_import(Menu):
self.layout.operator(
"wm.usd_import", text="Universal Scene Description (.usd, .usdc, .usda)")
- self.layout.operator("wm.gpencil_import_svg", text="SVG as Grease Pencil")
- self.layout.operator("wm.obj_import", text="Wavefront (.obj) (experimental)")
+ if bpy.app.build_options.io_gpencil:
+ self.layout.operator("wm.gpencil_import_svg", text="SVG as Grease Pencil")
+
+ if bpy.app.build_options.io_wavefront_obj:
+ self.layout.operator("wm.obj_import", text="Wavefront (.obj) (experimental)")
+ if bpy.app.build_options.io_stl:
+ self.layout.operator("wm.stl_import", text="STL (.stl) (experimental)")
class TOPBAR_MT_file_export(Menu):
@@ -473,14 +476,16 @@ class TOPBAR_MT_file_export(Menu):
self.layout.operator(
"wm.usd_export", text="Universal Scene Description (.usd, .usdc, .usda)")
- # Pugixml lib dependency
- if bpy.app.build_options.pugixml:
- self.layout.operator("wm.gpencil_export_svg", text="Grease Pencil as SVG")
- # Haru lib dependency
- if bpy.app.build_options.haru:
- self.layout.operator("wm.gpencil_export_pdf", text="Grease Pencil as PDF")
+ if bpy.app.build_options.io_gpencil:
+ # Pugixml lib dependency
+ if bpy.app.build_options.pugixml:
+ self.layout.operator("wm.gpencil_export_svg", text="Grease Pencil as SVG")
+ # Haru lib dependency
+ if bpy.app.build_options.haru:
+ self.layout.operator("wm.gpencil_export_pdf", text="Grease Pencil as PDF")
- self.layout.operator("wm.obj_export", text="Wavefront (.obj) (experimental)")
+ if bpy.app.build_options.io_wavefront_obj:
+ self.layout.operator("wm.obj_export", text="Wavefront (.obj) (experimental)")
class TOPBAR_MT_file_external_data(Menu):
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index ee3e7b7df8f..5070bd04142 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import (
Header,
@@ -1198,6 +1196,8 @@ class ThemeGenericClassGenerator:
("Scroll Bar", "wcol_scroll"),
("Progress Bar", "wcol_progress"),
("List Item", "wcol_list_item"),
+ # Not used yet, so hide this from the UI.
+ # ("Data-View Item", "wcol_view_item"),
("Tab", "wcol_tab"),
]
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 116dd280b5c..5e5e7a79035 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import (
Header,
@@ -97,7 +95,7 @@ class VIEW3D_HT_tool_header(Header):
elif tool_mode == 'PAINT_GPENCIL':
if is_valid_context:
brush = context.tool_settings.gpencil_paint.brush
- if brush.gpencil_tool != 'ERASE':
+ if brush and brush.gpencil_tool != 'ERASE':
if brush.gpencil_tool != 'TINT':
layout.popover("VIEW3D_PT_tools_grease_pencil_brush_advanced")
@@ -108,10 +106,11 @@ class VIEW3D_HT_tool_header(Header):
elif tool_mode == 'SCULPT_GPENCIL':
if is_valid_context:
brush = context.tool_settings.gpencil_sculpt_paint.brush
- tool = brush.gpencil_sculpt_tool
- if tool != 'CLONE':
- layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_brush_popover")
- layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
+ if brush:
+ tool = brush.gpencil_sculpt_tool
+ 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:
layout.popover("VIEW3D_PT_tools_grease_pencil_weight_appearance")
@@ -512,30 +511,27 @@ class _draw_tool_settings_context_mode:
header=True,
)
- if brush.curves_sculpt_tool == 'COMB':
+ curves_tool = brush.curves_sculpt_tool
+
+ if curves_tool == 'COMB':
layout.prop(brush, "falloff_shape", expand=True)
layout.popover("VIEW3D_PT_tools_brush_falloff")
-
- if brush.curves_sculpt_tool == 'ADD':
+ elif curves_tool == 'ADD':
layout.prop(brush, "falloff_shape", expand=True)
layout.prop(brush.curves_sculpt_settings, "add_amount")
layout.popover("VIEW3D_PT_curves_sculpt_add_shape", text="Curve Shape")
layout.prop(brush, "use_frontface", text="Front Faces Only")
-
- if brush.curves_sculpt_tool == 'GROW_SHRINK':
+ elif curves_tool == 'GROW_SHRINK':
layout.prop(brush, "direction", expand=True, text="")
layout.prop(brush, "falloff_shape", expand=True)
layout.popover("VIEW3D_PT_curves_sculpt_grow_shrink_scaling", text="Scaling")
layout.popover("VIEW3D_PT_tools_brush_falloff")
-
- if brush.curves_sculpt_tool == 'SNAKE_HOOK':
+ elif curves_tool == 'SNAKE_HOOK':
layout.prop(brush, "falloff_shape", expand=True)
layout.popover("VIEW3D_PT_tools_brush_falloff")
-
- if brush.curves_sculpt_tool == 'DELETE':
+ elif curves_tool == 'DELETE':
layout.prop(brush, "falloff_shape", expand=True)
-
- if brush.curves_sculpt_tool == 'SELECTION_PAINT':
+ elif curves_tool == 'SELECTION_PAINT':
layout.prop(brush, "direction", expand=True, text="")
layout.prop(brush, "falloff_shape", expand=True)
layout.popover("VIEW3D_PT_tools_brush_falloff")
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 1b714a40d03..892dc9a1e42 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Menu, Panel, UIList
from bl_ui.properties_grease_pencil_common import (
GreasePencilSculptAdvancedPanel,
diff --git a/release/scripts/startup/bl_ui/utils.py b/release/scripts/startup/bl_ui/utils.py
index 02d2448af66..87f44601ff3 100644
--- a/release/scripts/startup/bl_ui/utils.py
+++ b/release/scripts/startup/bl_ui/utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import Menu
diff --git a/release/scripts/startup/keyingsets_builtins.py b/release/scripts/startup/keyingsets_builtins.py
index fb287183c99..4390e6f0959 100644
--- a/release/scripts/startup/keyingsets_builtins.py
+++ b/release/scripts/startup/keyingsets_builtins.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Built-In Keying Sets
None of these Keying Sets should be removed, as these are needed by various parts of Blender in order for them
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index f5282123ce8..a8184b1d84b 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
import nodeitems_utils
from nodeitems_utils import (
@@ -185,6 +183,24 @@ def geometry_input_node_items(context):
yield NodeItem("GeometryNodeInputSceneTime")
+# Custom Menu for Geometry Node Instance Nodes.
+def geometry_instance_node_items(context):
+ if context is None:
+ return
+ space = context.space_data
+ if not space:
+ return
+ yield NodeItem("GeometryNodeInstanceOnPoints")
+ yield NodeItem("GeometryNodeInstancesToPoints")
+ yield NodeItem("GeometryNodeRealizeInstances")
+ yield NodeItem("GeometryNodeRotateInstances")
+ yield NodeItem("GeometryNodeScaleInstances")
+ yield NodeItem("GeometryNodeTranslateInstances")
+ yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
+ yield NodeItem("GeometryNodeInputInstanceRotation")
+ yield NodeItem("GeometryNodeInputInstanceScale")
+
+
# Custom Menu for Material Nodes.
def geometry_material_node_items(context):
if context is None:
@@ -637,14 +653,7 @@ geometry_node_categories = [
]),
GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=geometry_node_items),
GeometryNodeCategory("GEO_INPUT", "Input", items=geometry_input_node_items),
- GeometryNodeCategory("GEO_INSTANCE", "Instances", items=[
- NodeItem("GeometryNodeInstanceOnPoints"),
- NodeItem("GeometryNodeInstancesToPoints"),
- NodeItem("GeometryNodeRealizeInstances"),
- NodeItem("GeometryNodeRotateInstances"),
- NodeItem("GeometryNodeScaleInstances"),
- NodeItem("GeometryNodeTranslateInstances"),
- ]),
+ GeometryNodeCategory("GEO_INSTANCE", "Instances", items=geometry_instance_node_items),
GeometryNodeCategory("GEO_MATERIAL", "Material", items=geometry_material_node_items),
GeometryNodeCategory("GEO_MESH", "Mesh", items=mesh_node_items),
GeometryNodeCategory("GEO_PRIMITIVES_MESH", "Mesh Primitives", items=[
@@ -705,6 +714,7 @@ geometry_node_categories = [
NodeItem("ShaderNodeVectorRotate"),
]),
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
+ NodeItem("GeometryNodeVolumeCube"),
NodeItem("GeometryNodeVolumeToMesh"),
]),
GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
diff --git a/release/windows/manifest/blender.exe.manifest.in b/release/windows/manifest/blender.exe.manifest.in
index b516efe24cb..95a238f775b 100644
--- a/release/windows/manifest/blender.exe.manifest.in
+++ b/release/windows/manifest/blender.exe.manifest.in
@@ -7,6 +7,11 @@
</requestedPrivileges>
</security>
</trustInfo>
+ <application>
+ <windowsSettings>
+ <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
+ </windowsSettings>
+ </application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index e5e2b1711b1..78c8612f7f5 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -14,6 +14,15 @@
extern "C" {
#endif
+/* Name of subfolder inside BLENDER_DATAFILES that contains font files. */
+#define BLF_DATAFILES_FONTS_DIR "fonts"
+
+/* File name of the default variable-width font. */
+#define BLF_DEFAULT_PROPORTIONAL_FONT "droidsans.ttf"
+
+/* File name of the default fixed-pitch font. */
+#define BLF_DEFAULT_MONOSPACED_FONT "bmonofont-i18n.ttf"
+
/* enable this only if needed (unused circa 2016) */
#define BLF_BLUR_ENABLE 0
@@ -37,12 +46,14 @@ void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void));
*/
int BLF_load(const char *name) ATTR_NONNULL();
int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL();
+bool BLF_is_loaded(const char *name) ATTR_NONNULL();
int BLF_load_unique(const char *name) ATTR_NONNULL();
int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL();
void BLF_unload(const char *name) ATTR_NONNULL();
void BLF_unload_id(int fontid);
+void BLF_unload_all(void);
char *BLF_display_name_from_file(const char *filepath);
@@ -312,6 +323,7 @@ int BLF_set_default(void);
int BLF_load_default(bool unique);
int BLF_load_mono_default(bool unique);
+void BLF_load_font_stack(void);
#ifdef DEBUG
void BLF_state_print(int fontid);
@@ -331,6 +343,9 @@ void BLF_state_print(int fontid);
#define BLF_HINTING_FULL (1 << 10)
#define BLF_BOLD (1 << 11)
#define BLF_ITALIC (1 << 12)
+#define BLF_MONOSPACED (1 << 13) /* Intended USE is monospaced, regardless of font type. */
+#define BLF_DEFAULT (1 << 14) /* A font within the default stack of fonts. */
+#define BLF_LAST_RESORT (1 << 15) /* Must only be used as last font in the stack. */
#define BLF_DRAW_STR_DUMMY_MAX 1024
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index a944ab332bd..a1fcc17ca3f 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -34,13 +34,6 @@
#include "blf_internal.h"
#include "blf_internal_types.h"
-/* Max number of font in memory.
- * Take care that now every font have a glyph cache per size/dpi,
- * so we don't need load the same font with different size, just
- * load one and call BLF_size.
- */
-#define BLF_MAX_FONT 16
-
#define BLF_RESULT_CHECK_INIT(r_info) \
if (r_info) { \
memset(r_info, 0, sizeof(*(r_info))); \
@@ -48,7 +41,7 @@
((void)0)
/* Font array. */
-static FontBLF *global_font[BLF_MAX_FONT] = {NULL};
+FontBLF *global_font[BLF_MAX_FONT] = {NULL};
/* XXX: should these be made into global_font_'s too? */
@@ -134,6 +127,11 @@ bool BLF_has_glyph(int fontid, unsigned int unicode)
return false;
}
+bool BLF_is_loaded(const char *name)
+{
+ return blf_search(name) >= 0;
+}
+
int BLF_load(const char *name)
{
/* check if we already load this font. */
@@ -255,6 +253,20 @@ void BLF_unload_id(int fontid)
}
}
+void BLF_unload_all(void)
+{
+ for (int i = 0; i < BLF_MAX_FONT; i++) {
+ FontBLF *font = global_font[i];
+ if (font) {
+ blf_font_free(font);
+ global_font[i] = NULL;
+ }
+ }
+ blf_mono_font = -1;
+ blf_mono_font_render = -1;
+ BLF_default_set(-1);
+}
+
void BLF_enable(int fontid, int option)
{
FontBLF *font = blf_get(fontid);
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index a170f27d247..26a72fcb95a 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -18,6 +18,7 @@
#include FT_FREETYPE_H
#include FT_GLYPH_H
+#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */
#include "MEM_guardedalloc.h"
@@ -1288,6 +1289,25 @@ FontBLF *blf_font_new(const char *name, const char *filepath)
font->filepath = BLI_strdup(filepath);
blf_font_fill(font);
+ /* Save TrueType table with bits to quickly test most unicode block coverage. */
+ TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
+ if (os2_table) {
+ font->UnicodeRanges[0] = (uint)os2_table->ulUnicodeRange1;
+ font->UnicodeRanges[1] = (uint)os2_table->ulUnicodeRange2;
+ font->UnicodeRanges[2] = (uint)os2_table->ulUnicodeRange3;
+ font->UnicodeRanges[3] = (uint)os2_table->ulUnicodeRange4;
+ }
+
+ /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */
+ if (font->UnicodeRanges[0] == 0xffffffffU && font->UnicodeRanges[1] == 0xffffffffU &&
+ font->UnicodeRanges[2] == 0xffffffffU && font->UnicodeRanges[3] >= 0x7FFFFFFU) {
+ font->flags |= BLF_LAST_RESORT;
+ }
+
+ if (FT_IS_FIXED_WIDTH(font->face)) {
+ font->flags |= BLF_MONOSPACED;
+ }
+
if (FT_HAS_KERNING(font->face)) {
/* Create kerning cache table and fill with value indicating "unset". */
font->kerning_cache = MEM_mallocN(sizeof(KerningCacheBLF), __func__);
diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c
index 3a68423e64e..1bde25b5776 100644
--- a/source/blender/blenfont/intern/blf_font_default.c
+++ b/source/blender/blenfont/intern/blf_font_default.c
@@ -11,13 +11,14 @@
#include "BLF_api.h"
+#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "BKE_appdir.h"
static int blf_load_font_default(const char *filename, const bool unique)
{
- const char *dir = BKE_appdir_folder_id(BLENDER_DATAFILES, "fonts");
+ const char *dir = BKE_appdir_folder_id(BLENDER_DATAFILES, BLF_DATAFILES_FONTS_DIR);
if (dir == NULL) {
fprintf(stderr,
"%s: 'fonts' data path not found for '%s', will not be able to display text\n",
@@ -34,10 +35,46 @@ static int blf_load_font_default(const char *filename, const bool unique)
int BLF_load_default(const bool unique)
{
- return blf_load_font_default("droidsans.ttf", unique);
+ int font_id = blf_load_font_default(BLF_DEFAULT_PROPORTIONAL_FONT, unique);
+ BLF_enable(font_id, BLF_DEFAULT);
+ return font_id;
}
int BLF_load_mono_default(const bool unique)
{
- return blf_load_font_default("bmonofont-i18n.ttf", unique);
+ int font_id = blf_load_font_default(BLF_DEFAULT_MONOSPACED_FONT, unique);
+ BLF_enable(font_id, BLF_MONOSPACED | BLF_DEFAULT);
+ return font_id;
+}
+
+void BLF_load_font_stack()
+{
+ /* Load these if not already, might have been replaced by user custom. */
+ BLF_load_default(false);
+ BLF_load_mono_default(false);
+
+ const char *path = BKE_appdir_folder_id(BLENDER_DATAFILES, BLF_DATAFILES_FONTS_DIR SEP_STR);
+ if (path && BLI_exists(path)) {
+ struct direntry *dir;
+ uint num_files = BLI_filelist_dir_contents(path, &dir);
+ for (int f = 0; f < num_files; f++) {
+ if (!FILENAME_IS_CURRPAR(dir[f].relname) && !BLI_is_dir(dir[f].path)) {
+ if (!BLF_is_loaded(dir[f].path)) {
+ int font_id = BLF_load(dir[f].path);
+ if (font_id == -1) {
+ fprintf(stderr, "Unable to load font: %s\n", dir[f].path);
+ }
+ else {
+ BLF_enable(font_id, BLF_DEFAULT);
+ /* TODO: FontBLF will later load FT_Face on demand. When this is in
+ * place we can drop this face now since we have all needed data. */
+ }
+ }
+ }
+ }
+ BLI_filelist_free(dir, num_files);
+ }
+ else {
+ fprintf(stderr, "Fonts not found at %s\n", path);
+ }
}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 2694b179a11..ed30cca4da2 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -39,6 +39,7 @@
#include "BLI_math_vector.h"
#include "BLI_strict_flags.h"
+#include "BLI_string_utf8.h"
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
@@ -222,6 +223,335 @@ static GlyphBLF *blf_glyph_cache_add_glyph(
return g;
}
+/* This table can be used to find a coverage bit based on a charcode. later we can get default
+ * language and script from codepoint. */
+
+typedef struct eUnicodeBlock {
+ unsigned int first;
+ unsigned int last;
+ int coverage_bit; /* 0-122. -1 is N/A. */
+ /* Later we add primary script and language for Harfbuzz, data from
+ * https://en.wikipedia.org/wiki/Unicode_block */
+} eUnicodeBlock;
+
+static eUnicodeBlock unicode_blocks[] = {
+ /* Must be in ascending order by start of range. */
+ {0x0, 0x7F, 0}, /* Basic Latin. */
+ {0x80, 0xFF, 1}, /* Latin-1 Supplement. */
+ {0x100, 0x17F, 2}, /* Latin Extended-A. */
+ {0x180, 0x24F, 3}, /* Latin Extended-B. */
+ {0x250, 0x2AF, 4}, /* IPA Extensions. */
+ {0x2B0, 0x2FF, 5}, /* Spacing Modifier Letters. */
+ {0x300, 0x36F, 6}, /* Combining Diacritical Marks. */
+ {0x370, 0x3FF, 7}, /* Greek. */
+ {0x400, 0x52F, 9}, /* Cyrillic. */
+ {0x530, 0x58F, 10}, /* Armenian. */
+ {0x590, 0x5FF, 11}, /* Hebrew. */
+ {0x600, 0x6FF, 13}, /* Arabic. */
+ {0x700, 0x74F, 71}, /* Syriac. */
+ {0x750, 0x77F, 13}, /* Arabic Supplement. */
+ {0x780, 0x7BF, 72}, /* Thaana. */
+ {0x7C0, 0x7FF, 14}, /* NKo. */
+ {0x800, 0x83F, -1}, /* Samaritan. */
+ {0x840, 0x85F, -1}, /* Mandaic. */
+ {0x900, 0x97F, 15}, /* Devanagari. */
+ {0x980, 0x9FF, 16}, /* Bengali. */
+ {0xA00, 0xA7F, 17}, /* Gurmukhi. */
+ {0xA80, 0xAFF, 18}, /* Gujarati. */
+ {0xB00, 0xB7F, 19}, /* Oriya. */
+ {0xB80, 0xBFF, 20}, /* Tamil. */
+ {0xC00, 0xC7F, 21}, /* Telugu. */
+ {0xC80, 0xCFF, 22}, /* Kannada. */
+ {0xD00, 0xD7F, 23}, /* Malayalam. */
+ {0xD80, 0xDFF, 73}, /* Sinhala. */
+ {0xE00, 0xE7F, 24}, /* Thai. */
+ {0xE80, 0xEFF, 25}, /* Lao. */
+ {0xF00, 0xFFF, 70}, /* Tibetan. */
+ {0x1000, 0x109F, 74}, /* Myanmar. */
+ {0x10A0, 0x10FF, 26}, /* Georgian. */
+ {0x1100, 0x11FF, 28}, /* Hangul Jamo. */
+ {0x1200, 0x139F, 75}, /* Ethiopic. */
+ {0x13A0, 0x13FF, 76}, /* Cherokee. */
+ {0x1400, 0x167F, 77}, /* Canadian Aboriginal. */
+ {0x1680, 0x169F, 78}, /* Ogham. */
+ {0x16A0, 0x16FF, 79}, /* unic. */
+ {0x1700, 0x171F, 84}, /* Tagalog. */
+ {0x1720, 0x173F, 84}, /* Hanunoo. */
+ {0x1740, 0x175F, 84}, /* Buhid. */
+ {0x1760, 0x177F, 84}, /* Tagbanwa. */
+ {0x1780, 0x17FF, 80}, /* Khmer. */
+ {0x1800, 0x18AF, 81}, /* Mongolian. */
+ {0x1900, 0x194F, 93}, /* Limbu. */
+ {0x1950, 0x197F, 94}, /* Tai Le. */
+ {0x1980, 0x19DF, 95}, /* New Tai Lue". */
+ {0x19E0, 0x19FF, 80}, /* Khmer. */
+ {0x1A00, 0x1A1F, 96}, /* Buginese. */
+ {0x1A20, 0x1AAF, -1}, /* Tai Tham. */
+ {0x1B00, 0x1B7F, 27}, /* Balinese. */
+ {0x1B80, 0x1BBF, 112}, /* Sundanese. */
+ {0x1BC0, 0x1BFF, -1}, /* Batak. */
+ {0x1C00, 0x1C4F, 113}, /* Lepcha. */
+ {0x1C50, 0x1C7F, 114}, /* Ol Chiki. */
+ {0x1D00, 0x1DBF, 4}, /* IPA Extensions. */
+ {0x1DC0, 0x1DFF, 6}, /* Combining Diacritical Marks. */
+ {0x1E00, 0x1EFF, 29}, /* Latin Extended Additional. */
+ {0x1F00, 0x1FFF, 30}, /* Greek Extended. */
+ {0x2000, 0x206F, 31}, /* General Punctuation. */
+ {0x2070, 0x209F, 32}, /* Superscripts And Subscripts. */
+ {0x20A0, 0x20CF, 33}, /* Currency Symbols. */
+ {0x20D0, 0x20FF, 34}, /* Combining Diacritical Marks For Symbols. */
+ {0x2100, 0x214F, 35}, /* Letterlike Symbols. */
+ {0x2150, 0x218F, 36}, /* Number Forms. */
+ {0x2190, 0x21FF, 37}, /* Arrows. */
+ {0x2200, 0x22FF, 38}, /* Mathematical Operators. */
+ {0x2300, 0x23FF, 39}, /* Miscellaneous Technical. */
+ {0x2400, 0x243F, 40}, /* Control Pictures. */
+ {0x2440, 0x245F, 41}, /* Optical Character Recognition. */
+ {0x2460, 0x24FF, 42}, /* Enclosed Alphanumerics. */
+ {0x2500, 0x257F, 43}, /* Box Drawing. */
+ {0x2580, 0x259F, 44}, /* Block Elements. */
+ {0x25A0, 0x25FF, 45}, /* Geometric Shapes. */
+ {0x2600, 0x26FF, 46}, /* Miscellaneous Symbols. */
+ {0x2700, 0x27BF, 47}, /* Dingbats. */
+ {0x27C0, 0x27EF, 38}, /* Mathematical Operators. */
+ {0x27F0, 0x27FF, 37}, /* Arrows. */
+ {0x2800, 0x28FF, 82}, /* Braille. */
+ {0x2900, 0x297F, 37}, /* Arrows. */
+ {0x2980, 0x2AFF, 38}, /* Mathematical Operators. */
+ {0x2B00, 0x2BFF, 37}, /* Arrows. */
+ {0x2C00, 0x2C5F, 97}, /* Glagolitic. */
+ {0x2C60, 0x2C7F, 29}, /* Latin Extended Additional. */
+ {0x2C80, 0x2CFF, 8}, /* Coptic. */
+ {0x2D00, 0x2D2F, 26}, /* Georgian. */
+ {0x2D30, 0x2D7F, 98}, /* Tifinagh. */
+ {0x2D80, 0x2DDF, 75}, /* Ethiopic. */
+ {0x2DE0, 0x2DFF, 9}, /* Cyrillic. */
+ {0x2E00, 0x2E7F, 31}, /* General Punctuation. */
+ {0x2E80, 0x2FFF, 59}, /* CJK Unified Ideographs. */
+ {0x3000, 0x303F, 48}, /* CJK Symbols And Punctuation. */
+ {0x3040, 0x309F, 49}, /* Hiragana. */
+ {0x30A0, 0x30FF, 50}, /* Katakana. */
+ {0x3100, 0x312F, 51}, /* Bopomofo. */
+ {0x3130, 0x318F, 52}, /* Hangul Compatibility Jamo. */
+ {0x3190, 0x319F, 59}, /* CJK Unified Ideographs. */
+ {0x31A0, 0x31BF, 51}, /* Bopomofo. */
+ {0x31C0, 0x31EF, 59}, /* CJK Unified Ideographs. */
+ {0x31F0, 0x31FF, 50}, /* Katakana. */
+ {0x3200, 0x32FF, 54}, /* Enclosed CJK Letters And Months. */
+ {0x3300, 0x33FF, 55}, /* CJK Compatibility. */
+ {0x3400, 0x4DBF, 59}, /* CJK Unified Ideographs. */
+ {0x4DC0, 0x4DFF, 99}, /* Yijing. */
+ {0x4E00, 0x9FFF, 59}, /* CJK Unified Ideographs. */
+ {0xA000, 0xA4CF, 83}, /* Yi. */
+ {0xA4D0, 0xA4FF, -1}, /* Lisu. */
+ {0xA500, 0xA63F, 12}, /* Vai. */
+ {0xA640, 0xA69F, 9}, /* Cyrillic. */
+ {0xA6A0, 0xA6FF, -1}, /* Bamum. */
+ {0xA700, 0xA71F, 5}, /* Spacing Modifier Letters. */
+ {0xA720, 0xA7FF, 29}, /* Latin Extended Additional. */
+ {0xA800, 0xA82F, 100}, /* Syloti Nagri. */
+ {0xA840, 0xA87F, 53}, /* Phags-pa. */
+ {0xA880, 0xA8DF, 115}, /* Saurashtra. */
+ {0xA900, 0xA92F, 116}, /* Kayah Li. */
+ {0xA930, 0xA95F, 117}, /* Rejang. */
+ {0xA960, 0xA97F, 56}, /* Hangul Syllables. */
+ {0xA980, 0xA9DF, -1}, /* Javanese. */
+ {0xA9E0, 0xA9FF, 74}, /* Myanmar. */
+ {0xAA00, 0xAA5F, 118}, /* Cham. */
+ {0xAA60, 0xAA7F, 74}, /* Myanmar. */
+ {0xAA80, 0xAADF, -1}, /* Tai Viet. */
+ {0xAAE0, 0xAAFF, -1}, /* Meetei Mayek. */
+ {0xAB00, 0xAB2F, 75}, /* Ethiopic. */
+ {0xAB70, 0xABBF, 76}, /* Cherokee. */
+ {0xABC0, 0xABFF, -1}, /* Meetei Mayek. */
+ {0xAC00, 0xD7AF, 56}, /* Hangul Syllables. */
+ {0xD800, 0xDFFF, 57}, /* Non-Plane 0. */
+ {0xE000, 0xF6FF, 60}, /* Private Use Area. */
+ {0xE700, 0xEFFF, -1}, /* MS Wingdings. */
+ {0xF000, 0xF8FF, -1}, /* MS Symbols. */
+ {0xF900, 0xFAFF, 61}, /* CJK Compatibility Ideographs. */
+ {0xFB00, 0xFB4F, 62}, /* Alphabetic Presentation Forms. */
+ {0xFB50, 0xFDFF, 63}, /* Arabic Presentation Forms-A. */
+ {0xFE00, 0xFE0F, 91}, /* Variation Selectors. */
+ {0xFE10, 0xFE1F, 65}, /* CJK Compatibility Forms. */
+ {0xFE20, 0xFE2F, 64}, /* Combining Half Marks. */
+ {0xFE30, 0xFE4F, 65}, /* CJK Compatibility Forms. */
+ {0xFE50, 0xFE6F, 66}, /* Small Form Variants. */
+ {0xFE70, 0xFEFF, 67}, /* Arabic Presentation Forms-B. */
+ {0xFF00, 0xFFEF, 68}, /* Halfwidth And Fullwidth Forms. */
+ {0xFFF0, 0xFFFF, 69}, /* Specials. */
+ {0x10000, 0x1013F, 101}, /* Linear B. */
+ {0x10140, 0x1018F, 102}, /* Ancient Greek Numbers. */
+ {0x10190, 0x101CF, 119}, /* Ancient Symbols. */
+ {0x101D0, 0x101FF, 120}, /* Phaistos Disc. */
+ {0x10280, 0x1029F, 121}, /* Lycian. */
+ {0x102A0, 0x102DF, 121}, /* Carian. */
+ {0x10300, 0x1032F, 85}, /* Old Italic. */
+ {0x10330, 0x1034F, 86}, /* Gothic. */
+ {0x10350, 0x1037F, -1}, /* Old Permic. */
+ {0x10380, 0x1039F, 103}, /* Ugaritic. */
+ {0x103A0, 0x103DF, 104}, /* Old Persian. */
+ {0x10400, 0x1044F, 87}, /* Deseret. */
+ {0x10450, 0x1047F, 105}, /* Shavian. */
+ {0x10480, 0x104AF, 106}, /* Osmanya. */
+ {0x104B0, 0x104FF, -1}, /* Osage. */
+ {0x10500, 0x1052F, -1}, /* Elbasan. */
+ {0x10530, 0x1056F, -1}, /* Caucasian Albanian. */
+ {0x10570, 0x105BF, -1}, /* Vithkuqi. */
+ {0x10600, 0x1077F, -1}, /* Linear A. */
+ {0x10780, 0x107BF, 3}, /* Latin Extended-B. */
+ {0x10800, 0x1083F, 107}, /* Cypriot Syllabary. */
+ {0x10840, 0x1085F, -1}, /* Imperial Aramaic. */
+ {0x10860, 0x1087F, -1}, /* Palmyrene. */
+ {0x10880, 0x108AF, -1}, /* Nabataean. */
+ {0x108E0, 0x108FF, -1}, /* Hatran. */
+ {0x10900, 0x1091F, 58}, /* Phoenician. */
+ {0x10920, 0x1093F, 121}, /* Lydian. */
+ {0x10980, 0x1099F, -1}, /* Meroitic Hieroglyphs. */
+ {0x109A0, 0x109FF, -1}, /* Meroitic Cursive. */
+ {0x10A00, 0x10A5F, 108}, /* Kharoshthi. */
+ {0x10A60, 0x10A7F, -1}, /* Old South Arabian. */
+ {0x10A80, 0x10A9F, -1}, /* Old North Arabian. */
+ {0x10AC0, 0x10AFF, -1}, /* Manichaean. */
+ {0x10B00, 0x10B3F, -1}, /* Avestan. */
+ {0x10B40, 0x10B5F, -1}, /* Inscriptional Parthian. */
+ {0x10B60, 0x10B7F, -1}, /* Inscriptional Pahlavi. */
+ {0x10B80, 0x10BAF, -1}, /* Psalter Pahlavi. */
+ {0x10C00, 0x10C4F, -1}, /* Old Turkic. */
+ {0x10C80, 0x10CFF, -1}, /* Old Hungarian. */
+ {0x10D00, 0x10D3F, -1}, /* Hanifi Rohingya. */
+ {0x108E0, 0x10E7F, -1}, /* Rumi Numeral Symbols. */
+ {0x10E80, 0x10EBF, -1}, /* Yezidi. */
+ {0x10F00, 0x10F2F, -1}, /* Old Sogdian. */
+ {0x10F30, 0x10F6F, -1}, /* Sogdian. */
+ {0x10F70, 0x10FAF, -1}, /* Old Uyghur. */
+ {0x10FB0, 0x10FDF, -1}, /* Chorasmian. */
+ {0x10FE0, 0x10FFF, -1}, /* Elymaic. */
+ {0x11000, 0x1107F, -1}, /* Brahmi. */
+ {0x11080, 0x110CF, -1}, /* Kaithi. */
+ {0x110D0, 0x110FF, -1}, /* Sora Sompeng. */
+ {0x11100, 0x1114F, -1}, /* Chakma. */
+ {0x11150, 0x1117F, -1}, /* Mahajani. */
+ {0x11180, 0x111DF, -1}, /* Sharada. */
+ {0x111E0, 0x111FF, -1}, /* Sinhala Archaic Numbers. */
+ {0x11200, 0x1124F, -1}, /* Khojki. */
+ {0x11280, 0x112AF, -1}, /* Multani. */
+ {0x112B0, 0x112FF, -1}, /* Khudawadi. */
+ {0x11300, 0x1137F, -1}, /* Grantha. */
+ {0x11400, 0x1147F, -1}, /* Newa. */
+ {0x11480, 0x114DF, -1}, /* Tirhuta. */
+ {0x11580, 0x115FF, -1}, /* Siddham. */
+ {0x11600, 0x1165F, -1}, /* Modi. */
+ {0x11660, 0x1167F, 81}, /* Mongolian. */
+ {0x11680, 0x116CF, -1}, /* Takri. */
+ {0x11700, 0x1174F, -1}, /* Ahom. */
+ {0x11800, 0x1184F, -1}, /* Dogra. */
+ {0x118A0, 0x118FF, -1}, /* Warang Citi. */
+ {0x11900, 0x1195F, -1}, /* Dives Akuru. */
+ {0x119A0, 0x119FF, -1}, /* Nandinagari. */
+ {0x11A00, 0x11A4F, -1}, /* Zanabazar Square. */
+ {0x11A50, 0x11AAF, -1}, /* Soyombo. */
+ {0x11AB0, 0x11ABF, 77}, /* Canadian Aboriginal Syllabics. */
+ {0x11AC0, 0x11AFF, -1}, /* Pau Cin Hau. */
+ {0x11C00, 0x11C6F, -1}, /* Bhaiksuki. */
+ {0x11C70, 0x11CBF, -1}, /* Marchen. */
+ {0x11D00, 0x11D5F, -1}, /* Masaram Gondi. */
+ {0x11D60, 0x11DAF, -1}, /* Gunjala Gondi. */
+ {0x11EE0, 0x11EFF, -1}, /* Makasar. */
+ {0x11FB0, 0x11FBF, -1}, /* Lisu. */
+ {0x11FC0, 0x11FFF, 20}, /* Tamil. */
+ {0x12000, 0x1254F, 110}, /* Cuneiform. */
+ {0x12F90, 0x12FFF, -1}, /* Cypro-Minoan. */
+ {0x13000, 0x1343F, -1}, /* Egyptian Hieroglyphs. */
+ {0x14400, 0x1467F, -1}, /* Anatolian Hieroglyphs. */
+ {0x16800, 0x16A3F, -1}, /* Bamum. */
+ {0x16A40, 0x16A6F, -1}, /* Mro. */
+ {0x16A70, 0x16ACF, -1}, /* Tangsa. */
+ {0x16AD0, 0x16AFF, -1}, /* Bassa Vah. */
+ {0x16B00, 0x16B8F, -1}, /* Pahawh Hmong. */
+ {0x16E40, 0x16E9F, -1}, /* Medefaidrin. */
+ {0x16F00, 0x16F9F, -1}, /* Miao. */
+ {0x16FE0, 0x16FFF, -1}, /* Ideographic Symbols. */
+ {0x17000, 0x18AFF, -1}, /* Tangut. */
+ {0x1B170, 0x1B2FF, -1}, /* Nushu. */
+ {0x1BC00, 0x1BC9F, -1}, /* Duployan. */
+ {0x1D000, 0x1D24F, 88}, /* Musical Symbols. */
+ {0x1D2E0, 0x1D2FF, -1}, /* Mayan Numerals. */
+ {0x1D300, 0x1D35F, 109}, /* Tai Xuan Jing. */
+ {0x1D360, 0x1D37F, 111}, /* Counting Rod Numerals. */
+ {0x1D400, 0x1D7FF, 89}, /* Mathematical Alphanumeric Symbols. */
+ {0x1E2C0, 0x1E2FF, -1}, /* Wancho. */
+ {0x1E800, 0x1E8DF, -1}, /* Mende Kikakui. */
+ {0x1E900, 0x1E95F, -1}, /* Adlam. */
+ {0x1EC70, 0x1ECBF, -1}, /* Indic Siyaq Numbers. */
+ {0x1F000, 0x1F02F, 122}, /* Mahjong Tiles. */
+ {0x1F030, 0x1F09F, 122}, /* Domino Tiles. */
+ {0x1F600, 0x1F64F, -1}, /* Emoticons. */
+ {0x20000, 0x2A6DF, 59}, /* CJK Unified Ideographs. */
+ {0x2F800, 0x2FA1F, 61}, /* CJK Compatibility Ideographs. */
+ {0xE0000, 0xE007F, 92}, /* Tags. */
+ {0xE0100, 0xE01EF, 91}, /* Variation Selectors. */
+ {0xF0000, 0x10FFFD, 90}}; /* Private Use Supplementary. */
+
+/* Find a unicode block that a charcode belongs to. */
+static eUnicodeBlock *blf_charcode_to_unicode_block(uint charcode)
+{
+ if (charcode < 0x80) {
+ /* Shortcut to Basic Latin. */
+ return &unicode_blocks[0];
+ }
+
+ /* Binary search for other blocks. */
+
+ int min = 0;
+ int max = ARRAY_SIZE(unicode_blocks) - 1;
+ int mid;
+
+ if (charcode < unicode_blocks[0].first || charcode > unicode_blocks[max].last) {
+ return NULL;
+ }
+
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (charcode > unicode_blocks[mid].last) {
+ min = mid + 1;
+ }
+ else if (charcode < unicode_blocks[mid].first) {
+ max = mid - 1;
+ }
+ else {
+ return &unicode_blocks[mid];
+ }
+ }
+
+ return NULL;
+}
+
+static int blf_charcode_to_coverage_bit(uint charcode)
+{
+ int coverage_bit = -1;
+ eUnicodeBlock *block = blf_charcode_to_unicode_block(charcode);
+ if (block) {
+ coverage_bit = block->coverage_bit;
+ }
+
+ if (coverage_bit < 0 && charcode > 0xFFFF) {
+ /* No coverage bit, but OpenType specs v.1.3+ says bit 57 implies that there
+ * are codepoints supported beyond the BMP, so only check fonts with this set. */
+ coverage_bit = 57;
+ }
+
+ return coverage_bit;
+}
+
+static bool blf_font_has_coverage_bit(FontBLF *font, int coverage_bit)
+{
+ if (coverage_bit < 0) {
+ return false;
+ }
+ return (font->UnicodeRanges[(uint)coverage_bit >> 5] & (1u << ((uint)coverage_bit % 32)));
+}
+
/**
* Return a glyph index from `charcode`. Not found returns zero, which is a valid
* printable character (`.notdef` or `tofu`). Font is allowed to change here.
@@ -229,8 +559,42 @@ static GlyphBLF *blf_glyph_cache_add_glyph(
static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode)
{
FT_UInt glyph_index = FT_Get_Char_Index((*font)->face, charcode);
- /* TODO: If not found in this font, check others, update font pointer. */
- return glyph_index;
+ if (glyph_index) {
+ return glyph_index;
+ }
+
+ /* Not found in main font, so look in the others. */
+ FontBLF *last_resort = NULL;
+ int coverage_bit = blf_charcode_to_coverage_bit(charcode);
+ for (int i = 0; i < BLF_MAX_FONT; i++) {
+ FontBLF *f = global_font[i];
+ if (!f || f == *font || !(f->flags & BLF_DEFAULT)) {
+ continue;
+ }
+
+ if (f->flags & BLF_LAST_RESORT) {
+ last_resort = f;
+ continue;
+ }
+ if (coverage_bit < 0 || blf_font_has_coverage_bit(f, coverage_bit)) {
+ glyph_index = FT_Get_Char_Index(f->face, charcode);
+ if (glyph_index) {
+ *font = f;
+ return glyph_index;
+ }
+ }
+ }
+
+ /* Not found in the stack, return from Last Resort if there is one. */
+ if (last_resort) {
+ glyph_index = FT_Get_Char_Index(last_resort->face, charcode);
+ if (glyph_index) {
+ *font = last_resort;
+ return glyph_index;
+ }
+ }
+
+ return 0;
}
/**
@@ -377,24 +741,24 @@ static bool UNUSED_FUNCTION(blf_glyph_transform_width)(FT_GlyphSlot glyph, float
/**
* Transform glyph to fit nicely within a fixed column width.
*/
-static bool UNUSED_FUNCTION(blf_glyph_transform_monospace)(FT_GlyphSlot glyph, int width)
+static bool blf_glyph_transform_monospace(FT_GlyphSlot glyph, int width)
{
if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
- int gwidth = (int)(glyph->linearHoriAdvance >> 16);
- if (gwidth > width) {
- float scale = (float)width / (float)gwidth;
+ FT_Fixed current = glyph->linearHoriAdvance;
+ FT_Fixed target = width << 16; /* Do math in 16.16 values. */
+ if (target < current) {
+ const FT_Pos embolden = (FT_Pos)((current - target) >> 13);
+ /* Horizontally widen strokes to counteract narrowing. */
+ FT_Outline_EmboldenXY(&glyph->outline, embolden, 0);
+ const float scale = (float)(target - (embolden << 9)) / (float)current;
FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)};
- /* Narrowing all points also thins vertical strokes. */
FT_Outline_Transform(&glyph->outline, &matrix);
- const FT_Pos extra_x = (int)((float)(gwidth - width) * 5.65f);
- /* Horizontally widen strokes to counteract narrowing. */
- FT_Outline_EmboldenXY(&glyph->outline, extra_x, 0);
}
- else if (gwidth < width) {
- /* Narrow glyphs only need to be centered. */
- int nudge = (width - gwidth) / 2;
- FT_Outline_Translate(&glyph->outline, (FT_Pos)nudge * 64, 0);
+ else if (target > current) {
+ /* Center narrow glyphs. */
+ FT_Outline_Translate(&glyph->outline, (FT_Pos)((target - current) >> 11), 0);
}
+ glyph->advance.x = width << 6;
return true;
}
return false;
@@ -411,7 +775,9 @@ static bool UNUSED_FUNCTION(blf_glyph_transform_monospace)(FT_GlyphSlot glyph, i
*/
static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
FontBLF *glyph_font,
- FT_UInt glyph_index)
+ FT_UInt glyph_index,
+ uint charcode,
+ int fixed_width)
{
if (glyph_font != settings_font) {
FT_Set_Char_Size(glyph_font->face,
@@ -428,6 +794,10 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
return NULL;
}
+ if ((settings_font->flags & BLF_MONOSPACED) && (settings_font != glyph_font)) {
+ blf_glyph_transform_monospace(glyph, BLI_wcwidth((char32_t)charcode) * fixed_width);
+ }
+
if ((settings_font->flags & BLF_ITALIC) != 0) {
/* 37.5% of maximum rightward slant results in 6 degree slope, matching italic
* version (`DejaVuSans-Oblique.ttf`) of our current font. But a nice median when
@@ -466,7 +836,8 @@ GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode)
* renderer uses a shared buffer internally. */
BLI_spin_lock(font_with_glyph->ft_lib_mutex);
- FT_GlyphSlot glyph = blf_glyph_render(font, font_with_glyph, glyph_index);
+ FT_GlyphSlot glyph = blf_glyph_render(
+ font, font_with_glyph, glyph_index, charcode, gc->fixed_width);
if (glyph) {
/* Save this glyph in the initial font's cache. */
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 7754f960043..84037ff4bd0 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -14,6 +14,12 @@ struct ResultBLF;
struct rctf;
struct rcti;
+/* Max number of fonts in memory. Take care that every font has a glyph cache per size/dpi,
+ * so we don't need load the same font with different size, just load one and call BLF_size. */
+#define BLF_MAX_FONT 32
+
+extern struct FontBLF *global_font[BLF_MAX_FONT];
+
void blf_batch_draw_begin(struct FontBLF *font);
void blf_batch_draw(void);
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 9dfcb1a4ad6..998093dae70 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -226,6 +226,11 @@ typedef struct FontBLF {
/** File-path or NULL. */
char *filepath;
+ /* Copied from the SFNT OS/2 table. Bit flags for unicode blocks and ranges
+ * considered "functional". Cached here because face might not always exist.
+ * See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur */
+ uint UnicodeRanges[4];
+
/* aspect ratio or scale. */
float aspect[3];
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index 78edb6b95ed..13eefd27bec 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -50,7 +50,7 @@ typedef enum eAttrDomainMask {
/* Attributes. */
-bool BKE_id_attributes_supported(struct ID *id);
+bool BKE_id_attributes_supported(const struct ID *id);
bool BKE_attribute_allow_procedural_access(const char *attribute_name);
/**
@@ -58,25 +58,30 @@ bool BKE_attribute_allow_procedural_access(const char *attribute_name);
*/
struct CustomDataLayer *BKE_id_attribute_new(
struct ID *id, const char *name, int type, eAttrDomain domain, struct ReportList *reports);
-bool BKE_id_attribute_remove(struct ID *id,
- struct CustomDataLayer *layer,
- struct ReportList *reports);
+bool BKE_id_attribute_remove(struct ID *id, const char *name, struct ReportList *reports);
+
+/**
+ * Creates a duplicate attribute layer.
+ */
+struct CustomDataLayer *BKE_id_attribute_duplicate(struct ID *id,
+ const char *name,
+ struct ReportList *reports);
struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
const char *name,
int type,
eAttrDomain domain);
-struct CustomDataLayer *BKE_id_attribute_search(const struct ID *id,
+struct CustomDataLayer *BKE_id_attribute_search(struct ID *id,
const char *name,
eCustomDataMask type,
eAttrDomainMask domain_mask);
eAttrDomain BKE_id_attribute_domain(const struct ID *id, const struct CustomDataLayer *layer);
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
-bool BKE_id_attribute_required(struct ID *id, struct CustomDataLayer *layer);
+bool BKE_id_attribute_required(const struct ID *id, const char *name);
bool BKE_id_attribute_rename(struct ID *id,
- struct CustomDataLayer *layer,
+ const char *old_name,
const char *new_name,
struct ReportList *reports);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index ab13a2e85d0..2cd753da9d3 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -25,7 +25,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 0
+#define BLENDER_FILE_SUBVERSION 1
/* 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_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h
index 8b2af96a063..8c65214c78e 100644
--- a/source/blender/blenkernel/BKE_callbacks.h
+++ b/source/blender/blenkernel/BKE_callbacks.h
@@ -97,6 +97,12 @@ typedef enum {
BKE_CB_EVT_XR_SESSION_START_PRE,
BKE_CB_EVT_ANNOTATION_PRE,
BKE_CB_EVT_ANNOTATION_POST,
+ BKE_CB_EVT_OBJECT_BAKE_PRE,
+ BKE_CB_EVT_OBJECT_BAKE_COMPLETE,
+ BKE_CB_EVT_OBJECT_BAKE_CANCEL,
+ BKE_CB_EVT_COMPOSITE_PRE,
+ BKE_CB_EVT_COMPOSITE_POST,
+ BKE_CB_EVT_COMPOSITE_CANCEL,
BKE_CB_EVT_TOT,
} eCbEvent;
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index 41d369ae9b2..feb3dc7de80 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -119,7 +119,7 @@ bool BKE_collection_object_add(struct Main *bmain,
/**
* Add object to given collection, similar to #BKE_collection_object_add.
*
- * However, it additionnally ensures that the selected collection is also part of the given
+ * However, it additionally ensures that the selected collection is also part of the given
* `view_layer`, if non-NULL. Otherwise, the object is not added to any collection.
*/
bool BKE_collection_viewlayer_object_add(struct Main *bmain,
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index ce1f4c2b98c..737b05fee0c 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -307,6 +307,25 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
void *ownerdata,
float mat[4][4],
float ctime);
+
+/**
+ * Retrieves the list of all constraint targets, including the custom space target.
+ * Must be followed by a call to BKE_constraint_targets_flush to free memory.
+ *
+ * \param r_targets Pointer to the list to be initialized with target data.
+ * \returns the number of targets stored in the list.
+ */
+int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets);
+
+/**
+ * Copies changed data from the list produced by BKE_constraint_targets_get back to the constraint
+ * data structures and frees memory.
+ *
+ * \param targets List of targets filled by BKE_constraint_targets_get.
+ * \param no_copy Only free memory without copying changes (read-only mode).
+ */
+void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy);
+
/**
* Get the list of targets required for solving a constraint.
*/
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index f441203d9d6..b7068720469 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -222,9 +222,10 @@ void CTX_wm_operator_poll_msg_clear(struct bContext *C);
/* Data Context
*
- * - listbases consist of CollectionPointerLink items and must be
- * freed with BLI_freelistN!
- * - the dir listbase consists of LinkData items */
+ * - #ListBase consists of #CollectionPointerLink items and must be
+ * freed with #BLI_freelistN!
+ * - The dir #ListBase consists of #LinkData items.
+ */
/* data type, needed so we can tell between a NULL pointer and an empty list */
enum {
diff --git a/source/blender/blenkernel/BKE_curves.h b/source/blender/blenkernel/BKE_curves.h
index 88bb1c67fd1..c3302c6d2aa 100644
--- a/source/blender/blenkernel/BKE_curves.h
+++ b/source/blender/blenkernel/BKE_curves.h
@@ -25,7 +25,7 @@ void *BKE_curves_add(struct Main *bmain, const char *name);
struct BoundBox *BKE_curves_boundbox_get(struct Object *ob);
-bool BKE_curves_customdata_required(struct Curves *curves, struct CustomDataLayer *layer);
+bool BKE_curves_customdata_required(const struct Curves *curves, const char *name);
/* Depsgraph */
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 168b17bad30..2bebd3ff97d 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -182,6 +182,7 @@ class CurvesGeometry : public ::CurvesGeometry {
void update_curve_types();
bool has_curve_with_type(CurveType type) const;
+ bool has_curve_with_type(Span<CurveType> types) 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. */
@@ -264,22 +265,10 @@ class CurvesGeometry : public ::CurvesGeometry {
MutableSpan<float> nurbs_weights_for_write();
/**
- * The index of a triangle (#MLoopTri) that a curve is attached to.
- * The index is -1, if the curve is not attached.
+ * UV coordinate for each curve that encodes where the curve is attached to the surface mesh.
*/
- VArray<int> surface_triangle_indices() const;
- MutableSpan<int> surface_triangle_indices_for_write();
-
- /**
- * Barycentric coordinates of the attachment point within a triangle.
- * Only the first two coordinates are stored. The third coordinate can be derived because the sum
- * of the three coordinates is 1.
- *
- * When the triangle index is -1, this coordinate should be ignored.
- * The span can be empty, when all triangle indices are -1.
- */
- Span<float2> surface_triangle_coords() const;
- MutableSpan<float2> surface_triangle_coords_for_write();
+ Span<float2> surface_uv_coords() const;
+ MutableSpan<float2> surface_uv_coords_for_write();
VArray<float> selection_point_float() const;
MutableSpan<float> selection_point_float_for_write();
@@ -398,6 +387,7 @@ class CurvesGeometry : public ::CurvesGeometry {
void update_customdata_pointers();
+ void remove_points(IndexMask points_to_delete);
void remove_curves(IndexMask curves_to_delete);
/**
@@ -406,6 +396,11 @@ class CurvesGeometry : public ::CurvesGeometry {
*/
void reverse_curves(IndexMask curves_to_reverse);
+ /**
+ * Remove any attributes that are unused based on the types in the curves.
+ */
+ void remove_attributes_based_on_types();
+
/* --------------------------------------------------------------------
* Attributes.
*/
@@ -722,6 +717,12 @@ inline bool CurvesGeometry::has_curve_with_type(const CurveType type) const
return this->curve_type_counts()[type] > 0;
}
+inline bool CurvesGeometry::has_curve_with_type(const Span<CurveType> types) const
+{
+ return std::any_of(
+ types.begin(), types.end(), [&](CurveType type) { return this->has_curve_with_type(type); });
+}
+
inline const std::array<int, CURVE_TYPES_NUM> &CurvesGeometry::curve_type_counts() const
{
BLI_assert(this->runtime->type_counts == calculate_type_counts(this->curve_types()));
diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh
index 62b060093e9..f223e173ea9 100644
--- a/source/blender/blenkernel/BKE_curves_utils.hh
+++ b/source/blender/blenkernel/BKE_curves_utils.hh
@@ -9,9 +9,53 @@
* \brief Low-level operations for curves.
*/
+#include "BLI_function_ref.hh"
+#include "BLI_generic_pointer.hh"
+
namespace blender::bke::curves {
/**
+ * Copy the provided point attribute values between all curves in the #curve_ranges index
+ * ranges, assuming that all curves have the same number of control points in #src_curves
+ * and #dst_curves.
+ */
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ Span<IndexRange> curve_ranges,
+ GSpan src,
+ GMutableSpan dst);
+
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ IndexMask src_curve_selection,
+ GSpan src,
+ GMutableSpan dst);
+
+template<typename T>
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ const IndexMask src_curve_selection,
+ const Span<T> src,
+ MutableSpan<T> dst)
+{
+ copy_point_data(src_curves, dst_curves, src_curve_selection, GSpan(src), GMutableSpan(dst));
+}
+
+void fill_points(const CurvesGeometry &curves,
+ IndexMask curve_selection,
+ GPointer value,
+ GMutableSpan dst);
+
+template<typename T>
+void fill_points(const CurvesGeometry &curves,
+ const IndexMask curve_selection,
+ const T &value,
+ MutableSpan<T> dst)
+{
+ fill_points(curves, curve_selection, &value, dst);
+}
+
+/**
* Copy the size of every curve in #curve_ranges to the corresponding index in #counts.
*/
void fill_curve_counts(const bke::CurvesGeometry &curves,
@@ -23,4 +67,18 @@ void fill_curve_counts(const bke::CurvesGeometry &curves,
*/
void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, int start_offset = 0);
+IndexMask indices_for_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &type_counts,
+ const CurveType type,
+ const IndexMask selection,
+ Vector<int64_t> &r_indices);
+
+void foreach_curve_by_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &type_counts,
+ IndexMask selection,
+ FunctionRef<void(IndexMask)> catmull_rom_fn,
+ FunctionRef<void(IndexMask)> poly_fn,
+ FunctionRef<void(IndexMask)> bezier_fn,
+ FunctionRef<void(IndexMask)> nurbs_fn);
+
} // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 993ab476830..a1101c1df44 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -225,6 +225,7 @@ void *CustomData_add_layer_anonymous(struct CustomData *data,
* In edit-mode, use #EDBM_data_layer_free instead of this function.
*/
bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index);
+bool CustomData_free_layer_named(struct CustomData *data, const char *name, const int totelem);
/**
* Frees the layer index with the give type.
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 78d80ce200e..4489527fcab 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -259,6 +259,18 @@ struct FCurve *BKE_fcurve_iter_step(struct FCurve *fcu_iter, const char rna_path
/**
* High level function to get an f-curve from C without having the RNA.
+ *
+ * If there is an action assigned to the `id`'s #AnimData, it will be searched for a matching
+ * F-curve first. Drivers are searched only if no valid action F-curve could be found.
+ *
+ * \note Return pointer parameter (`r_driven`) is optional and may be NULL.
+ *
+ * \warning In case no animation (from an Action) F-curve is found, returned value is always NULL.
+ * This means that this function will set `r_driven` to True in case a valid driver F-curve is
+ * found, but will not return said F-curve. In other words:
+ * - Animated with FCurve: returns the `FCurve*` and `*r_driven = false`.
+ * - Animated with driver: returns `NULL` and `*r_driven = true`.
+ * - Not animated: returns `NULL` and `*r_driven = false`.
*/
struct FCurve *id_data_find_fcurve(
ID *id, void *data, struct StructRNA *type, const char *prop_name, int index, bool *r_driven);
@@ -279,6 +291,25 @@ struct FCurve *id_data_find_fcurve(
int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
/**
+ * Find an F-Curve from its rna path and index.
+ *
+ * If there is an action assigned to the `animdata`, it will be searched for a matching F-curve
+ * first. Drivers are searched only if no valid action F-curve could be found.
+ *
+ * \note Typically, indices in RNA arrays are stored separately in F-curves, so the rna_path
+ * should not include them (e.g. `rna_path='location[0]'` will not match any F-Curve on an Object,
+ * but `rna_path='location', rna_index=0` will if it exists).
+ *
+ * \note Return pointer parameters (`r_action`, `r_driven` and `r_special`) are all optional and
+ * may be NULL.
+ */
+struct FCurve *BKE_animadata_fcurve_find_by_rna_path(struct AnimData *animdata,
+ const char *rna_path,
+ const int rna_index,
+ struct bAction **r_action,
+ bool *r_driven);
+
+/**
* Find an f-curve based on an rna property.
*/
struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
@@ -291,7 +322,9 @@ struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
/**
* Same as above, but takes a context data,
* temp hack needed for complex paths like texture ones.
- */
+ *
+ * \param r_special Optional, ignored when NULL. Set to `true` if the given RNA `ptr` is a NLA
+ * strip, and the returned F-curve comes from this NLA strip. */
struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
const struct PointerRNA *ptr,
struct PropertyRNA *prop,
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 60564d1282e..dc7a5ab003a 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -76,13 +76,13 @@ struct bGPdata;
void BKE_gpencil_free_point_weights(struct MDeformVert *dvert);
void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps);
void BKE_gpencil_free_stroke_editcurve(struct bGPDstroke *gps);
-/* free stroke, doesn't unlink from any listbase */
+/** Free stroke, doesn't unlink from any #ListBase. */
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
-/* Free strokes belonging to a gp-frame */
+/** Free strokes belonging to a gp-frame. */
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
-/* Free all of a gp-layer's frames */
+/** Free all of a gp-layer's frames. */
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
-/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
+/** Free all of the gp-layers for a viewport (list should be `&gpd->layers` or so). */
void BKE_gpencil_free_layers(struct ListBase *list);
/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
void BKE_gpencil_free_data(struct bGPdata *gpd, bool free_all);
@@ -108,9 +108,9 @@ void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
*/
void BKE_gpencil_stroke_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
void BKE_gpencil_curve_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
-/* Assign unique stroke ID for selection. */
+/** Assign unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps);
-/* Reset unique stroke ID for selection. */
+/** Reset unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps);
/**
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index 86630a6ab44..2e28b3c00ee 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -70,6 +70,19 @@ bool BKE_lib_override_library_is_user_edited(const struct ID *id);
bool BKE_lib_override_library_is_system_defined(const struct Main *bmain, const struct ID *id);
/**
+ * Check if given Override Property for given ID is animated (through a F-Curve in an Action, or
+ * from a driver).
+ *
+ * \param override_rna_prop if not NULL, the RNA property matching the given path in the
+ * `override_prop`.
+ * \param rnaprop_index Array in the RNA property, 0 if unknown or irrelevant.
+ */
+bool BKE_lib_override_library_property_is_animated(const ID *id,
+ const IDOverrideLibraryProperty *override_prop,
+ const struct PropertyRNA *override_rna_prop,
+ const int rnaprop_index);
+
+/**
* Check if given ID is a leaf in its liboverride hierarchy (i.e. if it does not use any other
* override ID).
*
@@ -281,11 +294,14 @@ void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override
*
* \param idpoin: Pointer to the override ID.
* \param library_prop: The library override property to find the matching RNA property for.
+ * \param r_index: The RNA array flat index (i.e. flattened index in case of multi-dimensional
+ * array properties). See #RNA_path_resolve_full family of functions for details.
*/
bool BKE_lib_override_rna_property_find(struct PointerRNA *idpoin,
const struct IDOverrideLibraryProperty *library_prop,
struct PointerRNA *r_override_poin,
- struct PropertyRNA **r_override_prop);
+ struct PropertyRNA **r_override_prop,
+ int *r_index);
/**
* Find override property operation from given sub-item(s), if it exists.
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 59b22f7759b..2c444f42c46 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -77,8 +77,16 @@ typedef struct MainIDRelationsEntry {
typedef enum eMainIDRelationsEntryTags {
/* Generic tag marking the entry as to be processed. */
MAINIDRELATIONS_ENTRY_TAGS_DOIT = 1 << 0,
+
+ /* Generic tag marking the entry as processed in the `to` direction (i.e. we processed the IDs
+ * used by this item). */
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO = 1 << 1,
+ /* Generic tag marking the entry as processed in the `from` direction (i.e. we processed the IDs
+ * using by this item). */
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM = 1 << 2,
/* Generic tag marking the entry as processed. */
- MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = 1 << 1,
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO |
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM,
} eMainIDRelationsEntryTags;
typedef struct MainIDRelations {
diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
index abaf2ab0178..441783d46a1 100644
--- a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
+++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
@@ -23,6 +23,8 @@ namespace blender::meshintersect {
* \param material_remaps: An array of maps from material slot numbers in the corresponding mesh
* to the material slot in the first mesh. It is OK for material_remaps or any of its constituent
* arrays to be empty.
+ * \param r_intersecting_edges: Array to store indices of edges on the resulting mesh in. These
+ * 'new' edges are the result of the intersections.
*/
Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<const float4x4 *> transforms,
@@ -30,6 +32,7 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<Array<short>> material_remaps,
bool use_self,
bool hole_tolerant,
- int boolean_mode);
+ int boolean_mode,
+ Vector<int> *r_intersecting_edges);
} // namespace blender::meshintersect
diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh
index 37c2ad7d3cb..cbbd0249f4f 100644
--- a/source/blender/blenkernel/BKE_mesh_sample.hh
+++ b/source/blender/blenkernel/BKE_mesh_sample.hh
@@ -6,12 +6,20 @@
* \ingroup bke
*/
+#include "BLI_function_ref.hh"
#include "BLI_generic_virtual_array.hh"
#include "BLI_math_vec_types.hh"
+#include "DNA_meshdata_types.h"
+
#include "BKE_attribute.h"
struct Mesh;
+struct BVHTreeFromMesh;
+
+namespace blender {
+class RandomNumberGenerator;
+}
namespace blender::bke {
struct ReadAttributeLookup;
@@ -82,4 +90,55 @@ class MeshAttributeInterpolator {
Span<float3> ensure_nearest_weights();
};
+/**
+ * Find randomly distributed points on the surface of a mesh within a 3D sphere. This does not
+ * sample an exact number of points because it comes with extra overhead to avoid bias that is only
+ * required in some cases. If an exact number of points is required, that has to be implemented at
+ * a higher level.
+ *
+ * \param approximate_density: Roughly the number of points per unit of area.
+ * \return The number of added points.
+ */
+int sample_surface_points_spherical(RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ Span<int> looptri_indices_to_sample,
+ const float3 &sample_pos,
+ float sample_radius,
+ float approximate_density,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions);
+
+/**
+ * Find randomly distributed points on the surface of a mesh within a circle that is projected on
+ * the mesh. This does not result in an exact number of points because that would come with extra
+ * overhead and is not always possible. If an exact number of points is required, that has to be
+ * implemented at a higher level.
+ *
+ * \param region_position_to_ray: Function that converts a 2D position into a 3D ray that is used
+ * to find positions on the mesh.
+ * \param mesh_bvhtree: BVH tree of the triangles in the mesh. Passed in so that it does not have
+ * to be retrieved again.
+ * \param tries_num: Number of 2d positions that are sampled. The maximum
+ * number of new samples.
+ * \return The number of added points.
+ */
+int sample_surface_points_projected(
+ RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ BVHTreeFromMesh &mesh_bvhtree,
+ const float2 &sample_pos_re,
+ float sample_radius_re,
+ FunctionRef<void(const float2 &pos_re, float3 &r_start, float3 &r_end)> region_position_to_ray,
+ bool front_face_only,
+ int tries_num,
+ int max_points,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions);
+
+float3 compute_bary_coord_in_triangle(const Mesh &mesh,
+ const MLoopTri &looptri,
+ const float3 &position);
+
} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 1ff10d06b00..59a1599e7ae 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1493,6 +1493,9 @@ struct TexResult;
#define GEO_NODE_STORE_NAMED_ATTRIBUTE 1156
#define GEO_NODE_INPUT_NAMED_ATTRIBUTE 1157
#define GEO_NODE_REMOVE_ATTRIBUTE 1158
+#define GEO_NODE_INPUT_INSTANCE_ROTATION 1159
+#define GEO_NODE_INPUT_INSTANCE_SCALE 1160
+#define GEO_NODE_VOLUME_CUBE 1161
/** \} */
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 9e0ea5e13d5..a47e4a24f75 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -613,6 +613,10 @@ typedef struct SculptSession {
float init_pivot_rot[4];
float init_pivot_scale[3];
+ float prev_pivot_pos[3];
+ float prev_pivot_rot[4];
+ float prev_pivot_scale[3];
+
union {
struct {
struct SculptVertexPaintGeomMap gmap;
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 7a89dee4148..f517ff3a949 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -221,7 +221,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
PBVHFrustumPlanes *update_frustum,
PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers),
- void *user_data);
+ void *user_data,
+ bool full_render);
void BKE_pbvh_draw_debug_cb(
PBVH *pbvh,
diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h
index c238a24f173..6dbba11a56d 100644
--- a/source/blender/blenkernel/BKE_pointcloud.h
+++ b/source/blender/blenkernel/BKE_pointcloud.h
@@ -30,8 +30,7 @@ struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob);
bool BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]);
void BKE_pointcloud_update_customdata_pointers(struct PointCloud *pointcloud);
-bool BKE_pointcloud_customdata_required(struct PointCloud *pointcloud,
- struct CustomDataLayer *layer);
+bool BKE_pointcloud_customdata_required(const struct PointCloud *pointcloud, const char *name);
/* Dependency Graph */
diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h
index 4ad17610207..271026d4253 100644
--- a/source/blender/blenkernel/BKE_subdiv_modifier.h
+++ b/source/blender/blenkernel/BKE_subdiv_modifier.h
@@ -7,6 +7,8 @@
#pragma once
+#include "BKE_subdiv.h"
+
#include "BLI_sys_types.h"
#ifdef __cplusplus
@@ -24,9 +26,30 @@ struct Subdiv;
struct SubdivSettings;
struct SubsurfModifierData;
-void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings,
- const struct SubsurfModifierData *smd,
- bool use_render_params);
+/* Runtime subsurf modifier data, cached in modifier on evaluated meshes. */
+typedef struct SubsurfRuntimeData {
+ /* Subdivision settings, exists before descriptor or mesh wrapper is created. */
+ SubdivSettings settings;
+
+ /* Cached subdivision surface descriptor, with topology and settings. */
+ struct Subdiv *subdiv;
+ bool set_by_draw_code;
+
+ /* Cached mesh wrapper data, to be used for GPU subdiv or lazy evaluation on CPU. */
+ bool has_gpu_subdiv;
+ int resolution;
+ bool use_optimal_display;
+ bool calc_loop_normals;
+ bool use_loop_normals;
+
+ /* Cached from the draw code for stats display. */
+ int stats_totvert;
+ int stats_totedge;
+ int stats_totpoly;
+ int stats_totloop;
+} SubsurfRuntimeData;
+
+bool BKE_subsurf_modifier_runtime_init(struct SubsurfModifierData *smd, bool use_render_params);
bool BKE_subsurf_modifier_use_custom_loop_normals(const struct SubsurfModifierData *smd,
const struct Mesh *mesh);
@@ -57,12 +80,7 @@ extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv);
* which matches settings and topology.
*/
struct Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(
- const struct SubsurfModifierData *smd,
- const struct SubdivSettings *subdiv_settings,
- const struct Mesh *mesh,
- bool for_draw_code);
-
-struct SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(struct SubsurfModifierData *smd);
+ struct SubsurfRuntimeData *runtime_data, const struct Mesh *mesh, bool for_draw_code);
/**
* Return the #ModifierMode required for the evaluation of the subsurf modifier,
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index 823d32f83ba..f051335fc41 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -19,6 +19,10 @@ struct UnitSettings;
*/
size_t BKE_unit_value_as_string_adaptive(
char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad);
+/**
+ * Representation of a value in units. Negative precision is used to disable stripping of zeroes.
+ * This reduces text jumping when changing values.
+ */
size_t BKE_unit_value_as_string(char *str,
int len_max,
double value,
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 5cf0ca6e062..b3a9d894944 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -52,6 +52,7 @@
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
+#include "BKE_subdiv_modifier.h"
#include "BLI_sys_types.h" /* for intptr_t support */
@@ -598,10 +599,10 @@ static bool mesh_has_modifier_final_normals(const Mesh *mesh_input,
/* Test if mesh has the required loop normals, in case an additional modifier
* evaluation from another instance or from an operator requests it but the
* initial normals were not loop normals. */
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
- return (!do_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
+ return (!calc_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
}
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
@@ -610,16 +611,19 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
Mesh *mesh_final)
{
/* Compute normals. */
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
- mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ if (subsurf_runtime_data) {
+ subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
+ }
- if (do_loop_normals) {
+ if (calc_loop_normals) {
/* Compute loop normals (NOTE: will compute poly and vert normals as well, if needed!). In case
* of deferred CPU subdivision, this will be computed when the wrapper is generated. */
- if (mesh_final->runtime.subsurf_resolution == 0) {
+ if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}
@@ -628,14 +632,14 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
/* without this, drawing ngon tri's faces will show ugly tessellated face
* normals and will also have to calculate normals on the fly, try avoid
* this where possible since calculating polygon normals isn't fast,
- * note that this isn't a problem for subsurf (only quads) or editmode
+ * note that this isn't a problem for subsurf (only quads) or edit-mode
* which deals with drawing differently. */
BKE_mesh_ensure_normals_for_display(mesh_final);
}
/* Some modifiers, like data-transfer, may generate those data as temp layer,
* we do not want to keep them, as they are used by display code when available
- * (i.e. even if autosmooth is disabled). */
+ * (i.e. even if auto-smooth is disabled). */
if (CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) {
CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop);
}
@@ -1266,15 +1270,18 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
return;
}
- const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
- mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ if (subsurf_runtime_data) {
+ subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
+ }
- if (do_loop_normals) {
+ if (calc_loop_normals) {
/* Compute loop normals. In case of deferred CPU subdivision, this will be computed when the
* wrapper is generated. */
- if (mesh_final->runtime.subsurf_resolution == 0) {
+ if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 371bd8ded6d..05b51e0c9fa 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -980,13 +980,10 @@ void BKE_pose_channels_remove(Object *ob,
else {
/* Maybe something the bone references is being removed instead? */
for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == ob) {
if (ct->subtarget[0]) {
@@ -998,9 +995,7 @@ void BKE_pose_channels_remove(Object *ob,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 94b85e42f96..eb4784bebff 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -4074,7 +4074,7 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float
/* objects */
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
- * this tagged by Depsgraph on framechange. This optimization means that objects
+ * this tagged by Depsgraph on frame-change. This optimization means that objects
* linked from other (not-visible) scenes will not need their data calculated.
*/
EVAL_ANIM_IDS(main->objects.first, 0);
diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc
index fedcfc5c721..7c09b4a4ce3 100644
--- a/source/blender/blenkernel/intern/attribute.cc
+++ b/source/blender/blenkernel/intern/attribute.cc
@@ -89,23 +89,7 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
}
}
-static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer)
-{
- DomainInfo info[ATTR_DOMAIN_NUM];
- get_domains(id, info);
-
- for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
- CustomData *customdata = info[domain].customdata;
- if (customdata &&
- ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) {
- return customdata;
- }
- }
-
- return nullptr;
-}
-
-bool BKE_id_attributes_supported(ID *id)
+bool BKE_id_attributes_supported(const ID *id)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
@@ -123,23 +107,26 @@ bool BKE_attribute_allow_procedural_access(const char *attribute_name)
}
bool BKE_id_attribute_rename(ID *id,
- CustomDataLayer *layer,
+ const char *old_name,
const char *new_name,
ReportList *reports)
{
- if (BKE_id_attribute_required(id, layer)) {
+ if (BKE_id_attribute_required(id, old_name)) {
BLI_assert_msg(0, "Required attribute name is not editable");
return false;
}
- CustomData *customdata = attribute_customdata_find(id, layer);
- if (customdata == nullptr) {
+ CustomDataLayer *layer = BKE_id_attribute_search(
+ id, old_name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
+ if (layer == nullptr) {
BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
return false;
}
- BLI_strncpy_utf8(layer->name, new_name, sizeof(layer->name));
- CustomData_set_layer_unique_name(customdata, layer - customdata->layers);
+ char result_name[MAX_CUSTOMDATA_LAYER_NAME];
+ BKE_id_attribute_calc_unique_name(id, new_name, result_name);
+ BLI_strncpy_utf8(layer->name, result_name, sizeof(layer->name));
+
return true;
}
@@ -221,44 +208,73 @@ CustomDataLayer *BKE_id_attribute_new(
return (index == -1) ? nullptr : &(customdata->layers[index]);
}
-bool BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports)
+CustomDataLayer *BKE_id_attribute_duplicate(ID *id, const char *name, ReportList *reports)
{
- CustomData *customdata = attribute_customdata_find(id, layer);
- const int index = (customdata) ?
- CustomData_get_named_layer_index(customdata, layer->type, layer->name) :
- -1;
-
- if (index == -1) {
+ const CustomDataLayer *src_layer = BKE_id_attribute_search(
+ id, name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
+ if (src_layer == nullptr) {
BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
- return false;
+ return nullptr;
+ }
+
+ const eCustomDataType type = (eCustomDataType)src_layer->type;
+ const eAttrDomain domain = BKE_id_attribute_domain(id, src_layer);
+
+ /* Make a copy of name in case CustomData API reallocates the layers. */
+ const std::string name_copy = name;
+
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(id, info);
+ CustomData *customdata = info[domain].customdata;
+
+ CustomDataLayer *new_layer = BKE_id_attribute_new(id, name_copy.c_str(), type, domain, reports);
+ if (new_layer == nullptr) {
+ return nullptr;
}
- if (BKE_id_attribute_required(id, layer)) {
+ const int from_index = CustomData_get_named_layer_index(customdata, type, name_copy.c_str());
+ const int to_index = CustomData_get_named_layer_index(customdata, type, new_layer->name);
+ CustomData_copy_data_layer(
+ customdata, customdata, from_index, to_index, 0, 0, info[domain].length);
+
+ return new_layer;
+}
+
+bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports)
+{
+ if (BKE_id_attribute_required(id, name)) {
BKE_report(reports, RPT_ERROR, "Attribute is required and can't be removed");
return false;
}
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(id, info);
+
switch (GS(id->name)) {
case ID_ME: {
- Mesh *me = (Mesh *)id;
- BMEditMesh *em = me->edit_mesh;
- if (em != nullptr) {
- BM_data_layer_free(em->bm, customdata, layer->type);
- }
- else {
- const int length = BKE_id_attribute_data_length(id, layer);
- CustomData_free_layer(customdata, layer->type, length, index);
+ Mesh *mesh = reinterpret_cast<Mesh *>(id);
+ if (BMEditMesh *em = mesh->edit_mesh) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
+ if (CustomData *data = info[domain].customdata) {
+ if (BM_data_layer_free_named(em->bm, data, name)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
- break;
- }
- default: {
- const int length = BKE_id_attribute_data_length(id, layer);
- CustomData_free_layer(customdata, layer->type, length, index);
- break;
+ ATTR_FALLTHROUGH;
}
+ default:
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
+ if (CustomData *data = info[domain].customdata) {
+ if (CustomData_free_layer_named(data, name, info[domain].length)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
-
- return true;
}
CustomDataLayer *BKE_id_attribute_find(const ID *id,
@@ -284,7 +300,7 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
return nullptr;
}
-CustomDataLayer *BKE_id_attribute_search(const ID *id,
+CustomDataLayer *BKE_id_attribute_search(ID *id,
const char *name,
const eCustomDataMask type_mask,
const eAttrDomainMask domain_mask)
@@ -299,8 +315,8 @@ CustomDataLayer *BKE_id_attribute_search(const ID *id,
}
CustomData *customdata = info[domain].customdata;
- if (customdata == NULL) {
- return NULL;
+ if (customdata == nullptr) {
+ continue;
}
for (int i = 0; i < customdata->totlayer; i++) {
@@ -311,7 +327,7 @@ CustomDataLayer *BKE_id_attribute_search(const ID *id,
}
}
- return NULL;
+ return nullptr;
}
int BKE_id_attributes_length(const ID *id, eAttrDomainMask domain_mask, eCustomDataMask mask)
@@ -380,14 +396,14 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
return 0;
}
-bool BKE_id_attribute_required(ID *id, CustomDataLayer *layer)
+bool BKE_id_attribute_required(const ID *id, const char *name)
{
switch (GS(id->name)) {
case ID_PT: {
- return BKE_pointcloud_customdata_required((PointCloud *)id, layer);
+ return BKE_pointcloud_customdata_required((const PointCloud *)id, name);
}
case ID_CV: {
- return BKE_curves_customdata_required((Curves *)id, layer);
+ return BKE_curves_customdata_required((const Curves *)id, name);
}
default:
return false;
@@ -553,9 +569,9 @@ int BKE_id_attribute_to_index(const ID *id,
continue;
}
- CustomData *cdata = info[domains[i]].customdata;
+ const CustomData *cdata = info[domains[i]].customdata;
for (int j = 0; j < cdata->totlayer; j++) {
- CustomDataLayer *layer_iter = cdata->layers + j;
+ const CustomDataLayer *layer_iter = cdata->layers + j;
if (!(CD_TYPE_AS_MASK(layer_iter->type) & layer_mask) ||
(layer_iter->flag & CD_FLAG_TEMPORARY)) {
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 35f2f94bc91..6ffb3299869 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -6191,6 +6191,40 @@ bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstrai
/* -------- Target-Matrix Stuff ------- */
+int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets)
+{
+ BLI_listbase_clear(r_targets);
+
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ if (!cti) {
+ return 0;
+ }
+
+ int count = 0;
+
+ /* Constraint-specific targets. */
+ if (cti->get_constraint_targets) {
+ count = cti->get_constraint_targets(con, r_targets);
+ }
+
+ return count;
+}
+
+void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ if (!cti) {
+ return;
+ }
+
+ /* Release the constraint-specific targets. */
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(con, targets, no_copy);
+ }
+}
+
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
Scene *scene,
bConstraint *con,
diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc
index 4338883853d..5125e010b81 100644
--- a/source/blender/blenkernel/intern/curve.cc
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -44,7 +44,6 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
-#include "BKE_spline.hh"
#include "BKE_vfont.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc
index ab9dd702630..7ad83263b73 100644
--- a/source/blender/blenkernel/intern/curves.cc
+++ b/source/blender/blenkernel/intern/curves.cc
@@ -89,6 +89,10 @@ static void curves_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src,
dst.curve_offsets = static_cast<int *>(MEM_dupallocN(src.curve_offsets));
+ if (curves_src->surface_uv_map != nullptr) {
+ curves_dst->surface_uv_map = BLI_strdup(curves_src->surface_uv_map);
+ }
+
dst.runtime = MEM_new<bke::CurvesGeometryRuntime>(__func__);
dst.runtime->type_counts = src.runtime->type_counts;
@@ -108,6 +112,7 @@ static void curves_free_data(ID *id)
BKE_curves_batch_cache_free(curves);
MEM_SAFE_FREE(curves->mat);
+ MEM_SAFE_FREE(curves->surface_uv_map);
}
static void curves_foreach_id(ID *id, LibraryForeachIDData *data)
@@ -148,6 +153,8 @@ static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_addre
BLO_write_int32_array(writer, curves->geometry.curve_num + 1, curves->geometry.curve_offsets);
+ BLO_write_string(writer, curves->surface_uv_map);
+
BLO_write_pointer_array(writer, curves->totcol, curves->mat);
if (curves->adt) {
BKE_animdata_blend_write(writer, curves->adt);
@@ -167,6 +174,8 @@ static void curves_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_int32_array(reader, curves->geometry.curve_num + 1, &curves->geometry.curve_offsets);
+ BLO_read_data_address(reader, &curves->surface_uv_map);
+
curves->geometry.runtime = MEM_new<blender::bke::CurvesGeometryRuntime>(__func__);
/* Recalculate curve type count cache that isn't saved in files. */
@@ -199,8 +208,8 @@ IDTypeInfo IDType_ID_CV = {
/*id_filter */ FILTER_ID_CV,
/*main_listbase_index */ INDEX_ID_CV,
/*struct_size */ sizeof(Curves),
- /*name */ "Hair Curves",
- /*name_plural */ "Hair Curves",
+ /*name */ "Curves",
+ /*name_plural */ "curves",
/*translation_context */ BLT_I18NCONTEXT_ID_CURVES,
/*flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
/*asset_type_info */ nullptr,
@@ -264,9 +273,9 @@ BoundBox *BKE_curves_boundbox_get(Object *ob)
return ob->runtime.bb;
}
-bool BKE_curves_customdata_required(Curves *UNUSED(curves), CustomDataLayer *layer)
+bool BKE_curves_customdata_required(const Curves *UNUSED(curves), const char *name)
{
- return layer->type == CD_PROP_FLOAT3 && STREQ(layer->name, ATTR_POSITION);
+ return STREQ(name, ATTR_POSITION);
}
Curves *BKE_curves_copy_for_eval(Curves *curves_src, bool reference)
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index c2e67d853c9..1c3715aaf69 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -18,6 +18,7 @@
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
namespace blender::bke {
@@ -35,10 +36,9 @@ static const std::string ATTR_HANDLE_POSITION_RIGHT = "handle_right";
static const std::string ATTR_NURBS_ORDER = "nurbs_order";
static const std::string ATTR_NURBS_WEIGHT = "nurbs_weight";
static const std::string ATTR_NURBS_KNOTS_MODE = "knots_mode";
-static const std::string ATTR_SURFACE_TRIANGLE_INDEX = "surface_triangle_index";
-static const std::string ATTR_SURFACE_TRIANGLE_COORDINATE = "surface_triangle_coordinate";
static const std::string ATTR_SELECTION_POINT_FLOAT = ".selection_point_float";
static const std::string ATTR_SELECTION_CURVE_FLOAT = ".selection_curve_float";
+static const std::string ATTR_SURFACE_UV_COORDINATE = "surface_uv_coordinate";
/* -------------------------------------------------------------------- */
/** \name Constructors/Destructor
@@ -419,24 +419,14 @@ MutableSpan<int8_t> CurvesGeometry::nurbs_knots_modes_for_write()
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE, 0);
}
-VArray<int> CurvesGeometry::surface_triangle_indices() const
+Span<float2> CurvesGeometry::surface_uv_coords() const
{
- return get_varray_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1);
+ return get_span_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_UV_COORDINATE);
}
-MutableSpan<int> CurvesGeometry::surface_triangle_indices_for_write()
+MutableSpan<float2> CurvesGeometry::surface_uv_coords_for_write()
{
- return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1);
-}
-
-Span<float2> CurvesGeometry::surface_triangle_coords() const
-{
- return get_span_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_COORDINATE);
-}
-
-MutableSpan<float2> CurvesGeometry::surface_triangle_coords_for_write()
-{
- return get_mutable_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_COORDINATE);
+ return get_mutable_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_UV_COORDINATE);
}
VArray<float> CurvesGeometry::selection_point_float() const
@@ -561,16 +551,8 @@ 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;
- }
- const VArray<int8_t> types = this->curve_types();
- if (types.is_single()) {
- return types.get_internal_single() == type ? IndexMask(this->curves_num()) : IndexMask(0);
- }
- Span<int8_t> types_span = types.get_internal_span();
- return index_mask_ops::find_indices_based_on_predicate(
- selection, 1024, r_indices, [&](const int index) { return types_span[index] == type; });
+ return curves::indices_for_type(
+ this->curve_types(), this->curve_type_counts(), type, selection, r_indices);
}
void CurvesGeometry::ensure_nurbs_basis_cache() const
@@ -1118,6 +1100,165 @@ static void *ensure_customdata_layer(CustomData &custom_data,
&custom_data, data_type, CD_DEFAULT, nullptr, tot_elements, name.c_str());
}
+static void copy_between_buffers(const CPPType &type,
+ const void *src_buffer,
+ void *dst_buffer,
+ const IndexRange src_range,
+ const IndexRange dst_range)
+{
+ BLI_assert(src_range.size() == dst_range.size());
+ type.copy_construct_n(POINTER_OFFSET(src_buffer, type.size() * src_range.start()),
+ POINTER_OFFSET(dst_buffer, type.size() * dst_range.start()),
+ src_range.size());
+}
+
+template<typename T>
+static void copy_with_map(const Span<T> src, const Span<int> map, MutableSpan<T> dst)
+{
+ threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ dst[i] = src[map[i]];
+ }
+ });
+}
+
+static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst)
+{
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_with_map(src.typed<T>(), map, dst.typed<T>());
+ });
+}
+
+/**
+ * Builds an array that for every point, contains the corresponding curve index.
+ */
+static Array<int> build_point_to_curve_map(const CurvesGeometry &curves)
+{
+ Array<int> point_to_curve_map(curves.points_num());
+ threading::parallel_for(curves.curves_range(), 1024, [&](const IndexRange curves_range) {
+ for (const int i_curve : curves_range) {
+ point_to_curve_map.as_mutable_span().slice(curves.points_for_curve(i_curve)).fill(i_curve);
+ }
+ });
+ return point_to_curve_map;
+}
+
+static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves,
+ const IndexMask points_to_delete)
+{
+ /* Use a map from points to curves to facilitate using an #IndexMask input. */
+ const Array<int> point_to_curve_map = build_point_to_curve_map(curves);
+
+ const Vector<IndexRange> copy_point_ranges = points_to_delete.extract_ranges_invert(
+ curves.points_range());
+
+ /* For every range of points to copy, find the offset in the result curves point layers. */
+ int new_point_count = 0;
+ Array<int> copy_point_range_dst_offsets(copy_point_ranges.size());
+ for (const int i : copy_point_ranges.index_range()) {
+ copy_point_range_dst_offsets[i] = new_point_count;
+ new_point_count += copy_point_ranges[i].size();
+ }
+ BLI_assert(new_point_count == (curves.points_num() - points_to_delete.size()));
+
+ /* Find out how many non-deleted points there are in every curve. */
+ Array<int> curve_point_counts(curves.curves_num(), 0);
+ for (const IndexRange range : copy_point_ranges) {
+ for (const int point_i : range) {
+ curve_point_counts[point_to_curve_map[point_i]]++;
+ }
+ }
+
+ /* Build the offsets for the new curve points, skipping curves that had all points deleted.
+ * Also store the original indices of the corresponding input curves, to facilitate parallel
+ * copying of curve domain data. */
+ int new_curve_count = 0;
+ int curve_point_offset = 0;
+ Vector<int> new_curve_offsets;
+ Vector<int> new_curve_orig_indices;
+ new_curve_offsets.append(0);
+ for (const int i : curve_point_counts.index_range()) {
+ if (curve_point_counts[i] > 0) {
+ curve_point_offset += curve_point_counts[i];
+ new_curve_offsets.append(curve_point_offset);
+
+ new_curve_count++;
+ new_curve_orig_indices.append(i);
+ }
+ }
+
+ CurvesGeometry new_curves{new_point_count, new_curve_count};
+
+ threading::parallel_invoke(
+ /* Initialize curve offsets. */
+ [&]() { new_curves.offsets_for_write().copy_from(new_curve_offsets); },
+ /* Copy over point attributes. */
+ [&]() {
+ const CustomData &old_point_data = curves.point_data;
+ CustomData &new_point_data = new_curves.point_data;
+ for (const int layer_i : IndexRange(old_point_data.totlayer)) {
+ const CustomDataLayer &old_layer = old_point_data.layers[layer_i];
+ const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
+ const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
+
+ void *dst_buffer = ensure_customdata_layer(
+ new_point_data, old_layer.name, data_type, new_point_count);
+
+ threading::parallel_for(
+ copy_point_ranges.index_range(), 128, [&](const IndexRange ranges_range) {
+ for (const int range_i : ranges_range) {
+ const IndexRange src_range = copy_point_ranges[range_i];
+ copy_between_buffers(type,
+ old_layer.data,
+ dst_buffer,
+ src_range,
+ {copy_point_range_dst_offsets[range_i], src_range.size()});
+ }
+ });
+ }
+ },
+ /* Copy over curve attributes.
+ * In some cases points are just dissolved, so the the number of
+ * curves will be the same. That could be optimized in the future. */
+ [&]() {
+ const CustomData &old_curve_data = curves.curve_data;
+ CustomData &new_curve_data = new_curves.curve_data;
+ for (const int layer_i : IndexRange(old_curve_data.totlayer)) {
+ const CustomDataLayer &old_layer = old_curve_data.layers[layer_i];
+ const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
+ const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
+
+ void *dst_buffer = ensure_customdata_layer(
+ new_curve_data, old_layer.name, data_type, new_curve_count);
+
+ if (new_curves.curves_num() == curves.curves_num()) {
+ type.copy_construct_n(old_layer.data, dst_buffer, new_curves.curves_num());
+ }
+ else {
+ copy_with_map({type, old_layer.data, curves.curves_num()},
+ new_curve_orig_indices,
+ {type, dst_buffer, new_curves.curves_num()});
+ }
+ }
+ });
+
+ new_curves.update_curve_types();
+
+ return new_curves;
+}
+
+void CurvesGeometry::remove_points(const IndexMask points_to_delete)
+{
+ if (points_to_delete.is_empty()) {
+ return;
+ }
+ if (points_to_delete.size() == this->points_num()) {
+ *this = {};
+ }
+ *this = copy_with_removed_points(*this, points_to_delete);
+}
+
static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
const IndexMask curves_to_delete)
{
@@ -1177,20 +1318,17 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
- const void *src_buffer = old_layer.data;
void *dst_buffer = ensure_customdata_layer(
new_point_data, old_layer.name, data_type, new_tot_points);
threading::parallel_for(
old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) {
for (const int range_i : ranges_range) {
- const IndexRange old_point_range = old_point_ranges[range_i];
- const IndexRange new_point_range = new_point_ranges[range_i];
-
- type.copy_construct_n(
- POINTER_OFFSET(src_buffer, type.size() * old_point_range.start()),
- POINTER_OFFSET(dst_buffer, type.size() * new_point_range.start()),
- old_point_range.size());
+ copy_between_buffers(type,
+ old_layer.data,
+ dst_buffer,
+ old_point_ranges[range_i],
+ new_point_ranges[range_i]);
}
});
}
@@ -1204,20 +1342,17 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
- const void *src_buffer = old_layer.data;
void *dst_buffer = ensure_customdata_layer(
- new_curve_data, old_layer.name, data_type, new_tot_points);
+ new_curve_data, old_layer.name, data_type, new_tot_curves);
threading::parallel_for(
old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) {
for (const int range_i : ranges_range) {
- const IndexRange old_curve_range = old_curve_ranges[range_i];
- const IndexRange new_curve_range = new_curve_ranges[range_i];
-
- type.copy_construct_n(
- POINTER_OFFSET(src_buffer, type.size() * old_curve_range.start()),
- POINTER_OFFSET(dst_buffer, type.size() * new_curve_range.start()),
- old_curve_range.size());
+ copy_between_buffers(type,
+ old_layer.data,
+ dst_buffer,
+ old_curve_ranges[range_i],
+ new_curve_ranges[range_i]);
}
});
}
@@ -1230,6 +1365,12 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
void CurvesGeometry::remove_curves(const IndexMask curves_to_delete)
{
+ if (curves_to_delete.is_empty()) {
+ return;
+ }
+ if (curves_to_delete.size() == this->curves_num()) {
+ *this = {};
+ }
*this = copy_with_removed_curves(*this, curves_to_delete);
}
@@ -1333,6 +1474,27 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
this->tag_topology_changed();
}
+void CurvesGeometry::remove_attributes_based_on_types()
+{
+ const int points_num = this->points_num();
+ const int curves_num = this->curves_num();
+ if (!this->has_curve_with_type(CURVE_TYPE_BEZIER)) {
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_LEFT.c_str(), points_num);
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_RIGHT.c_str(), points_num);
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_LEFT.c_str(), points_num);
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_RIGHT.c_str(), points_num);
+ }
+ if (!this->has_curve_with_type(CURVE_TYPE_NURBS)) {
+ CustomData_free_layer_named(&this->point_data, ATTR_NURBS_WEIGHT.c_str(), points_num);
+ CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_ORDER.c_str(), curves_num);
+ CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_KNOTS_MODE.c_str(), curves_num);
+ }
+ if (!this->has_curve_with_type({CURVE_TYPE_BEZIER, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_NURBS})) {
+ CustomData_free_layer_named(&this->curve_data, ATTR_RESOLUTION.c_str(), curves_num);
+ }
+ this->update_customdata_pointers();
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc
index 78c2382b62f..802469399ab 100644
--- a/source/blender/blenkernel/intern/curves_utils.cc
+++ b/source/blender/blenkernel/intern/curves_utils.cc
@@ -4,6 +4,8 @@
* \ingroup bke
*/
+#include "BLI_index_mask_ops.hh"
+
#include "BKE_curves_utils.hh"
namespace blender::bke::curves {
@@ -35,4 +37,86 @@ void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, const int
counts_to_offsets.last() = offset;
}
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ const Span<IndexRange> curve_ranges,
+ const GSpan src,
+ GMutableSpan dst)
+{
+ threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
+ for (const IndexRange range : curve_ranges.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curves(range);
+ const IndexRange dst_points = dst_curves.points_for_curves(range);
+ /* The arrays might be large, so a threaded copy might make sense here too. */
+ dst.slice(dst_points).copy_from(src.slice(src_points));
+ }
+ });
+}
+
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ const IndexMask src_curve_selection,
+ const GSpan src,
+ GMutableSpan dst)
+{
+ threading::parallel_for(src_curve_selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : src_curve_selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ /* The arrays might be large, so a threaded copy might make sense here too. */
+ dst.slice(dst_points).copy_from(src.slice(src_points));
+ }
+ });
+}
+
+void fill_points(const CurvesGeometry &curves,
+ const IndexMask curve_selection,
+ const GPointer value,
+ GMutableSpan dst)
+{
+ BLI_assert(*value.type() == dst.type());
+ const CPPType &type = dst.type();
+ threading::parallel_for(curve_selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : curve_selection.slice(range)) {
+ const IndexRange points = curves.points_for_curve(i);
+ type.fill_assign_n(value.get(), dst.slice(curves.points_for_curve(i)).data(), points.size());
+ }
+ });
+}
+
+IndexMask indices_for_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &type_counts,
+ const CurveType type,
+ const IndexMask selection,
+ Vector<int64_t> &r_indices)
+{
+ if (type_counts[type] == types.size()) {
+ return selection;
+ }
+ if (types.is_single()) {
+ return types.get_internal_single() == type ? IndexMask(types.size()) : IndexMask(0);
+ }
+ Span<int8_t> types_span = types.get_internal_span();
+ return index_mask_ops::find_indices_based_on_predicate(
+ selection, 4096, r_indices, [&](const int index) { return types_span[index] == type; });
+}
+
+void foreach_curve_by_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &counts,
+ const IndexMask selection,
+ FunctionRef<void(IndexMask)> catmull_rom_fn,
+ FunctionRef<void(IndexMask)> poly_fn,
+ FunctionRef<void(IndexMask)> bezier_fn,
+ FunctionRef<void(IndexMask)> nurbs_fn)
+{
+ Vector<int64_t> catmull_rom;
+ Vector<int64_t> poly;
+ Vector<int64_t> bezier;
+ Vector<int64_t> nurbs;
+ catmull_rom_fn(indices_for_type(types, counts, CURVE_TYPE_CATMULL_ROM, selection, catmull_rom));
+ poly_fn(indices_for_type(types, counts, CURVE_TYPE_POLY, selection, poly));
+ bezier_fn(indices_for_type(types, counts, CURVE_TYPE_BEZIER, selection, bezier));
+ nurbs_fn(indices_for_type(types, counts, CURVE_TYPE_NURBS, selection, nurbs));
+}
+
} // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index a63528835ee..bb5b2ee0836 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -20,6 +20,7 @@
#include "BLI_bitmap.h"
#include "BLI_color.hh"
#include "BLI_endian_switch.h"
+#include "BLI_index_range.hh"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_math_vector.hh"
@@ -27,6 +28,7 @@
#include "BLI_path_util.h"
#include "BLI_span.hh"
#include "BLI_string.h"
+#include "BLI_string_ref.hh"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
@@ -57,6 +59,7 @@
using blender::IndexRange;
using blender::Span;
+using blender::StringRef;
using blender::Vector;
/* number of layers to add when growing a CustomData object */
@@ -261,8 +264,8 @@ static void layerInterp_mdeformvert(const void **sources,
};
MDeformVert *dvert = static_cast<MDeformVert *>(dest);
- struct MDeformWeight_Link *dest_dwlink = nullptr;
- struct MDeformWeight_Link *node;
+ MDeformWeight_Link *dest_dwlink = nullptr;
+ MDeformWeight_Link *node;
/* build a list of unique def_nrs for dest */
int totweight = 0;
@@ -289,7 +292,7 @@ static void layerInterp_mdeformvert(const void **sources,
/* if this def_nr is not in the list, add it */
if (!node) {
- struct MDeformWeight_Link *tmp_dwlink = static_cast<MDeformWeight_Link *>(
+ MDeformWeight_Link *tmp_dwlink = static_cast<MDeformWeight_Link *>(
alloca(sizeof(*tmp_dwlink)));
tmp_dwlink->dw.def_nr = dw->def_nr;
tmp_dwlink->dw.weight = weight;
@@ -2237,8 +2240,8 @@ static bool customdata_typemap_is_valid(const CustomData *data)
}
#endif
-bool CustomData_merge(const struct CustomData *source,
- struct CustomData *dest,
+bool CustomData_merge(const CustomData *source,
+ CustomData *dest,
eCustomDataMask mask,
eCDAllocType alloctype,
int totelem)
@@ -2339,8 +2342,8 @@ void CustomData_realloc(CustomData *data, int totelem)
}
}
-void CustomData_copy(const struct CustomData *source,
- struct CustomData *dest,
+void CustomData_copy(const CustomData *source,
+ CustomData *dest,
eCustomDataMask mask,
eCDAllocType alloctype,
int totelem)
@@ -2403,7 +2406,7 @@ void CustomData_free(CustomData *data, int totelem)
CustomData_reset(data);
}
-void CustomData_free_typemask(struct CustomData *data, int totelem, eCustomDataMask mask)
+void CustomData_free_typemask(CustomData *data, int totelem, eCustomDataMask mask)
{
for (int i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
@@ -2458,7 +2461,7 @@ int CustomData_get_layer_index(const CustomData *data, int type)
return data->typemap[type];
}
-int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n)
+int CustomData_get_layer_index_n(const CustomData *data, int type, int n)
{
BLI_assert(n >= 0);
int i = CustomData_get_layer_index(data, type);
@@ -2515,7 +2518,7 @@ int CustomData_get_stencil_layer_index(const CustomData *data, int type)
/* -------------------------------------------------------------------- */
/* index values per layer type */
-int CustomData_get_named_layer(const struct CustomData *data, int type, const char *name)
+int CustomData_get_named_layer(const CustomData *data, int type, const char *name)
{
const int named_index = CustomData_get_named_layer_index(data, type, name);
const int layer_index = data->typemap[type];
@@ -2551,7 +2554,7 @@ int CustomData_get_stencil_layer(const CustomData *data, int type)
return (layer_index != -1) ? data->layers[layer_index].active_mask : -1;
}
-const char *CustomData_get_active_layer_name(const struct CustomData *data, const int type)
+const char *CustomData_get_active_layer_name(const CustomData *data, const int type)
{
/* Get the layer index of the active layer of this type. */
const int layer_index = CustomData_get_active_layer_index(data, type);
@@ -2642,7 +2645,7 @@ void CustomData_set_layer_stencil_index(CustomData *data, int type, int n)
}
}
-void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
+void CustomData_set_layer_flag(CustomData *data, int type, int flag)
{
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
@@ -2651,7 +2654,7 @@ void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
}
}
-void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag)
+void CustomData_clear_layer_flag(CustomData *data, int type, int flag)
{
const int nflag = ~flag;
@@ -2826,7 +2829,7 @@ void *CustomData_add_layer_named(CustomData *data,
return nullptr;
}
-void *CustomData_add_layer_anonymous(struct CustomData *data,
+void *CustomData_add_layer_anonymous(CustomData *data,
int type,
eCDAllocType alloctype,
void *layerdata,
@@ -2899,6 +2902,18 @@ bool CustomData_free_layer(CustomData *data, int type, int totelem, int index)
return true;
}
+bool CustomData_free_layer_named(CustomData *data, const char *name, const int totelem)
+{
+ for (const int i : IndexRange(data->totlayer)) {
+ const CustomDataLayer &layer = data->layers[i];
+ if (StringRef(layer.name) == name) {
+ CustomData_free_layer(data, layer.type, totelem, i);
+ return true;
+ }
+ }
+ return false;
+}
+
bool CustomData_free_layer_active(CustomData *data, int type, int totelem)
{
const int index = CustomData_get_active_layer_index(data, type);
@@ -3032,7 +3047,7 @@ void CustomData_duplicate_referenced_layers(CustomData *data, int totelem)
}
}
-bool CustomData_is_referenced_layer(struct CustomData *data, int type)
+bool CustomData_is_referenced_layer(CustomData *data, int type)
{
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
@@ -3077,7 +3092,7 @@ void CustomData_free_temporary(CustomData *data, int totelem)
}
}
-void CustomData_set_only_copy(const struct CustomData *data, eCustomDataMask mask)
+void CustomData_set_only_copy(const CustomData *data, eCustomDataMask mask)
{
for (int i = 0; i < data->totlayer; i++) {
if (!(mask & CD_TYPE_AS_MASK(data->layers[i].type))) {
@@ -3310,7 +3325,7 @@ void CustomData_interp(const CustomData *source,
}
}
-void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices)
+void CustomData_swap_corners(CustomData *data, int index, const int *corner_indices)
{
for (int i = 0; i < data->totlayer; i++) {
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
@@ -3323,7 +3338,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
}
}
-void CustomData_swap(struct CustomData *data, const int index_a, const int index_b)
+void CustomData_swap(CustomData *data, const int index_a, const int index_b)
{
char buff_static[256];
@@ -3402,7 +3417,7 @@ void *CustomData_get_layer_n(const CustomData *data, int type, int n)
return data->layers[layer_index].data;
}
-void *CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
+void *CustomData_get_layer_named(const CustomData *data, int type, const char *name)
{
int layer_index = CustomData_get_named_layer_index(data, type, name);
if (layer_index == -1) {
@@ -3469,7 +3484,7 @@ void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
return ptr;
}
-void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr)
+void *CustomData_set_layer_n(const CustomData *data, int type, int n, void *ptr)
{
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_layer_index_n(data, type, n);
@@ -3986,7 +4001,7 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
return POINTER_OFFSET(block, data->layers[n].offset);
}
-bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
+bool CustomData_layer_has_math(const CustomData *data, int layer_n)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
@@ -3998,7 +4013,7 @@ bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
return false;
}
-bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n)
+bool CustomData_layer_has_interp(const CustomData *data, int layer_n)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
@@ -4009,7 +4024,7 @@ bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n)
return false;
}
-bool CustomData_has_math(const struct CustomData *data)
+bool CustomData_has_math(const CustomData *data)
{
/* interpolates a layer at a time */
for (int i = 0; i < data->totlayer; i++) {
@@ -4021,7 +4036,7 @@ bool CustomData_has_math(const struct CustomData *data)
return false;
}
-bool CustomData_bmesh_has_free(const struct CustomData *data)
+bool CustomData_bmesh_has_free(const CustomData *data)
{
for (int i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
@@ -4034,7 +4049,7 @@ bool CustomData_bmesh_has_free(const struct CustomData *data)
return false;
}
-bool CustomData_has_interp(const struct CustomData *data)
+bool CustomData_has_interp(const CustomData *data)
{
/* interpolates a layer at a time */
for (int i = 0; i < data->totlayer; i++) {
@@ -4046,7 +4061,7 @@ bool CustomData_has_interp(const struct CustomData *data)
return false;
}
-bool CustomData_has_referenced(const struct CustomData *data)
+bool CustomData_has_referenced(const CustomData *data)
{
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].flag & CD_FLAG_NOFREE) {
@@ -4505,7 +4520,7 @@ void CustomData_validate_layer_name(const CustomData *data,
}
}
-bool CustomData_verify_versions(struct CustomData *data, int index)
+bool CustomData_verify_versions(CustomData *data, int index)
{
const LayerTypeInfo *typeInfo;
CustomDataLayer *layer = &data->layers[index];
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 48f2d66c1cd..e5bb70f8cda 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -2024,13 +2024,13 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
settings.use_threading = (sData->total_points > 1000);
BLI_task_parallel_range(
0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb, &settings);
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_normals_tag_dirty(result);
}
/* displace */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
dynamicPaint_applySurfaceDisplace(surface, result);
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_normals_tag_dirty(result);
}
}
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 952d5df299c..0203620df84 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -229,16 +229,13 @@ FCurve *id_data_find_fcurve(
return NULL;
}
- /* Animation takes priority over drivers. */
- if (adt->action && adt->action->curves.first) {
- fcu = BKE_fcurve_find(&adt->action->curves, path, index);
- }
-
- /* If not animated, check if driven. */
- if (fcu == NULL && adt->drivers.first) {
- fcu = BKE_fcurve_find(&adt->drivers, path, index);
- if (fcu && r_driven) {
- *r_driven = true;
+ /* FIXME: The way drivers are handled here (always NULL-ifying `fcu`) is very weird, this needs
+ * to be re-checked I think?. */
+ bool is_driven = false;
+ fcu = BKE_animadata_fcurve_find_by_rna_path(adt, path, index, NULL, &is_driven);
+ if (is_driven) {
+ if (r_driven != NULL) {
+ *r_driven = is_driven;
}
fcu = NULL;
}
@@ -259,12 +256,11 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i
/* Check paths of curves, then array indices... */
for (fcu = list->first; fcu; fcu = fcu->next) {
+ /* Check indices first, much cheaper than a string comparison. */
/* Simple string-compare (this assumes that they have the same root...) */
- if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) {
- /* Now check indices. */
- if (fcu->array_index == array_index) {
- return fcu;
- }
+ if (UNLIKELY(fcu->array_index == array_index && fcu->rna_path &&
+ fcu->rna_path[0] == rna_path[0] && STREQ(fcu->rna_path, rna_path))) {
+ return fcu;
}
}
@@ -339,6 +335,47 @@ int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, con
return matches;
}
+FCurve *BKE_animadata_fcurve_find_by_rna_path(
+ AnimData *animdata, const char *rna_path, int rna_index, bAction **r_action, bool *r_driven)
+{
+ if (r_driven != NULL) {
+ *r_driven = false;
+ }
+ if (r_action != NULL) {
+ *r_action = NULL;
+ }
+
+ const bool has_action_fcurves = animdata->action != NULL &&
+ !BLI_listbase_is_empty(&animdata->action->curves);
+ const bool has_drivers = !BLI_listbase_is_empty(&animdata->drivers);
+
+ /* Animation takes priority over drivers. */
+ if (has_action_fcurves) {
+ FCurve *fcu = BKE_fcurve_find(&animdata->action->curves, rna_path, rna_index);
+
+ if (fcu != NULL) {
+ if (r_action != NULL) {
+ *r_action = animdata->action;
+ }
+ return fcu;
+ }
+ }
+
+ /* If not animated, check if driven. */
+ if (has_drivers) {
+ FCurve *fcu = BKE_fcurve_find(&animdata->drivers, rna_path, rna_index);
+
+ if (fcu != NULL) {
+ if (r_driven != NULL) {
+ *r_driven = true;
+ }
+ return fcu;
+ }
+ }
+
+ return NULL;
+}
+
FCurve *BKE_fcurve_find_by_rna(PointerRNA *ptr,
PropertyRNA *prop,
int rnaindex,
@@ -360,17 +397,18 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *UNUSED(C),
bool *r_driven,
bool *r_special)
{
- FCurve *fcu = NULL;
-
- *r_driven = false;
- *r_special = false;
-
- if (r_animdata) {
+ if (r_animdata != NULL) {
*r_animdata = NULL;
}
- if (r_action) {
+ if (r_action != NULL) {
*r_action = NULL;
}
+ if (r_driven != NULL) {
+ *r_driven = false;
+ }
+ if (r_special) {
+ *r_special = false;
+ }
/* Special case for NLA Control Curves... */
if (BKE_nlastrip_has_curves_for_property(ptr, prop)) {
@@ -379,59 +417,46 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *UNUSED(C),
/* Set the special flag, since it cannot be a normal action/driver
* if we've been told to start looking here...
*/
- *r_special = true;
+ if (r_special) {
+ *r_special = true;
+ }
+
+ *r_driven = false;
+ if (r_animdata) {
+ *r_animdata = NULL;
+ }
+ if (r_action) {
+ *r_action = NULL;
+ }
/* The F-Curve either exists or it doesn't here... */
- fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
- return fcu;
+ return BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
}
/* There must be some RNA-pointer + property combo. */
if (!prop || !ptr->owner_id || !RNA_property_animateable(ptr, prop)) {
- return fcu;
+ return NULL;
}
AnimData *adt = BKE_animdata_from_id(ptr->owner_id);
if (adt == NULL) {
- return fcu;
+ return NULL;
}
- const bool has_action_fcurves = adt->action != NULL &&
- !BLI_listbase_is_empty(&adt->action->curves);
- const bool has_drivers = !BLI_listbase_is_empty(&adt->drivers);
-
/* XXX This function call can become a performance bottleneck. */
- char *path = RNA_path_from_ID_to_property(ptr, prop);
-
- /* Standard F-Curve - Animation (Action) or Drivers. */
- /* Animation takes priority over drivers. */
- /* XXX: The logic here is duplicated with a function up above. */
- if (has_action_fcurves) {
- fcu = BKE_fcurve_find(&adt->action->curves, path, rnaindex);
-
- if (fcu) {
- if (r_action) {
- *r_action = adt->action;
- }
- if (r_animdata) {
- *r_animdata = adt;
- }
- }
+ char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+ if (rna_path == NULL) {
+ return NULL;
}
- /* If not animated, check if driven. */
- if (fcu == NULL && has_drivers) {
- fcu = BKE_fcurve_find(&adt->drivers, path, rnaindex);
+ /* Standard F-Curve from animdata - Animation (Action) or Drivers. */
+ FCurve *fcu = BKE_animadata_fcurve_find_by_rna_path(adt, rna_path, rnaindex, r_action, r_driven);
- if (fcu) {
- if (r_animdata) {
- *r_animdata = adt;
- }
- *r_driven = true;
- }
+ if (fcu != NULL && r_animdata != NULL) {
+ *r_animdata = adt;
}
- MEM_SAFE_FREE(path);
+ MEM_freeN(rna_path);
return fcu;
}
@@ -999,9 +1024,8 @@ static void UNUSED_FUNCTION(bezt_add_to_cfra_elem)(ListBase *lb, BezTriple *bezt
* \{ */
/* Some utilities for working with FPoints (i.e. 'sampled' animation curve data, such as
- * data imported from BVH/Mocap files), which are specialized for use with high density datasets,
- * which BezTriples/Keyframe data are ill equipped to do.
- */
+ * data imported from BVH/motion-capture files), which are specialized for use with high density
+ * datasets, which BezTriples/Keyframe data are ill equipped to do. */
float fcurve_samplingcb_evalcurve(FCurve *fcu, void *UNUSED(data), float evaltime)
{
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
index 0003961c033..af058534f68 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -12,7 +12,6 @@
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
-#include "BKE_spline.hh"
#include "attribute_access_intern.hh"
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 10226bc6990..1a43c4d01b0 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_bounds.hh"
#include "BLI_map.hh"
#include "BLI_task.hh"
@@ -15,7 +16,6 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
#include "BKE_volume.h"
#include "DNA_collection_types.h"
@@ -175,6 +175,7 @@ Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const
{
+ using namespace blender;
bool have_minmax = false;
if (const PointCloud *pointcloud = this->get_pointcloud_for_read()) {
have_minmax |= BKE_pointcloud_minmax(pointcloud, *r_min, *r_max);
@@ -185,10 +186,16 @@ bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_ma
if (const Volume *volume = this->get_volume_for_read()) {
have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max);
}
- if (const Curves *curves = this->get_curves_for_read()) {
- std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves);
+ if (const Curves *curves_id = this->get_curves_for_read()) {
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
/* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */
- have_minmax |= curve->bounds_min_max(*r_min, *r_max, true);
+ std::optional<bounds::MinMaxResult<float3>> min_max = bounds::min_max(
+ curves.evaluated_positions());
+ if (min_max) {
+ have_minmax = true;
+ *r_min = math::min(*r_min, min_max->min);
+ *r_max = math::max(*r_max, min_max->max);
+ }
}
return have_minmax;
}
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index d3c3f41779a..2d6e0e05a97 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -32,9 +32,7 @@ static void add_final_mesh_as_geometry_component(const Object &object, GeometryS
if (mesh != nullptr) {
BKE_mesh_wrapper_ensure_mdata(mesh);
-
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
+ geometry_set.replace_mesh(mesh, GeometryOwnershipType::ReadOnly);
}
}
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index faafd1e1040..0bf5418ea8f 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -647,32 +647,38 @@ static bGPdata *gpencil_copy_structure_for_eval(bGPdata *gpd)
return gpd_eval;
}
-static void copy_frame_to_eval_cb(bGPDlayer *UNUSED(gpl),
+static void copy_frame_to_eval_ex(bGPDframe *gpf_orig, bGPDframe *gpf_eval)
+{
+ /* Free any existing eval stroke data. This happens in case we have a single user on the data
+ * block and the strokes have not been deleted. */
+ if (!BLI_listbase_is_empty(&gpf_eval->strokes)) {
+ BKE_gpencil_free_strokes(gpf_eval);
+ }
+ /* Copy strokes to eval frame and update internal orig pointers. */
+ BKE_gpencil_frame_copy_strokes(gpf_orig, gpf_eval);
+ BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf_eval);
+}
+
+static void copy_frame_to_eval_cb(bGPDlayer *gpl,
bGPDframe *gpf,
bGPDstroke *UNUSED(gps),
void *UNUSED(thunk))
{
- /* Early return when callback is not provided with a frame. */
- if (gpf == NULL) {
+ /* Early return when callback:
+ * - Is not provided with a frame.
+ * - When the frame is the layer's active frame (already handled in
+ * gpencil_copy_visible_frames_to_eval).
+ */
+ if (gpf == NULL || gpf == gpl->actframe) {
return;
}
- /* Free any existing eval stroke data. This happens in case we have a single user on the data
- * block and the strokes have not been deleted. */
- if (!BLI_listbase_is_empty(&gpf->strokes)) {
- BKE_gpencil_free_strokes(gpf);
- }
-
- /* Get original frame. */
- bGPDframe *gpf_orig = gpf->runtime.gpf_orig;
- /* Copy strokes to eval frame and update internal orig pointers. */
- BKE_gpencil_frame_copy_strokes(gpf_orig, gpf);
- BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf);
+ copy_frame_to_eval_ex(gpf->runtime.gpf_orig, gpf);
}
static void gpencil_copy_visible_frames_to_eval(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- /* Remap layers' active frame with time modifiers applied. */
+ /* Remap layers active frame with time modifiers applied. */
bGPdata *gpd_eval = ob->data;
LISTBASE_FOREACH (bGPDlayer *, gpl_eval, &gpd_eval->layers) {
bGPDframe *gpf_eval = gpl_eval->actframe;
@@ -680,9 +686,14 @@ static void gpencil_copy_visible_frames_to_eval(Depsgraph *depsgraph, Scene *sce
if (gpf_eval == NULL || gpf_eval->framenum != remap_cfra) {
gpl_eval->actframe = BKE_gpencil_layer_frame_get(gpl_eval, remap_cfra, GP_GETFRAME_USE_PREV);
}
+ /* Always copy active frame to eval, because the modifiers always evaluate the active frame,
+ * even if it's not visible (e.g. the layer is hidden).*/
+ if (gpl_eval->actframe != NULL) {
+ copy_frame_to_eval_ex(gpl_eval->actframe->runtime.gpf_orig, gpl_eval->actframe);
+ }
}
- /* Copy only visible frames to evaluated version. */
+ /* Copy visible frames that are not the active one to evaluated version. */
BKE_gpencil_visible_stroke_advanced_iter(
NULL, ob, copy_frame_to_eval_cb, NULL, NULL, true, scene->r.cfra);
}
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index e99230ef523..35f02c29a00 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -168,7 +168,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
/* NOTE: This code comes from python, here's the corresponding comment. */
/* This over-allocates proportional to the list size, making room
- * for additional growth. The over-allocation is mild, but is
+ * for additional growth. The over-allocation is mild, but is
* enough to give linear-time amortized behavior over a long
* sequence of appends() in the presence of a poorly-performing
* system realloc().
diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc
index 06a5d877882..0c1f01c3796 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -1730,7 +1730,7 @@ static void stampdata_from_template(StampData *stamp_data,
stamp_data->file[0] = '\0';
}
if (scene->r.stamp & R_STAMP_NOTE) {
- SNPRINTF(stamp_data->note, "%s", stamp_data_template->note);
+ STRNCPY(stamp_data->note, stamp_data_template->note);
}
else {
stamp_data->note[0] = '\0';
@@ -3895,7 +3895,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
}
if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D) {
- IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], ibuf_arr.data(), &ibuf_arr[1]);
}
for (int i = 0; i < totviews; i++) {
@@ -4064,7 +4064,7 @@ static ImBuf *image_load_image_file(
/* multi-views/multi-layers OpenEXR files directly populate ima, and return null ibuf... */
if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D && ibuf_arr[0] &&
tot_viewfiles == 1 && totviews >= 2) {
- IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], ibuf_arr.data(), &ibuf_arr[1]);
}
/* return the original requested ImBuf */
diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc
index bed79a318e8..6edb9e1b24c 100644
--- a/source/blender/blenkernel/intern/image_gpu.cc
+++ b/source/blender/blenkernel/intern/image_gpu.cc
@@ -718,12 +718,31 @@ static void gpu_texture_update_from_ibuf(
int tex_offset = ibuf->channels * (y * ibuf->x + x);
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
- if (rect_float == nullptr) {
- /* Byte pixels. */
- if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
- const bool compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(
- ibuf->rect_colorspace);
+ if (rect_float) {
+ /* Float image is already in scene linear colorspace or non-color data by
+ * convention, no colorspace conversion needed. But we do require 4 channels
+ * currently. */
+ if (ibuf->channels != 4 || scaled || !store_premultiplied) {
+ rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
+ if (rect_float == nullptr) {
+ return;
+ }
+ tex_stride = w;
+ tex_offset = 0;
+
+ IMB_colormanagement_imbuf_to_float_texture(
+ rect_float, x, y, w, h, ibuf, store_premultiplied);
+ }
+ }
+ else {
+ /* Byte image is in original colorspace from the file, and may need conversion. */
+ if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+ /* Non-color data, just store buffer as is. */
+ }
+ else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
+ /* sRGB or scene linear, store as byte texture that the GPU can decode directly. */
rect = (uchar *)MEM_mallocN(sizeof(uchar[4]) * w * h, __func__);
if (rect == nullptr) {
return;
@@ -734,13 +753,10 @@ static void gpu_texture_update_from_ibuf(
/* Convert to scene linear with sRGB compression, and premultiplied for
* correct texture interpolation. */
- IMB_colormanagement_imbuf_to_byte_texture(
- rect, x, y, w, h, ibuf, compress_as_srgb, store_premultiplied);
+ IMB_colormanagement_imbuf_to_byte_texture(rect, x, y, w, h, ibuf, store_premultiplied);
}
- }
- else {
- /* Float pixels. */
- if (ibuf->channels != 4 || scaled || !store_premultiplied) {
+ else {
+ /* Other colorspace, store as float texture to avoid precision loss. */
rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
if (rect_float == nullptr) {
return;
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index 6bfdaf9b522..9dda3762553 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -274,6 +274,12 @@ static void image_save_post(ReportList *reports,
if (opts->do_newpath) {
BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
+
+ /* only image path, never ibuf */
+ if (opts->relative) {
+ const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
+ BLI_path_rel(ima->filepath, relbase); /* only after saving */
+ }
}
ibuf->userflags &= ~IB_BITMAPDIRTY;
@@ -303,12 +309,6 @@ static void image_save_post(ReportList *reports,
ima->type = IMA_TYPE_IMAGE;
}
- /* only image path, never ibuf */
- if (opts->relative) {
- const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
- BLI_path_rel(ima->filepath, relbase); /* only after saving */
- }
-
/* Update image file color space when saving to another color space. */
const bool linear_float_output = BKE_imtype_requires_linear_float(opts->im_format.imtype);
diff --git a/source/blender/blenkernel/intern/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc
index 168feebedec..0b91a1e2866 100644
--- a/source/blender/blenkernel/intern/lib_override.cc
+++ b/source/blender/blenkernel/intern/lib_override.cc
@@ -21,8 +21,10 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_collection.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
@@ -312,7 +314,6 @@ bool BKE_lib_override_library_is_user_edited(const ID *id)
bool BKE_lib_override_library_is_system_defined(const Main *bmain, const ID *id)
{
-
if (ID_IS_OVERRIDE_LIBRARY(id)) {
const ID *override_owner_id;
lib_override_get(bmain, id, &override_owner_id);
@@ -322,6 +323,34 @@ bool BKE_lib_override_library_is_system_defined(const Main *bmain, const ID *id)
return false;
}
+bool BKE_lib_override_library_property_is_animated(const ID *id,
+ const IDOverrideLibraryProperty *override_prop,
+ const PropertyRNA *override_rna_prop,
+ const int rnaprop_index)
+{
+ AnimData *anim_data = BKE_animdata_from_id(id);
+ if (anim_data != nullptr) {
+ struct FCurve *fcurve;
+ char *index_token_start = const_cast<char *>(
+ RNA_path_array_index_token_find(override_prop->rna_path, override_rna_prop));
+ if (index_token_start != nullptr) {
+ const char index_token_start_backup = *index_token_start;
+ *index_token_start = '\0';
+ fcurve = BKE_animadata_fcurve_find_by_rna_path(
+ anim_data, override_prop->rna_path, rnaprop_index, nullptr, nullptr);
+ *index_token_start = index_token_start_backup;
+ }
+ else {
+ fcurve = BKE_animadata_fcurve_find_by_rna_path(
+ anim_data, override_prop->rna_path, 0, nullptr, nullptr);
+ }
+ if (fcurve != nullptr) {
+ return true;
+ }
+ }
+ return false;
+}
+
static int foreachid_is_hierarchy_leaf_fn(LibraryIDLinkCallbackData *cb_data)
{
ID *id_owner = cb_data->id_owner;
@@ -658,6 +687,51 @@ static void lib_override_group_tag_data_clear(LibOverrideGroupTagData *data)
memset(data, 0, sizeof(*data));
}
+static void lib_override_hierarchy_dependencies_recursive_tag_from(LibOverrideGroupTagData *data)
+{
+ Main *bmain = data->bmain;
+ ID *id = data->id_root;
+ const bool is_override = data->is_override;
+
+ if ((*(uint *)&id->tag & data->tag) == 0) {
+ /* This ID is not tagged, no reason to proceed further to its parents. */
+ return;
+ }
+
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
+
+ if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM) {
+ /* This ID has already been processed. */
+ return;
+ }
+ /* This way we won't process again that ID, should we encounter it again through another
+ * relationship hierarchy. */
+ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM;
+
+ for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != nullptr;
+ from_id_entry = from_id_entry->next) {
+ if ((from_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
+ /* Never consider non-overridable relationships ('from', 'parents', 'owner' etc. pointers)
+ * as actual dependencies. */
+ continue;
+ }
+ /* We only consider IDs from the same library. */
+ ID *from_id = from_id_entry->id_pointer.from;
+ if (from_id == nullptr || from_id->lib != id->lib ||
+ (is_override && !ID_IS_OVERRIDE_LIBRARY(from_id))) {
+ /* IDs from different libraries, or non-override IDs in case we are processing overrides,
+ * are both barriers of dependency. */
+ continue;
+ }
+ from_id->tag |= data->tag;
+ LibOverrideGroupTagData sub_data = *data;
+ sub_data.id_root = from_id;
+ lib_override_hierarchy_dependencies_recursive_tag_from(&sub_data);
+ }
+}
+
/* Tag all IDs in dependency relationships within an override hierarchy/group.
*
* Requires existing `Main.relations`.
@@ -674,13 +748,13 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
BLI_assert(entry != nullptr);
- if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
+ if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO) {
/* This ID has already been processed. */
return (*(uint *)&id->tag & data->tag) != 0;
}
/* This way we won't process again that ID, should we encounter it again through another
* relationship hierarchy. */
- entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
+ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO;
for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
to_id_entry = to_id_entry->next) {
@@ -704,6 +778,15 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
}
}
+ /* If the current ID is/has been tagged for override above, then check its reversed dependencies
+ * (i.e. IDs that depend on the current one).
+ *
+ * This will cover e.g. the case where user override an armature, and would expect the mesh
+ * object deformed by that armature to also be overridden. */
+ if ((*(uint *)&id->tag & data->tag) != 0) {
+ lib_override_hierarchy_dependencies_recursive_tag_from(data);
+ }
+
return (*(uint *)&id->tag & data->tag) != 0;
}
@@ -2423,7 +2506,7 @@ static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data)
if (id != nullptr && ID_IS_LINKED(id) && id->lib != id_owner->lib) {
const int owner_library_indirect_level = ID_IS_LINKED(id_owner) ? id_owner->lib->temp_index :
0;
- if (owner_library_indirect_level > 200) {
+ if (owner_library_indirect_level > 100) {
CLOG_ERROR(&LOG,
"Levels of indirect usages of libraries is way too high, there are most likely "
"dependency loops, skipping further building loops (involves at least '%s' from "
@@ -2434,6 +2517,16 @@ static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data)
id->lib->filepath);
return IDWALK_RET_NOP;
}
+ if (owner_library_indirect_level > 90) {
+ CLOG_WARN(
+ &LOG,
+ "Levels of indirect usages of libraries is suspiciously too high, there are most likely "
+ "dependency loops (involves at least '%s' from '%s' and '%s' from '%s')",
+ id_owner->name,
+ id_owner->lib->filepath,
+ id->name,
+ id->lib->filepath);
+ }
if (owner_library_indirect_level >= id->lib->temp_index) {
id->lib->temp_index = owner_library_indirect_level + 1;
@@ -2667,11 +2760,12 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibra
bool BKE_lib_override_rna_property_find(PointerRNA *idpoin,
const IDOverrideLibraryProperty *library_prop,
PointerRNA *r_override_poin,
- PropertyRNA **r_override_prop)
+ PropertyRNA **r_override_prop,
+ int *r_index)
{
BLI_assert(RNA_struct_is_ID(idpoin->type) && ID_IS_OVERRIDE_LIBRARY(idpoin->data));
- return RNA_path_resolve_property(
- idpoin, library_prop->rna_path, r_override_poin, r_override_prop);
+ return RNA_path_resolve_property_full(
+ idpoin, library_prop->rna_path, r_override_poin, r_override_prop, r_index);
}
void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 2600a40153c..246999a1179 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -454,7 +454,7 @@ static void libblock_remap_reset_remapping_status_callback(ID *old_id,
* \param old_id: the data-block to dereference (may be NULL if \a id is non-NULL).
* \param new_id: the new data-block to replace \a old_id references with (may be NULL).
* \param r_id_remap_data: if non-NULL, the IDRemap struct to use
- * (uselful to retrieve info about remapping process).
+ * (useful to retrieve info about remapping process).
*/
ATTR_NONNULL(1)
static void libblock_remap_data(Main *bmain,
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index c0eb1955fdf..12a661d139b 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -55,7 +55,7 @@ static void linestyle_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const
FreestyleLineStyle *linestyle_dst = (FreestyleLineStyle *)id_dst;
const FreestyleLineStyle *linestyle_src = (const FreestyleLineStyle *)id_src;
- /* We never handle usercount here for own data. */
+ /* We never handle user-count here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
/* We always need allocation of our private ID data. */
const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index e5b875cadf9..04a07fb42be 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1448,7 +1448,7 @@ static bool fill_texpaint_slots_cb(bNode *node, void *userdata)
slot->attribute_name = storage->name;
if (storage->type == SHD_ATTRIBUTE_GEOMETRY) {
const Mesh *mesh = (const Mesh *)fill_data->ob->data;
- CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name);
+ const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name);
slot->valid = layer != NULL;
}
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index 14bd6aa5b2f..a1ef2d2e6b5 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -791,7 +791,8 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<Array<short>> material_remaps,
const bool use_self,
const bool hole_tolerant,
- const int boolean_mode)
+ const int boolean_mode,
+ Vector<int> *r_intersecting_edges)
{
#ifdef WITH_GMP
BLI_assert(meshes.size() == transforms.size());
@@ -828,7 +829,23 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
write_obj_mesh(m_out, "m_out");
}
- return imesh_to_mesh(&m_out, mim);
+ Mesh *result = imesh_to_mesh(&m_out, mim);
+
+ /* Store intersecting edge indices. */
+ if (r_intersecting_edges != nullptr) {
+ for (int fi : m_out.face_index_range()) {
+ const Face &face = *m_out.face(fi);
+ const MPoly &poly = result->mpoly[fi];
+ for (int corner_i : face.index_range()) {
+ if (face.is_intersect[corner_i]) {
+ int e_index = result->mloop[poly.loopstart + corner_i].e;
+ r_intersecting_edges->append(e_index);
+ }
+ }
+ }
+ }
+
+ return result;
#else // WITH_GMP
UNUSED_VARS(meshes,
transforms,
@@ -836,7 +853,8 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
target_transform,
use_self,
hole_tolerant,
- boolean_mode);
+ boolean_mode,
+ r_intersecting_edges);
return nullptr;
#endif // WITH_GMP
}
diff --git a/source/blender/blenkernel/intern/mesh_calc_edges.cc b/source/blender/blenkernel/intern/mesh_calc_edges.cc
index 5895eb7fd71..31e20750cf2 100644
--- a/source/blender/blenkernel/intern/mesh_calc_edges.cc
+++ b/source/blender/blenkernel/intern/mesh_calc_edges.cc
@@ -81,7 +81,7 @@ static void add_existing_edges_to_hash_maps(Mesh *mesh,
{
/* Assume existing edges are valid. */
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
+ const int task_index = &edge_map - edge_maps.data();
for (const MEdge &edge : Span(mesh->medge, mesh->totedge)) {
OrderedEdge ordered_edge{edge.v1, edge.v2};
/* Only add the edge when it belongs into this map. */
@@ -98,7 +98,7 @@ static void add_polygon_edges_to_hash_maps(Mesh *mesh,
{
const Span<MLoop> loops{mesh->mloop, mesh->totloop};
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
+ const int task_index = &edge_map - edge_maps.data();
for (const MPoly &poly : Span(mesh->mpoly, mesh->totpoly)) {
Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
const MLoop *prev_loop = &poly_loops.last();
@@ -131,7 +131,7 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edg
}
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
+ const int task_index = &edge_map - edge_maps.data();
int new_edge_index = edge_index_offsets[task_index];
for (EdgeMap::MutableItem item : edge_map.items()) {
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index cc4a995b1b1..48c49055899 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -41,7 +41,6 @@
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
-#include "BKE_spline.hh"
/* these 2 are only used by conversion functions */
#include "BKE_curve.h"
/* -- */
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index ba1004e8371..2366b7526a1 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -345,7 +345,7 @@ void BKE_mesh_calc_normals_poly_and_vertex(const MVert *mvert,
const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
{
- if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) {
+ if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
BLI_assert(mesh->runtime.vert_normals != nullptr || mesh->totvert == 0);
return mesh->runtime.vert_normals;
}
@@ -356,7 +356,7 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex;
BLI_mutex_lock(normals_mutex);
- if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) {
+ if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
BLI_assert(mesh->runtime.vert_normals != nullptr);
BLI_mutex_unlock(normals_mutex);
return mesh->runtime.vert_normals;
diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc
index 7595c08a208..106c4c610ba 100644
--- a/source/blender/blenkernel/intern/mesh_sample.cc
+++ b/source/blender/blenkernel/intern/mesh_sample.cc
@@ -2,12 +2,15 @@
#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
+#include "BKE_bvhutils.h"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_sample.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BLI_rand.hh"
+
namespace blender::bke::mesh_surface_sample {
template<typename T>
@@ -259,4 +262,173 @@ void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_
}
}
+int sample_surface_points_spherical(RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ const Span<int> looptri_indices_to_sample,
+ const float3 &sample_pos,
+ const float sample_radius,
+ const float approximate_density,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions)
+{
+ const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
+ BKE_mesh_runtime_looptri_len(&mesh)};
+
+ const float sample_radius_sq = pow2f(sample_radius);
+ const float sample_plane_area = M_PI * sample_radius_sq;
+ /* Used for switching between two triangle sampling strategies. */
+ const float area_threshold = sample_plane_area;
+
+ const int old_num = r_bary_coords.size();
+
+ for (const int looptri_index : looptri_indices_to_sample) {
+ const MLoopTri &looptri = looptris[looptri_index];
+
+ const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co;
+ const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co;
+ const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co;
+
+ const float looptri_area = area_tri_v3(v0, v1, v2);
+
+ if (looptri_area < area_threshold) {
+ /* The triangle is small compared to the sample radius. Sample by generating random
+ * barycentric coordinates. */
+ const int amount = rng.round_probabilistic(approximate_density * looptri_area);
+ for ([[maybe_unused]] const int i : IndexRange(amount)) {
+ const float3 bary_coord = rng.get_barycentric_coordinates();
+ const float3 point_pos = attribute_math::mix3(bary_coord, v0, v1, v2);
+ const float dist_to_sample_sq = math::distance_squared(point_pos, sample_pos);
+ if (dist_to_sample_sq > sample_radius_sq) {
+ continue;
+ }
+
+ r_bary_coords.append(bary_coord);
+ r_looptri_indices.append(looptri_index);
+ r_positions.append(point_pos);
+ }
+ }
+ else {
+ /* The triangle is large compared to the sample radius. Sample by generating random points
+ * on the triangle plane within the sample radius. */
+ float3 normal;
+ normal_tri_v3(normal, v0, v1, v2);
+
+ float3 sample_pos_proj = sample_pos;
+ project_v3_plane(sample_pos_proj, normal, v0);
+
+ const float proj_distance_sq = math::distance_squared(sample_pos_proj, sample_pos);
+ const float sample_radius_factor_sq = 1.0f -
+ std::min(1.0f, proj_distance_sq / sample_radius_sq);
+ const float radius_proj_sq = sample_radius_sq * sample_radius_factor_sq;
+ const float radius_proj = std::sqrt(radius_proj_sq);
+ const float circle_area = M_PI * radius_proj;
+
+ const int amount = rng.round_probabilistic(approximate_density * circle_area);
+
+ const float3 axis_1 = math::normalize(v1 - v0) * radius_proj;
+ const float3 axis_2 = math::normalize(math::cross(axis_1, math::cross(axis_1, v2 - v0))) *
+ radius_proj;
+
+ for ([[maybe_unused]] const int i : IndexRange(amount)) {
+ const float r = std::sqrt(rng.get_float());
+ const float angle = rng.get_float() * 2.0f * M_PI;
+ const float x = r * std::cos(angle);
+ const float y = r * std::sin(angle);
+ const float3 point_pos = sample_pos_proj + axis_1 * x + axis_2 * y;
+ if (!isect_point_tri_prism_v3(point_pos, v0, v1, v2)) {
+ /* Sampled point is not in the triangle. */
+ continue;
+ }
+
+ float3 bary_coord;
+ interp_weights_tri_v3(bary_coord, v0, v1, v2, point_pos);
+
+ r_bary_coords.append(bary_coord);
+ r_looptri_indices.append(looptri_index);
+ r_positions.append(point_pos);
+ }
+ }
+ }
+ return r_bary_coords.size() - old_num;
+}
+
+int sample_surface_points_projected(
+ RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ BVHTreeFromMesh &mesh_bvhtree,
+ const float2 &sample_pos_re,
+ const float sample_radius_re,
+ const FunctionRef<void(const float2 &pos_re, float3 &r_start, float3 &r_end)>
+ region_position_to_ray,
+ const bool front_face_only,
+ const int tries_num,
+ const int max_points,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions)
+{
+ const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
+ BKE_mesh_runtime_looptri_len(&mesh)};
+
+ int point_count = 0;
+ for ([[maybe_unused]] const int _ : IndexRange(tries_num)) {
+ if (point_count == max_points) {
+ break;
+ }
+
+ const float r = sample_radius_re * std::sqrt(rng.get_float());
+ const float angle = rng.get_float() * 2.0f * M_PI;
+ float3 ray_start, ray_end;
+ const float2 pos_re = sample_pos_re + r * float2(std::cos(angle), std::sin(angle));
+ region_position_to_ray(pos_re, ray_start, ray_end);
+ const float3 ray_direction = math::normalize(ray_end - ray_start);
+
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(mesh_bvhtree.tree,
+ ray_start,
+ ray_direction,
+ 0.0f,
+ &ray_hit,
+ mesh_bvhtree.raycast_callback,
+ &mesh_bvhtree);
+
+ if (ray_hit.index == -1) {
+ continue;
+ }
+
+ if (front_face_only) {
+ const float3 normal = ray_hit.no;
+ if (math::dot(ray_direction, normal) >= 0.0f) {
+ continue;
+ }
+ }
+
+ const int looptri_index = ray_hit.index;
+ const float3 pos = ray_hit.co;
+
+ const float3 bary_coords = compute_bary_coord_in_triangle(mesh, looptris[looptri_index], pos);
+
+ r_positions.append(pos);
+ r_bary_coords.append(bary_coords);
+ r_looptri_indices.append(looptri_index);
+ point_count++;
+ }
+ return point_count;
+}
+
+float3 compute_bary_coord_in_triangle(const Mesh &mesh,
+ const MLoopTri &looptri,
+ const float3 &position)
+{
+ const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co;
+ const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co;
+ const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co;
+ float3 bary_coords;
+ interp_weights_tri_v3(bary_coords, v0, v1, v2, position);
+ return bary_coords;
+}
+
} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc
index c505a74724b..fdebf1d6a26 100644
--- a/source/blender/blenkernel/intern/mesh_wrapper.cc
+++ b/source/blender/blenkernel/intern/mesh_wrapper.cc
@@ -314,28 +314,23 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
return me;
}
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (runtime_data == nullptr || runtime_data->settings.level == 0) {
+ return me;
+ }
+
/* Initialize the settings before ensuring the descriptor as this is checked to decide whether
* subdivision is needed at all, and checking the descriptor status might involve checking if the
* data is out-of-date, which is a very expensive operation. */
SubdivToMeshSettings mesh_settings;
- mesh_settings.resolution = me->runtime.subsurf_resolution;
- mesh_settings.use_optimal_display = me->runtime.subsurf_use_optimal_display;
+ mesh_settings.resolution = runtime_data->resolution;
+ mesh_settings.use_optimal_display = runtime_data->use_optimal_display;
if (mesh_settings.resolution < 3) {
return me;
}
- const bool apply_render = me->runtime.subsurf_apply_render;
-
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(&subdiv_settings, smd, apply_render);
- if (subdiv_settings.level == 0) {
- return me;
- }
-
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
-
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, me, false);
if (subdiv == nullptr) {
/* Happens on bad topology, but also on empty input mesh. */
return me;
@@ -358,7 +353,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
CustomData_set_layer_flag(&me->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
CustomData_set_layer_flag(&subdiv_mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
- else if (me->runtime.subsurf_do_loop_normals) {
+ else if (runtime_data->calc_loop_normals) {
BKE_mesh_calc_normals_split(subdiv_mesh);
}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index a5f6c453ed4..8f54d71108a 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -244,24 +244,42 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, const ListBase *src, const
}
}
-static void update_active_strip_from_listbase(AnimData *adt_dest,
- NlaTrack *track_dest,
- const NlaStrip *active_strip,
- const ListBase /* NlaStrip */ *strips_source)
+/**
+ * Find `active_strip` in `strips_source`, then return the strip with the same
+ * index from `strips_dest`.
+ */
+static NlaStrip *find_active_strip_from_listbase(const NlaStrip *active_strip,
+ const ListBase /* NlaStrip */ *strips_source,
+ const ListBase /* NlaStrip */ *strips_dest)
{
- NlaStrip *strip_dest = track_dest->strips.first;
+ NlaStrip *strip_dest = strips_dest->first;
LISTBASE_FOREACH (const NlaStrip *, strip_source, strips_source) {
- if (strip_source == active_strip) {
- adt_dest->actstrip = strip_dest;
- return;
+ if (strip_dest == NULL) {
+ /* The tracks are assumed to have an equal number of strips, but this is not the case when
+ * dragging multiple strips. The transform system merges the selected strips into one
+ * meta-strip, reducing the number of strips in `track_dest`. */
+ break;
}
-
- if (strip_source->type == NLASTRIP_TYPE_META) {
- update_active_strip_from_listbase(adt_dest, track_dest, active_strip, &strip_source->strips);
+ if (strip_source == active_strip) {
+ return strip_dest;
+ }
+
+ const bool src_is_meta = strip_source->type == NLASTRIP_TYPE_META;
+ const bool dst_is_meta = strip_dest->type == NLASTRIP_TYPE_META;
+ BLI_assert_msg(src_is_meta == dst_is_meta,
+ "Expecting topology of source and destination strips to be equal");
+ if (src_is_meta && dst_is_meta) {
+ NlaStrip *found_in_meta = find_active_strip_from_listbase(
+ active_strip, &strip_source->strips, &strip_dest->strips);
+ if (found_in_meta != NULL) {
+ return found_in_meta;
+ }
}
strip_dest = strip_dest->next;
}
+
+ return NULL;
}
/* Set adt_dest->actstrip to the strip with the same index as adt_source->actstrip. */
@@ -272,8 +290,9 @@ static void update_active_strip(AnimData *adt_dest,
{
BLI_assert(BLI_listbase_count(&track_source->strips) == BLI_listbase_count(&track_dest->strips));
- update_active_strip_from_listbase(
- adt_dest, track_dest, adt_source->actstrip, &track_source->strips);
+ NlaStrip *active_strip = find_active_strip_from_listbase(
+ adt_source->actstrip, &track_source->strips, &track_dest->strips);
+ adt_dest->actstrip = active_strip;
}
/* Set adt_dest->act_track to the track with the same index as adt_source->act_track. */
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index cf50e8a3b43..e02d3b6486c 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4764,6 +4764,8 @@ static void registerGeometryNodes()
register_node_type_geo_input_curve_tilt();
register_node_type_geo_input_id();
register_node_type_geo_input_index();
+ register_node_type_geo_input_instance_rotation();
+ register_node_type_geo_input_instance_scale();
register_node_type_geo_input_material_index();
register_node_type_geo_input_material();
register_node_type_geo_input_mesh_edge_angle();
@@ -4834,6 +4836,7 @@ static void registerGeometryNodes()
register_node_type_geo_translate_instances();
register_node_type_geo_triangulate();
register_node_type_geo_viewer();
+ register_node_type_geo_volume_cube();
register_node_type_geo_volume_to_mesh();
}
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 52b25399e32..c8b87c27697 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -2483,21 +2483,16 @@ static void copy_object_pose(Object *obn, const Object *ob, const int flag)
* BKE_library_remap stuff, but...
* the flush_constraint_targets callback am not sure about, so will delay that for now. */
LISTBASE_FOREACH (bConstraint *, con, &chan->constraints) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {nullptr, nullptr};
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == ob) {
ct->tar = obn;
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, false);
- }
+ BKE_constraint_targets_flush(con, &targets, false);
}
}
}
@@ -5488,11 +5483,9 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
/* also update constraint targets */
LISTBASE_FOREACH (bConstraint *, con, &ob->constraints) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {nullptr, nullptr};
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
+ if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar) {
BKE_object_modifier_update_subframe(
@@ -5500,9 +5493,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
}
}
/* free temp targets */
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, false);
- }
+ BKE_constraint_targets_flush(con, &targets, false);
}
}
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index bb499f24c07..81c7e7f34da 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -2117,7 +2117,7 @@ void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object)
/* Copy the current mesh visibility to the Face Sets. */
BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh);
if (object->sculpt != NULL) {
- /* If a sculpt session is active, ensure we have its faceset data porperly up-to-date. */
+ /* If a sculpt session is active, ensure we have its face-set data properly up-to-date. */
object->sculpt->face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
/* NOTE: In theory we could add that on the fly when required by sculpt code.
@@ -2284,7 +2284,7 @@ void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg)
subdiv_ccg->grid_hidden);
}
-bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
+bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *UNUSED(v3d))
{
SculptSession *ss = ob->sculpt;
if (ss == NULL || ss->pbvh == NULL || ss->mode_type != OB_MODE_SCULPT) {
@@ -2293,8 +2293,8 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
/* Regular mesh only draws from PBVH without modifiers and shape keys. */
- const bool full_shading = (v3d && (v3d->shading.type > OB_SOLID));
- return !(ss->shapekey_active || ss->deform_modifiers_active || full_shading);
+
+ return !(ss->shapekey_active || ss->deform_modifiers_active);
}
/* Multires and dyntopo always draw directly from the PBVH. */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index a5f7f73af70..b44b70bcd55 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -2276,7 +2276,7 @@ void psys_emitter_customdata_mask(ParticleSystem *psys, CustomData_MeshMasks *r_
r_cddata_masks->fmask |= CD_MASK_MTFACE;
}
- /* ask for vertexgroups if we need them */
+ /* Ask for vertex-groups if we need them. */
for (i = 0; i < PSYS_TOT_VG; i++) {
if (psys->vgroup[i]) {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index a7ab1536b1f..3ad770c5429 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -3121,7 +3121,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
col.cfra = cfra;
col.old_cfra = sim->psys->cfra;
- /* get acceleration (from gravity, forcefields etc. to be re-applied in collision response) */
+ /* Get acceleration (from gravity, force-fields etc. to be re-applied in collision response). */
sub_v3_v3v3(col.acc, pa->state.vel, pa->prev_state.vel);
mul_v3_fl(col.acc, 1.0f / col.total_time);
@@ -4962,7 +4962,7 @@ void particle_system_update(struct Depsgraph *depsgraph,
}
/* Save matrix for duplicators,
- * at rendertime the actual dupliobject's matrix is used so don't update! */
+ * at render-time the actual dupli-object's matrix is used so don't update! */
invert_m4_m4(psys->imat, ob->obmat);
BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 2b049222073..3b20bdc826c 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -714,6 +714,10 @@ void BKE_pbvh_free(PBVH *pbvh)
MEM_SAFE_FREE(pbvh->vert_bitmap);
+ if (pbvh->vbo_id) {
+ GPU_pbvh_free_format(pbvh->vbo_id);
+ }
+
MEM_freeN(pbvh);
}
@@ -1299,6 +1303,17 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
+ CustomData *vdata, *ldata;
+
+ if (!pbvh->bm) {
+ vdata = pbvh->vdata;
+ ldata = pbvh->ldata;
+ }
+ else {
+ vdata = &pbvh->bm->vdata;
+ ldata = &pbvh->bm->ldata;
+ }
+
if (node->flag & PBVH_RebuildDrawBuffers) {
switch (pbvh->type) {
case PBVH_GRIDS:
@@ -1326,7 +1341,8 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
const int update_flags = pbvh_get_buffers_update_flags(pbvh);
switch (pbvh->type) {
case PBVH_GRIDS:
- GPU_pbvh_grid_buffers_update(node->draw_buffers,
+ GPU_pbvh_grid_buffers_update(pbvh->vbo_id,
+ node->draw_buffers,
pbvh->subdiv_ccg,
pbvh->grids,
pbvh->grid_flag_mats,
@@ -1339,26 +1355,22 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
update_flags);
break;
case PBVH_FACES: {
- CustomDataLayer *layer = NULL;
- eAttrDomain domain;
-
- BKE_pbvh_get_color_layer(pbvh->mesh, &layer, &domain);
-
- GPU_pbvh_mesh_buffers_update(node->draw_buffers,
+ GPU_pbvh_mesh_buffers_update(pbvh->vbo_id,
+ node->draw_buffers,
pbvh->verts,
- pbvh->vert_normals,
+ vdata,
+ ldata,
CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK),
- layer ? layer->data : NULL,
- layer ? layer->type : -1,
- layer ? domain : ATTR_DOMAIN_AUTO,
CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
pbvh->face_sets_color_seed,
pbvh->face_sets_color_default,
- update_flags);
+ update_flags,
+ pbvh->vert_normals);
break;
}
case PBVH_BMESH:
- GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
+ GPU_pbvh_bmesh_buffers_update(pbvh->vbo_id,
+ node->draw_buffers,
pbvh->bm,
node->bm_faces,
node->bm_unique_verts,
@@ -1379,8 +1391,79 @@ void pbvh_free_draw_buffers(PBVH *pbvh, PBVHNode *node)
}
}
+static void pbvh_check_draw_layout(PBVH *pbvh)
+{
+ const CustomData *vdata;
+ const CustomData *ldata;
+
+ if (!pbvh->vbo_id) {
+ pbvh->vbo_id = GPU_pbvh_make_format();
+ }
+
+ switch (pbvh->type) {
+ case PBVH_BMESH:
+ if (!pbvh->bm) {
+ /* BMesh hasn't been created yet */
+ return;
+ }
+
+ vdata = &pbvh->bm->vdata;
+ ldata = &pbvh->bm->ldata;
+ break;
+ case PBVH_FACES:
+ vdata = pbvh->vdata;
+ ldata = pbvh->ldata;
+ break;
+ case PBVH_GRIDS:
+ ldata = vdata = NULL;
+ break;
+ }
+
+ /* Rebuild all draw buffers if attribute layout changed.
+ *
+ * NOTE: The optimization where we only send active attributes
+ * to the GPU in workbench mode is disabled due to bugs
+ * (there's no guarantee there isn't another EEVEE viewport which would
+ * free the draw buffers and corrupt the draw cache).
+ */
+ if (GPU_pbvh_attribute_names_update(pbvh->type, pbvh->vbo_id, vdata, ldata, false)) {
+ /* attribute layout changed; force rebuild */
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (node->flag & PBVH_Leaf) {
+ node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+ }
+ }
+ }
+}
+
static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag)
{
+ const CustomData *vdata;
+
+ if (!pbvh->vbo_id) {
+ pbvh->vbo_id = GPU_pbvh_make_format();
+ }
+
+ switch (pbvh->type) {
+ case PBVH_BMESH:
+ if (!pbvh->bm) {
+ /* BMesh hasn't been created yet */
+ return;
+ }
+
+ vdata = &pbvh->bm->vdata;
+ break;
+ case PBVH_FACES:
+ vdata = pbvh->vdata;
+ break;
+ case PBVH_GRIDS:
+ vdata = NULL;
+ break;
+ }
+ UNUSED_VARS(vdata);
+
if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) {
/* Free buffers uses OpenGL, so not in parallel. */
for (int n = 0; n < totnode; n++) {
@@ -2540,7 +2623,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh,
}
if (origco) {
- /* intersect with backuped original coordinates */
+ /* Intersect with backed-up original coordinates. */
hit |= ray_face_nearest_tri(ray_start,
ray_normal,
origco[face_verts[0]],
@@ -2783,7 +2866,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
PBVHFrustumPlanes *update_frustum,
PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
- void *user_data)
+ void *user_data,
+ bool UNUSED(full_render))
{
PBVHNode **nodes;
int totnode;
@@ -2806,6 +2890,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
}
+ pbvh_check_draw_layout(pbvh);
+
/* Update draw buffers. */
if (totnode != 0 && (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers))) {
pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag);
@@ -3156,6 +3242,11 @@ bool BKE_pbvh_is_drawing(const PBVH *pbvh)
return pbvh->is_drawing;
}
+bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh)
+{
+ return pbvh->draw_cache_invalid;
+}
+
void BKE_pbvh_is_drawing_set(PBVH *pbvh, bool val)
{
pbvh->is_drawing = val;
@@ -3229,8 +3320,3 @@ void BKE_pbvh_ensure_node_loops(PBVH *pbvh)
MEM_SAFE_FREE(visit);
}
-
-bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh)
-{
- return pbvh->draw_cache_invalid;
-}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index d4c6dcfbc96..112fd01c699 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -376,6 +376,9 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
return false;
}
+ /* Trigger draw manager cache invalidation. */
+ pbvh->draw_cache_invalid = true;
+
/* For each BMFace, store the AABB and AABB centroid */
BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC");
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 98b490b28dd..a4ac2744a73 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -2,6 +2,8 @@
#pragma once
+struct PBVHGPUFormat;
+
/** \file
* \ingroup bke
*/
@@ -123,9 +125,7 @@ struct PBVHNode {
PBVHPixelsNode pixels;
};
-typedef enum {
- PBVH_DYNTOPO_SMOOTH_SHADING = 1,
-} PBVHFlags;
+typedef enum { PBVH_DYNTOPO_SMOOTH_SHADING = 1 } PBVHFlags;
typedef struct PBVHBMeshLog PBVHBMeshLog;
@@ -204,6 +204,8 @@ struct PBVH {
/* Used by DynTopo to invalidate the draw cache. */
bool draw_cache_invalid;
+
+ struct PBVHGPUFormat *vbo_id;
};
/* pbvh.c */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 2467ca16670..d7bdfe08ab9 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -3232,7 +3232,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
scene, pid->calldata, &cache->startframe, &cache->endframe);
}
- /* XXX workaround for regression inroduced in ee3fadd, needs looking into */
+ /* XXX: workaround for regression introduced in ee3fadd, needs looking into. */
if (pid->type == PTCACHE_TYPE_RIGIDBODY) {
if ((cache->flag & PTCACHE_REDO_NEEDED ||
(cache->flag & PTCACHE_SIMULATION_VALID) == 0) &&
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 9720c61e3b9..e38c20d8eb7 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -315,9 +315,9 @@ void BKE_pointcloud_update_customdata_pointers(PointCloud *pointcloud)
CustomData_get_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, POINTCLOUD_ATTR_RADIUS));
}
-bool BKE_pointcloud_customdata_required(PointCloud *UNUSED(pointcloud), CustomDataLayer *layer)
+bool BKE_pointcloud_customdata_required(const PointCloud *UNUSED(pointcloud), const char *name)
{
- return layer->type == CD_PROP_FLOAT3 && STREQ(layer->name, POINTCLOUD_ATTR_POSITION);
+ return STREQ(name, POINTCLOUD_ATTR_POSITION);
}
/* Dependency Graph */
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 1996273b681..fda833ffd27 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -247,7 +247,7 @@ bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv,
}
/* Set coordinates of base mesh vertices. */
set_coarse_positions(subdiv, mesh, coarse_vertex_cos);
- /* Set face-varyign data to UV maps. */
+ /* Set face-varying data to UV maps. */
const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
const MLoopUV *mloopuv = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPUV, layer_index);
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index ca4130d6bc4..433bad34479 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -5,9 +5,6 @@
* \ingroup bke
*/
-#include "BKE_mesh.h"
-#include "BKE_subdiv_mesh.h"
-
#include "atomic_ops.h"
#include "DNA_key_types.h"
@@ -24,6 +21,7 @@
#include "BKE_subdiv.h"
#include "BKE_subdiv_eval.h"
#include "BKE_subdiv_foreach.h"
+#include "BKE_subdiv_mesh.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c
index e43da956ce5..f5423dccc0f 100644
--- a/source/blender/blenkernel/intern/subdiv_modifier.c
+++ b/source/blender/blenkernel/intern/subdiv_modifier.c
@@ -3,8 +3,6 @@
#include "BKE_subdiv_modifier.h"
-#include "BLI_session_uuid.h"
-
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
@@ -21,22 +19,40 @@
#include "opensubdiv_capi.h"
-void BKE_subsurf_modifier_subdiv_settings_init(SubdivSettings *settings,
- const SubsurfModifierData *smd,
- const bool use_render_params)
+bool BKE_subsurf_modifier_runtime_init(SubsurfModifierData *smd, const bool use_render_params)
{
const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels;
- settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
- settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
- settings->level = settings->is_simple ?
- 1 :
- (settings->is_adaptive ? smd->quality : requested_levels);
- settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
- settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
+ SubdivSettings settings;
+ settings.is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
+ settings.is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
+ settings.level = settings.is_simple ? 1 :
+ (settings.is_adaptive ? smd->quality : requested_levels);
+ settings.use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
+ settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
smd->boundary_smooth);
- settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
+ settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
smd->uv_smooth);
+
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (settings.level == 0) {
+ /* Modifier is effectively disabled, but still update settings if runtime data
+ * was already allocated. */
+ if (runtime_data) {
+ runtime_data->settings = settings;
+ }
+
+ return false;
+ }
+ else {
+ /* Allocate runtime data if it did not exist yet. */
+ if (runtime_data == NULL) {
+ runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
+ smd->modifier.runtime = runtime_data;
+ }
+ runtime_data->settings = settings;
+ return true;
+ }
}
static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene,
@@ -133,37 +149,27 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh)
{
- return BLI_session_uuid_is_generated(&mesh->runtime.subsurf_session_uuid);
+ SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
+ return runtime_data && runtime_data->has_gpu_subdiv;
}
void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv) = NULL;
-Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(const SubsurfModifierData *smd,
- const SubdivSettings *subdiv_settings,
+Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data,
const Mesh *mesh,
const bool for_draw_code)
{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
if (runtime_data->subdiv && runtime_data->set_by_draw_code != for_draw_code) {
BKE_subdiv_free(runtime_data->subdiv);
runtime_data->subdiv = NULL;
}
- Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh);
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(
+ runtime_data->subdiv, &runtime_data->settings, mesh);
runtime_data->subdiv = subdiv;
runtime_data->set_by_draw_code = for_draw_code;
return subdiv;
}
-SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(SubsurfModifierData *smd)
-{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
- if (runtime_data == NULL) {
- runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
- smd->modifier.runtime = runtime_data;
- }
- return runtime_data;
-}
-
int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode)
{
if (is_final_render) {
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index ba2df362b92..efabb4f039a 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -926,11 +926,9 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
int x;
for (x = 1; x < edgeSize - 1; x++) {
- /* This gives errors with -debug-fpe
- * the normals don't seem to be unit length.
- * this is most likely caused by edges with no
- * faces which are now zerod out, see comment in:
- * ccgSubSurf__calcVertNormals(), - campbell */
+ /* NOTE(@campbellbarton): This gives errors with `--debug-fpe` the normals don't seem to be
+ * unit length. This is most likely caused by edges with no faces which are now zeroed out,
+ * see comment in: `ccgSubSurf__calcVertNormals()`. */
vd = ccgSubSurf_getEdgeData(ss, e, x);
ccgDM_to_MVert(&mvert[i++], &key, vd);
}
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index f9d3a44e5cb..8b462cba7ed 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -336,7 +336,11 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
tracking->stabilization.filter = TRACKING_FILTER_BILINEAR;
tracking->stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
- BKE_tracking_object_add(tracking, "Camera");
+ /* Descending order of average error: tracks with the highest error are on top. */
+ tracking->dopesheet.sort_method = TRACKING_DOPE_SORT_AVERAGE_ERROR;
+ tracking->dopesheet.flag |= TRACKING_DOPE_SORT_INVERSE;
+
+ BKE_tracking_object_add(tracking, DATA_("Camera"));
}
ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
@@ -2904,6 +2908,10 @@ static int channels_average_error_sort(const void *a, const void *b)
return 1;
}
+ if (channel_a->track->error == channel_b->track->error) {
+ return channels_alpha_sort(a, b);
+ }
+
return 0;
}
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index d86a0c10f01..e2e0b4227e3 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -362,7 +362,7 @@ static MovieTrackingMarker *get_tracking_data_point(StabContext *ctx,
*
* As a simple default, we use the weighted average of the location markers
* of the current frame as pivot point. TODO: It is planned to add further
- * options, like e.g. anchoring the pivot point at the canvas. Moreover,
+ * options, like e.g. anchoring the pivot point at the canvas. Moreover,
* it is planned to allow for a user controllable offset.
*/
static void setup_pivot(const float ref_pos[2], float r_pivot[2])
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 30e02e5411b..b31632f0234 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -460,11 +460,20 @@ static size_t unit_as_string(char *str,
}
double value_conv = (value / unit->scalar) - unit->bias;
+ bool strip_skip = false;
+
+ /* Negative precision is used to disable stripping of zeroes.
+ * This reduces text jumping when changing values. */
+ if (prec < 0) {
+ strip_skip = true;
+ prec *= -1;
+ }
/* Adjust precision to expected number of significant digits.
* Note that here, we shall not have to worry about very big/small numbers, units are expected
* to replace 'scientific notation' in those cases. */
prec -= integer_digits_d(value_conv);
+
CLAMP(prec, 0, 6);
/* Convert to a string. */
@@ -478,12 +487,14 @@ static size_t unit_as_string(char *str,
size_t i = len - 1;
if (prec > 0) {
- while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */
- str[i--] = pad;
- }
+ if (!strip_skip) {
+ while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */
+ str[i--] = pad;
+ }
- if (i > 0 && str[i] == '.') { /* 10. -> 10 */
- str[i--] = pad;
+ if (i > 0 && str[i] == '.') { /* 10. -> 10 */
+ str[i--] = pad;
+ }
}
}
diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h
index 9bb7f3bfa8b..4a7fae6e98c 100644
--- a/source/blender/blenlib/BLI_assert.h
+++ b/source/blender/blenlib/BLI_assert.h
@@ -73,7 +73,7 @@ void _BLI_assert_unreachable_print(const char *file, int line, const char *funct
# define BLI_STATIC_ASSERT(a, msg) _STATIC_ASSERT(a);
# endif
#elif defined(__COVERITY__)
-/* Workaround error with coverity */
+/* Workaround error with COVERITY. */
# define BLI_STATIC_ASSERT(a, msg)
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
/* C11 */
diff --git a/source/blender/blenlib/BLI_bounds.hh b/source/blender/blenlib/BLI_bounds.hh
index d20382ed500..f5a18a0ea48 100644
--- a/source/blender/blenlib/BLI_bounds.hh
+++ b/source/blender/blenlib/BLI_bounds.hh
@@ -28,10 +28,11 @@ template<typename T> static std::optional<MinMaxResult<T>> min_max(Span<T> value
if (values.is_empty()) {
return std::nullopt;
}
+ const MinMaxResult<T> init{values.first(), values.first()};
return threading::parallel_reduce(
values.index_range(),
1024,
- MinMaxResult<T>(),
+ init,
[&](IndexRange range, const MinMaxResult<T> &init) {
MinMaxResult<T> result = init;
for (const int i : range) {
@@ -55,10 +56,11 @@ static std::optional<MinMaxResult<T>> min_max_with_radii(Span<T> values, Span<Ra
if (values.is_empty()) {
return std::nullopt;
}
+ const MinMaxResult<T> init{values.first(), values.first()};
return threading::parallel_reduce(
values.index_range(),
1024,
- MinMaxResult<T>(),
+ init,
[&](IndexRange range, const MinMaxResult<T> &init) {
MinMaxResult<T> result = init;
for (const int i : range) {
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 7f90ec20b66..8743b135dff 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -562,7 +562,7 @@ bool BLI_ghashutil_ptrcmp(const void *a, const void *b);
/**
* This function implements the widely used `djb` hash apparently posted
- * by Daniel Bernstein to `comp.lang.c` some time ago. The 32 bit
+ * by Daniel Bernstein to `comp.lang.c` some time ago. The 32 bit
* unsigned hash value starts at 5381 and for each byte 'c' in the
* string, is updated: `hash = hash * 33 + c`.
* This function uses the signed value of each byte.
diff --git a/source/blender/blenlib/BLI_hash_tables.hh b/source/blender/blenlib/BLI_hash_tables.hh
index 334634613a2..156fe481828 100644
--- a/source/blender/blenlib/BLI_hash_tables.hh
+++ b/source/blender/blenlib/BLI_hash_tables.hh
@@ -209,11 +209,11 @@ template<typename Key, Key EmptyValue, Key RemovedValue> struct TemplatedKeyInfo
};
/**
- * 0xffff...ffff indicates an empty slot.
- * 0xffff...fffe indicates a removed slot.
+ * `0xffff...ffff` indicates an empty slot.
+ * `0xffff...fffe` indicates a removed slot.
*
* Those specific values are used, because with them a single comparison is enough to check whether
- * a slot is occupied. The keys 0x0000...0000 and 0x0000...0001 also satisfy this constraint.
+ * a slot is occupied. The keys `0x0000...0000` and `0x0000...0001` also satisfy this constraint.
* However, nullptr is much more likely to be used as valid key.
*/
template<typename Pointer> struct PointerKeyInfo {
diff --git a/source/blender/blenlib/BLI_index_mask.hh b/source/blender/blenlib/BLI_index_mask.hh
index b87ab0afc98..22bdf090181 100644
--- a/source/blender/blenlib/BLI_index_mask.hh
+++ b/source/blender/blenlib/BLI_index_mask.hh
@@ -278,7 +278,7 @@ class IndexMask {
* before each range in the return value starts.
*/
Vector<IndexRange> extract_ranges_invert(const IndexRange full_range,
- Vector<int64_t> *r_skip_amounts) const;
+ Vector<int64_t> *r_skip_amounts = nullptr) const;
};
} // namespace blender
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 64b820a22b0..6386a7f76f8 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -123,7 +123,7 @@ MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float c
* one of the primaries, it lies outside the color gamut
* accessible from the given triple of primaries. Desaturate
* it by adding white, equal quantities of R, G, and B, enough
- * to make RGB all positive. The function returns 1 if the
+ * to make RGB all positive. The function returns 1 if the
* components were modified, zero otherwise.
*/
int constrain_rgb(float *r, float *g, float *b);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 5c1b6c8d774..93b413ab755 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -136,7 +136,7 @@ bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2],
bool is_poly_convex_v2(const float verts[][2], unsigned int nr);
/**
* Check if either of the diagonals along this quad create flipped triangles
- * (normals pointing away from eachother).
+ * (normals pointing away from each other).
* - (1 << 0): (v1-v3) is flipped.
* - (1 << 1): (v2-v4) is flipped.
*/
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index edfe53bc938..2cd2a299d53 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -374,7 +374,7 @@ void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3]);
* A safe version of invert that uses valid axes, calculating the zero'd axis
* based on the non-zero ones.
*
- * This works well for transformation matrices, when a single axis is zerod.
+ * This works well for transformation matrices, when a single axis is zeroed.
*/
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4]);
diff --git a/source/blender/blenlib/BLI_math_vector.hh b/source/blender/blenlib/BLI_math_vector.hh
index 7983bbccb35..384c4b49070 100644
--- a/source/blender/blenlib/BLI_math_vector.hh
+++ b/source/blender/blenlib/BLI_math_vector.hh
@@ -159,6 +159,39 @@ inline T safe_mod(const vec_base<T, Size> &a, const T &b)
return result;
}
+/**
+ * Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a .
+ * In other words, it is equivalent to `divide_ceil(a, b) * b`.
+ * It is undefined if \a a is negative or \b b is not strictly positive.
+ */
+template<typename T, int Size, BLI_ENABLE_IF((is_math_integral_type<T>))>
+inline vec_base<T, Size> ceil_to_multiple(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
+{
+ vec_base<T, Size> result;
+ for (int i = 0; i < Size; i++) {
+ BLI_assert(a[i] >= 0);
+ BLI_assert(b[i] > 0);
+ result[i] = ((a[i] + b[i] - 1) / b[i]) * b[i];
+ }
+ return result;
+}
+
+/**
+ * Integer division that returns the ceiling, instead of flooring like normal C division.
+ * It is undefined if \a a is negative or \b b is not strictly positive.
+ */
+template<typename T, int Size, BLI_ENABLE_IF((is_math_integral_type<T>))>
+inline vec_base<T, Size> divide_ceil(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
+{
+ vec_base<T, Size> result;
+ for (int i = 0; i < Size; i++) {
+ BLI_assert(a[i] >= 0);
+ BLI_assert(b[i] > 0);
+ result[i] = (a[i] + b[i] - 1) / b[i];
+ }
+ return result;
+}
+
template<typename T, int Size>
inline void min_max(const vec_base<T, Size> &vector,
vec_base<T, Size> &min,
diff --git a/source/blender/blenlib/BLI_utildefines_iter.h b/source/blender/blenlib/BLI_utildefines_iter.h
index 870e90bd971..03dc775a66b 100644
--- a/source/blender/blenlib/BLI_utildefines_iter.h
+++ b/source/blender/blenlib/BLI_utildefines_iter.h
@@ -21,7 +21,7 @@
* (100, 3) -> [16, 49, 83]
* (100, 100) -> [0..99]
* </pre>
- * \note this is mainly useful for numbers that might not divide evenly into eachother.
+ * \note this is mainly useful for numbers that might not divide evenly into each other.
*/
#define BLI_FOREACH_SPARSE_RANGE(src, dst, i) \
for (int _src = (src), _src2 = _src * 2, _dst2 = (dst)*2, _error = _dst2 - _src, i = 0, _delta; \
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index ab4ca185ddb..8f228ea188e 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -1138,6 +1138,8 @@ template<typename T> class VArray_Span final : public Span<T> {
Array<T> owned_data_;
public:
+ VArray_Span() = default;
+
VArray_Span(VArray<T> varray) : Span<T>(), varray_(std::move(varray))
{
this->size_ = varray_.size();
@@ -1151,6 +1153,30 @@ template<typename T> class VArray_Span final : public Span<T> {
this->data_ = owned_data_.data();
}
}
+
+ VArray_Span(VArray_Span &&other)
+ : varray_(std::move(other.varray_)), owned_data_(std::move(other.owned_data_))
+ {
+ this->size_ = varray_.size();
+ if (varray_.is_span()) {
+ this->data_ = varray_.get_internal_span().data();
+ }
+ else {
+ this->data_ = owned_data_.data();
+ }
+ other.data_ = nullptr;
+ other.size_ = 0;
+ }
+
+ VArray_Span &operator=(VArray_Span &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ std::destroy_at(this);
+ new (this) VArray_Span(std::move(other));
+ return *this;
+ }
};
/**
diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc
index ece22bcf82e..db6cb0824dc 100644
--- a/source/blender/blenlib/intern/delaunay_2d.cc
+++ b/source/blender/blenlib/intern/delaunay_2d.cc
@@ -2637,6 +2637,7 @@ void prepare_cdt_for_output(CDT_state<T> *cdt_state, const CDT_output_type outpu
remove_faces_in_holes(cdt_state);
}
else if (output_type == CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES) {
+ remove_outer_edges_until_constraints(cdt_state);
remove_non_constraint_edges_leave_valid_bmesh(cdt_state);
remove_faces_in_holes(cdt_state);
}
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index 9da8c0a0941..d57f859eb1b 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -143,7 +143,7 @@ static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ct
(void)0
/* Before we start, one word to the strange constants. They are defined in RFC 1321 as:
- * T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+ * `T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64`
*/
/* Round 1. */
@@ -315,7 +315,7 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock)
break;
}
- /* Process buffer with BLOCKSIZE bytes. Note that BLOCKSIZE % 64 == 0. */
+ /* Process buffer with BLOCKSIZE bytes. Note that `BLOCKSIZE % 64 == 0`. */
md5_process_block(buffer, BLOCKSIZE, &ctx);
}
@@ -323,7 +323,7 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock)
* 'fillbuf' contains the needed bits. */
memcpy(&buffer[sum], fillbuf, 64);
- /* Compute amount of padding bytes needed. Alignment is done to (N + PAD) % 64 == 56.
+ /* Compute amount of padding bytes needed. Alignment is done to `(N + PAD) % 64 == 56`.
* There is always at least one byte padded, i.e. if the alignment is correctly aligned,
* 64 padding bytes are added.
*/
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index a983821f15e..4a213f5fe74 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -767,6 +767,20 @@ MALWAYS_INLINE __m128 _bli_math_fastpow24(const __m128 arg)
return _mm_mul_ps(x, _mm_mul_ps(x, x));
}
+MALWAYS_INLINE __m128 _bli_math_rsqrt(__m128 in)
+{
+ __m128 r = _mm_rsqrt_ps(in);
+ /* Only do additional Newton-Raphson iterations when using actual SSE
+ * code path. When we are emulating SSE on NEON via sse2neon, the
+ * additional NR iterations are already done inside _mm_rsqrt_ps
+ * emulation. */
+# if defined(__SSE2__)
+ r = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f), r),
+ _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(in, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+# endif
+ return r;
+}
+
/* Calculate powf(x, 1.0f / 2.4) */
MALWAYS_INLINE __m128 _bli_math_fastpow512(const __m128 arg)
{
@@ -776,14 +790,14 @@ MALWAYS_INLINE __m128 _bli_math_fastpow512(const __m128 arg)
*/
__m128 xf = _bli_math_fastpow(0x3f2aaaab, 0x5eb504f3, arg);
__m128 xover = _mm_mul_ps(arg, xf);
- __m128 xfm1 = _mm_rsqrt_ps(xf);
+ __m128 xfm1 = _bli_math_rsqrt(xf);
__m128 x2 = _mm_mul_ps(arg, arg);
__m128 xunder = _mm_mul_ps(x2, xfm1);
/* sqrt2 * over + 2 * sqrt2 * under */
__m128 xavg = _mm_mul_ps(_mm_set1_ps(1.0f / (3.0f * 0.629960524947437f) * 0.999852f),
_mm_add_ps(xover, xunder));
- xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg));
- xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg));
+ xavg = _mm_mul_ps(xavg, _bli_math_rsqrt(xavg));
+ xavg = _mm_mul_ps(xavg, _bli_math_rsqrt(xavg));
return xavg;
}
diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c
index 2352d687061..b5650410a70 100644
--- a/source/blender/blenlib/intern/math_solvers.c
+++ b/source/blender/blenlib/intern/math_solvers.c
@@ -99,8 +99,8 @@ bool BLI_tridiagonal_solve_cyclic(
/* Degenerate case that works but can be simplified. */
if (count == 2) {
- float a2[2] = {0, a[1] + c[1]};
- float c2[2] = {a[0] + c[0], 0};
+ const float a2[2] = {0, a[1] + c[1]};
+ const float c2[2] = {a[0] + c[0], 0};
return BLI_tridiagonal_solve(a2, b, c2, d, r_x, count);
}
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 94efb0dd9e7..0cbf62cce03 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -363,6 +363,10 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst_w,
int BLI_wcwidth(char32_t ucs)
{
+ /* Treat private use areas (icon fonts), symbols, and emoticons as double-width. */
+ if (ucs >= 0xf0000 || (ucs >= 0xe000 && ucs < 0xf8ff) || (ucs >= 0x1f300 && ucs < 0x1fbff)) {
+ return 2;
+ }
return mk_wcwidth(ucs);
}
diff --git a/source/blender/blenlib/tests/BLI_bounds_test.cc b/source/blender/blenlib/tests/BLI_bounds_test.cc
index 9c123d4705c..5aa4e710e90 100644
--- a/source/blender/blenlib/tests/BLI_bounds_test.cc
+++ b/source/blender/blenlib/tests/BLI_bounds_test.cc
@@ -33,6 +33,13 @@ TEST(bounds, MinMaxFloat)
EXPECT_EQ(result->max, 3.0f);
}
+TEST(bounds, MinGreaterThanZero)
+{
+ Array<float> data = {1.5f, 3.0f, 1.1f, 100.0f};
+ auto result = bounds::min_max(data.as_span());
+ EXPECT_GT(result->min, 1.0f);
+}
+
TEST(bounds, MinMaxRadii)
{
Array<int2> data = {int2(0, 1), int2(3, -1), int2(0, -2), int2(-1, 1)};
diff --git a/source/blender/blenlib/tests/BLI_math_color_test.cc b/source/blender/blenlib/tests/BLI_math_color_test.cc
index 7f2c0a3f1ca..4d928477870 100644
--- a/source/blender/blenlib/tests/BLI_math_color_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_color_test.cc
@@ -74,3 +74,71 @@ TEST(math_color, LinearRGBTosRGBRoundtrip)
EXPECT_NEAR(orig_linear_color, linear_color, 1e-5);
}
}
+
+TEST(math_color, linearrgb_to_srgb_v3_v3)
+{
+ float srgb_color[3];
+ {
+ const float kTolerance = 1.0e-8f;
+ const float linear_color[3] = {0.0023f, 0.0024f, 0.0025f};
+ linearrgb_to_srgb_v3_v3(srgb_color, linear_color);
+ EXPECT_NEAR(0.029716f, srgb_color[0], kTolerance);
+ EXPECT_NEAR(0.031008f, srgb_color[1], kTolerance);
+ EXPECT_NEAR(0.032300f, srgb_color[2], kTolerance);
+ }
+
+ {
+ /* SIMD implementation of linear->srgb for larger inputs
+ * is less accurate; use larger tolerance. */
+ const float kTolerance = 3.6e-5f;
+ const float linear_color[3] = {0.71f, 0.75f, 0.78f};
+ linearrgb_to_srgb_v3_v3(srgb_color, linear_color);
+ EXPECT_NEAR(0.859696f, srgb_color[0], kTolerance);
+ EXPECT_NEAR(0.880825f, srgb_color[1], kTolerance);
+ EXPECT_NEAR(0.896244f, srgb_color[2], kTolerance);
+ }
+
+ {
+ /* Not a common, but possible case: values beyond 1.0 range. */
+ const float kTolerance = 2.3e-4f;
+ const float linear_color[3] = {1.5f, 2.8f, 5.6f};
+ linearrgb_to_srgb_v3_v3(srgb_color, linear_color);
+ EXPECT_NEAR(1.19418f, srgb_color[0], kTolerance);
+ EXPECT_NEAR(1.56520f, srgb_color[1], kTolerance);
+ EXPECT_NEAR(2.10771f, srgb_color[2], kTolerance);
+ }
+}
+
+TEST(math_color, srgb_to_linearrgb_v3_v3)
+{
+ float linear_color[3];
+ {
+ const float kTolerance = 1.0e-8f;
+ const float srgb_color[3] = {0.0023f, 0.0024f, 0.0025f};
+ srgb_to_linearrgb_v3_v3(linear_color, srgb_color);
+ EXPECT_NEAR(0.000178019f, linear_color[0], kTolerance);
+ EXPECT_NEAR(0.000185759f, linear_color[1], kTolerance);
+ EXPECT_NEAR(0.000193498f, linear_color[2], kTolerance);
+ }
+
+ {
+ /* SIMD implementation of linear->srgb for larger inputs
+ * is less accurate; use larger tolerance. */
+ const float kTolerance = 1.5e-7f;
+ const float srgb_color[3] = {0.71f, 0.72f, 0.73f};
+ srgb_to_linearrgb_v3_v3(linear_color, srgb_color);
+ EXPECT_NEAR(0.4623615f, linear_color[0], kTolerance);
+ EXPECT_NEAR(0.4770000f, linear_color[1], kTolerance);
+ EXPECT_NEAR(0.4919052f, linear_color[2], kTolerance);
+ }
+
+ {
+ /* Not a common, but possible case: values beyond 1.0 range. */
+ const float kTolerance = 7.7e-6f;
+ const float srgb_color[3] = {1.1f, 2.5f, 5.6f};
+ srgb_to_linearrgb_v3_v3(linear_color, srgb_color);
+ EXPECT_NEAR(1.24277f, linear_color[0], kTolerance);
+ EXPECT_NEAR(8.35473f, linear_color[1], kTolerance);
+ EXPECT_NEAR(56.23833f, linear_color[2], kTolerance);
+ }
+}
diff --git a/source/blender/blenlib/tests/BLI_math_vector_test.cc b/source/blender/blenlib/tests/BLI_math_vector_test.cc
index 282be5f1963..5686be975b5 100644
--- a/source/blender/blenlib/tests/BLI_math_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_vector_test.cc
@@ -105,4 +105,24 @@ TEST(math_vector, InterpolateFloat)
EXPECT_FLOAT_EQ(result.z, 75.0f);
}
+TEST(math_vector, CeilToMultiple)
+{
+ const int3 a(21, 16, 0);
+ const int3 b(8, 16, 15);
+ const int3 result = math::ceil_to_multiple(a, b);
+ EXPECT_FLOAT_EQ(result.x, 24);
+ EXPECT_FLOAT_EQ(result.y, 16);
+ EXPECT_FLOAT_EQ(result.z, 0);
+}
+
+TEST(math_vector, DivideCeil)
+{
+ const int3 a(21, 16, 0);
+ const int3 b(8, 16, 15);
+ const int3 result = math::divide_ceil(a, b);
+ EXPECT_FLOAT_EQ(result.x, 3);
+ EXPECT_FLOAT_EQ(result.y, 1);
+ EXPECT_FLOAT_EQ(result.z, 0);
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index eeec55a7b06..e542bc46a28 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -1569,8 +1569,8 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
if (!MAIN_VERSION_ATLEAST(bmain, 281, 2)) {
/* Replace Multiply and Additive blend mode by Alpha Blend
- * now that we use dualsource blending. */
- /* We take care of doing only nodetrees that are always part of materials
+ * now that we use dual-source blending. */
+ /* We take care of doing only node-trees that are always part of materials
* with old blending modes. */
for (Material *ma = bmain->materials.first; ma; ma = ma->id.next) {
bNodeTree *ntree = ma->nodetree;
@@ -4102,7 +4102,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_DataTransfer) {
- /* Now datatransfer's mix factor is multiplied with weights when any,
+ /* Now data-transfer's mix factor is multiplied with weights when any,
* instead of being ignored,
* we need to take care of that to keep 'old' files compatible. */
DataTransferModifierData *dtmd = (DataTransferModifierData *)md;
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index cd56adfe60c..a15ddc75aa2 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1440,7 +1440,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
view_layer->eevee.render_passes &= ~EEVEE_RENDER_PASS_UNUSED_8;
}
- /* Rename Renderlayer Socket `VolumeScatterCol` to `VolumeDir` */
+ /* Rename Render-layer Socket `VolumeScatterCol` to `VolumeDir`. */
if (scene->nodetree) {
LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) {
if (node->type == CMP_NODE_R_LAYERS) {
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 98c860792b2..97b414d4b4a 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -25,6 +25,7 @@
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
+#include "DNA_curves_types.h"
#include "DNA_genfile.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_lineart_types.h"
@@ -1000,6 +1001,9 @@ static void do_version_subsurface_methods(bNode *node)
static void version_geometry_nodes_add_attribute_input_settings(NodesModifierData *nmd)
{
+ if (nmd->settings.properties == NULL) {
+ return;
+ }
/* Before versioning the properties, make sure it hasn't been done already. */
LISTBASE_FOREACH (const IDProperty *, property, &nmd->settings.properties->data.group) {
if (strstr(property->name, "_use_attribute") || strstr(property->name, "_attribute_name")) {
@@ -1371,6 +1375,250 @@ static void version_liboverride_rnacollections_insertion_animdata(ID *id)
}
}
+static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTree *ntree)
+{
+ /* 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;
+ }
+ }
+ }
+ }
+}
+
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
@@ -2777,260 +3025,9 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /**
- * Versioning code until next subversion bump goes here.
- *
- * \note Be sure to check when bumping the version:
- * - "versioning_userdef.c", #blo_do_versions_userdef
- * - "versioning_userdef.c", #do_versions_theme
- *
- * \note Keep this message at the bottom of the function.
- */
- {
- /* Keep this block, even when empty. */
-
- /* Replace legacy combine/separate color nodes */
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 1)) {
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;
- }
- }
- }
- }
+ versioning_replace_legacy_combined_and_separate_color_nodes(ntree);
}
FOREACH_NODETREE_END;
@@ -3062,5 +3059,41 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
SEQ_for_each_callback(&ed->seqbase, version_merge_still_offsets, NULL);
}
}
+
+ /* Use the curves type enum for the set spline type node, instead of a special one. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_CURVE_SPLINE_TYPE) {
+ NodeGeometryCurveSplineType *storage = (NodeGeometryCurveSplineType *)node->storage;
+ switch (storage->spline_type) {
+ case 0: /* GEO_NODE_SPLINE_TYPE_BEZIER */
+ storage->spline_type = CURVE_TYPE_BEZIER;
+ break;
+ case 1: /* GEO_NODE_SPLINE_TYPE_NURBS */
+ storage->spline_type = CURVE_TYPE_NURBS;
+ break;
+ case 2: /* GEO_NODE_SPLINE_TYPE_POLY */
+ storage->spline_type = CURVE_TYPE_POLY;
+ break;
+ }
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
}
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index b3f3b9cbf7d..40359500d3c 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -347,6 +347,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
*/
{
/* Keep this block, even when empty. */
+ btheme->tui.wcol_view_item = U_theme_default.tui.wcol_view_item;
}
#undef FROM_DEFAULT_V4_UCHAR
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 65c42545a77..68171f26a66 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -977,7 +977,7 @@ static void write_libraries(WriteData *wd, Main *main)
if (main->curlib->packedfile) {
BKE_packedfile_blend_write(&writer, main->curlib->packedfile);
if (wd->use_memfile == false) {
- CLOG_INFO(&LOG, 2, "Write packed .blend: %s\n", main->curlib->filepath);
+ CLOG_INFO(&LOG, 2, "Write packed .blend: %s", main->curlib->filepath);
}
}
@@ -990,7 +990,7 @@ static void write_libraries(WriteData *wd, Main *main)
if (!BKE_idtype_idcode_is_linkable(GS(id->name))) {
CLOG_ERROR(&LOG,
"Data-block '%s' from lib '%s' is not linkable, but is flagged as "
- "directly linked\n",
+ "directly linked",
id->name,
main->curlib->filepath_abs);
}
@@ -1498,7 +1498,7 @@ void BLO_write_struct_array_by_name(BlendWriter *writer,
{
int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
if (UNLIKELY(struct_id == -1)) {
- CLOG_ERROR(&LOG, "Can't find SDNA code <%s>\n", struct_name);
+ CLOG_ERROR(&LOG, "Can't find SDNA code <%s>", struct_name);
return;
}
BLO_write_struct_array_by_id(writer, struct_id, array_size, data_ptr);
@@ -1546,7 +1546,7 @@ void BLO_write_struct_list_by_name(BlendWriter *writer, const char *struct_name,
{
int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
if (UNLIKELY(struct_id == -1)) {
- CLOG_ERROR(&LOG, "Can't find SDNA code <%s>\n", struct_name);
+ CLOG_ERROR(&LOG, "Can't find SDNA code <%s>", struct_name);
return;
}
BLO_write_struct_list_by_id(writer, struct_id, list);
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index ebb0f604df7..129eba3de2f 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -28,13 +28,6 @@ const char *BLT_translate_do_iface(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_tooltip(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid);
-/**
- * Note that "lang" here is the _output_ display language. We used to restrict
- * IME for keyboard _input_ language because our multilingual font was only used
- * when some output languages were selected. That font is used all the time now.
- */
-bool BLT_lang_is_ime_supported(void);
-
/* The "translation-marker" macro. */
#define N_(msgid) msgid
#define CTX_N_(context, msgid) msgid
diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c
index b015057ad2d..cb04b3ac0dc 100644
--- a/source/blender/blentranslation/intern/blt_lang.c
+++ b/source/blender/blentranslation/intern/blt_lang.c
@@ -345,12 +345,3 @@ void BLT_lang_locale_explode(const char *locale,
MEM_freeN(_t);
}
}
-
-bool BLT_lang_is_ime_supported(void)
-{
-#ifdef WITH_INPUT_IME
- return true;
-#else
- return false;
-#endif
-}
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index ee8c22df630..4391a6a92d7 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -460,7 +460,7 @@ void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const boo
for (el_store = eloops->first; el_store; el_store = el_store->next) {
float len_sq;
if (use_normals) {
- /* scale the length by how close the loops are to pointing at eachother */
+ /* Scale the length by how close the loops are to pointing at each other. */
float dir[3];
sub_v3_v3v3(dir, co, el_store->co);
len_sq = normalize_v3(dir);
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 2f5827bdc4c..0c3db31dd1f 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -894,6 +894,27 @@ void BM_data_layer_free(BMesh *bm, CustomData *data, int type)
}
}
+bool BM_data_layer_free_named(BMesh *bm, CustomData *data, const char *name)
+{
+ CustomData olddata = *data;
+ olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
+
+ /* the pool is now owned by olddata and must not be shared */
+ data->pool = NULL;
+
+ const bool has_layer = CustomData_free_layer_named(data, name, 0);
+
+ if (has_layer) {
+ update_data_blocks(bm, &olddata, data);
+ }
+
+ if (olddata.layers) {
+ MEM_freeN(olddata.layers);
+ }
+
+ return has_layer;
+}
+
void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
{
CustomData olddata;
diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h
index a2f1dfc706d..2cf9dffceec 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -59,6 +59,10 @@ void BM_data_interp_face_vert_edge(
void BM_data_layer_add(BMesh *bm, CustomData *data, int type);
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name);
void BM_data_layer_free(BMesh *bm, CustomData *data, int type);
+/**
+ * Remove a named custom data layer, if it existed. Return true if the layer was removed.
+ */
+bool BM_data_layer_free_named(BMesh *bm, CustomData *data, const char *name);
void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n);
void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int dst_n);
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.h b/source/blender/compositor/operations/COM_TonemapOperation.h
index 84ee9c563fd..7868aa140dc 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.h
+++ b/source/blender/compositor/operations/COM_TonemapOperation.h
@@ -81,8 +81,8 @@ class TonemapOperation : public MultiThreadedOperation {
};
/**
- * \brief class of tonemap, implementing the photoreceptor tonemap
- * most parts have already been done in TonemapOperation
+ * \brief class of tone-map, implementing the photo-receptor tone-map
+ * most parts have already been done in #TonemapOperation.
* \ingroup operation
*/
diff --git a/source/blender/datatoc/datatoc_icon.py b/source/blender/datatoc/datatoc_icon.py
index cce464dbc41..7373df71318 100755
--- a/source/blender/datatoc/datatoc_icon.py
+++ b/source/blender/datatoc/datatoc_icon.py
@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
_IS_BIG_ENDIAN = (__import__("sys").byteorder != 'little')
diff --git a/source/blender/datatoc/datatoc_icon_split.py b/source/blender/datatoc/datatoc_icon_split.py
index fcfd63f8707..8edafeda328 100755
--- a/source/blender/datatoc/datatoc_icon_split.py
+++ b/source/blender/datatoc/datatoc_icon_split.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
This script dices up PNG into small files to store in version control.
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index d632c4e2f7e..8ba6c840a59 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -42,9 +42,7 @@ struct StackEntry {
struct CyclesSolverState {
CyclesSolverState(Depsgraph *graph)
- : graph(graph),
- traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack")),
- num_cycles(0)
+ : graph(graph), traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack"))
{
/* pass */
}
@@ -57,7 +55,7 @@ struct CyclesSolverState {
}
Depsgraph *graph;
BLI_Stack *traversal_stack;
- int num_cycles;
+ int num_cycles = 0;
};
inline void set_node_visited_state(Node *node, eCyclicCheckVisitedState state)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index ae159373efd..c13c6d2f870 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -1137,6 +1137,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
/* Add dependencies for each constraint in turn. */
for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {nullptr, nullptr};
/* Invalid constraint type. */
if (cti == nullptr) {
continue;
@@ -1188,9 +1189,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
add_relation(cache_key, constraint_op_key, cti->name);
}
}
- else if (cti->get_constraint_targets) {
- ListBase targets = {nullptr, nullptr};
- cti->get_constraint_targets(con, &targets);
+ else if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == nullptr) {
continue;
@@ -1300,9 +1299,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
add_relation(target_transform_key, constraint_op_key, cti->name);
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, true);
- }
+ BKE_constraint_targets_flush(con, &targets, true);
}
}
}
@@ -1714,6 +1711,37 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
}
add_relation(variable_exit_key, driver_key, "RNA Target -> Driver");
+ /* It is possible that RNA path points to a property of a different ID than the target_id:
+ * for example, paths like "data" on Object, "camera" on Scene.
+ *
+ * For the demonstration purposes lets consider a driver variable uses Scene ID as target
+ * and "camera.location.x" as its RNA path. If the scene has 2 different cameras at
+ * 2 different locations changing the active scene camera is expected to immediately be
+ * reflected in the variable value. In order to achieve this behavior we create a relation
+ * from the target ID to the driver so that if the ID property of the target ID changes the
+ * driver is re-evaluated.
+ *
+ * The most straightforward (at the moment of writing this comment) way of figuring out
+ * such relation is to use copy-on-write operation of the target ID. There are two down
+ * sides of this approach which are considered a design limitation as there is a belief
+ * that they are not common in practice or are not reliable due to other issues:
+ *
+ * - IDs which are not covered with the copy-on-write mechanism.
+ *
+ * Such IDs are either do not have ID properties, or are not part of the dependency
+ * graph.
+ *
+ * - Modifications of evaluated IDs from a Python handler.
+ * Such modifications are not fully integrated in the dependency graph evaluation as it
+ * has issues with copy-on-write tagging and the fact that relations are defined by the
+ * original main database status. */
+ if (target_id != variable_exit_key.ptr.owner_id) {
+ if (deg_copy_on_write_is_needed(GS(target_id->name))) {
+ ComponentKey target_id_key(target_id, NodeType::COPY_ON_WRITE);
+ add_relation(target_id_key, driver_key, "Target ID -> Driver");
+ }
+ }
+
/* The RNA getter for `object.data` can write to the mesh datablock due
* to the call to `BKE_mesh_wrapper_ensure_subdivision()`. This relation
* ensures it is safe to call when the driver is evaluated.
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index d2a89576022..9cb3743dd02 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -39,8 +39,8 @@ set(INC
set(SRC
intern/draw_cache.c
intern/draw_cache_extract_mesh.cc
- intern/draw_cache_extract_mesh_render_data.c
- intern/mesh_extractors/extract_mesh.c
+ intern/draw_cache_extract_mesh_render_data.cc
+ intern/mesh_extractors/extract_mesh.cc
intern/mesh_extractors/extract_mesh_ibo_edituv.cc
intern/mesh_extractors/extract_mesh_ibo_fdots.cc
intern/mesh_extractors/extract_mesh_ibo_lines.cc
@@ -75,7 +75,7 @@ set(SRC
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_gpencil.c
intern/draw_cache_impl_lattice.c
- intern/draw_cache_impl_mesh.c
+ intern/draw_cache_impl_mesh.cc
intern/draw_cache_impl_metaball.c
intern/draw_cache_impl_particles.c
intern/draw_cache_impl_pointcloud.c
@@ -201,7 +201,7 @@ set(SRC
intern/DRW_render.h
intern/draw_attributes.h
intern/draw_cache.h
- intern/draw_cache_extract.h
+ intern/draw_cache_extract.hh
intern/draw_cache_impl.h
intern/draw_cache_inline.h
intern/draw_color_management.h
@@ -221,7 +221,7 @@ set(SRC
intern/draw_texture_pool.h
intern/draw_view.h
intern/draw_view_data.h
- intern/mesh_extractors/extract_mesh.h
+ intern/mesh_extractors/extract_mesh.hh
intern/smaa_textures.h
engines/basic/basic_engine.h
engines/basic/basic_private.h
@@ -452,108 +452,113 @@ set(GLSL_SRC
engines/select/shaders/select_id_vert.glsl
engines/select/shaders/select_id_frag.glsl
- engines/basic/shaders/conservative_depth_geom.glsl
- engines/basic/shaders/depth_vert.glsl
- engines/basic/shaders/depth_pointcloud_vert.glsl
- engines/basic/shaders/depth_frag.glsl
-
- engines/overlay/shaders/common_overlay_lib.glsl
- engines/overlay/shaders/antialiasing_frag.glsl
- engines/overlay/shaders/armature_dof_vert.glsl
- engines/overlay/shaders/armature_dof_solid_frag.glsl
- engines/overlay/shaders/armature_envelope_outline_vert.glsl
- engines/overlay/shaders/armature_envelope_solid_frag.glsl
- engines/overlay/shaders/armature_envelope_solid_vert.glsl
- engines/overlay/shaders/armature_shape_outline_geom.glsl
- engines/overlay/shaders/armature_shape_outline_vert.glsl
- engines/overlay/shaders/armature_shape_solid_frag.glsl
- engines/overlay/shaders/armature_shape_solid_vert.glsl
- engines/overlay/shaders/armature_shape_wire_vert.glsl
- engines/overlay/shaders/armature_sphere_outline_vert.glsl
- engines/overlay/shaders/armature_sphere_solid_frag.glsl
- engines/overlay/shaders/armature_sphere_solid_vert.glsl
- engines/overlay/shaders/armature_stick_frag.glsl
- engines/overlay/shaders/armature_stick_vert.glsl
- engines/overlay/shaders/armature_wire_frag.glsl
- engines/overlay/shaders/armature_wire_vert.glsl
- engines/overlay/shaders/background_frag.glsl
- engines/overlay/shaders/clipbound_vert.glsl
- engines/overlay/shaders/depth_only_vert.glsl
- engines/overlay/shaders/edit_curve_handle_geom.glsl
- engines/overlay/shaders/edit_curve_handle_vert.glsl
- engines/overlay/shaders/edit_curve_point_vert.glsl
- engines/overlay/shaders/edit_curve_wire_vert.glsl
- engines/overlay/shaders/edit_gpencil_canvas_vert.glsl
- engines/overlay/shaders/edit_gpencil_guide_vert.glsl
- engines/overlay/shaders/edit_gpencil_vert.glsl
- engines/overlay/shaders/edit_lattice_point_vert.glsl
- engines/overlay/shaders/edit_lattice_wire_vert.glsl
- engines/overlay/shaders/edit_mesh_common_lib.glsl
- engines/overlay/shaders/edit_mesh_frag.glsl
- engines/overlay/shaders/edit_mesh_geom.glsl
- engines/overlay/shaders/edit_mesh_normal_vert.glsl
- engines/overlay/shaders/edit_mesh_analysis_frag.glsl
- engines/overlay/shaders/edit_mesh_analysis_vert.glsl
- engines/overlay/shaders/edit_mesh_skin_root_vert.glsl
- engines/overlay/shaders/edit_mesh_vert.glsl
- engines/overlay/shaders/edit_particle_strand_vert.glsl
- engines/overlay/shaders/edit_particle_point_vert.glsl
- engines/overlay/shaders/edit_uv_edges_vert.glsl
- engines/overlay/shaders/edit_uv_edges_geom.glsl
- engines/overlay/shaders/edit_uv_edges_frag.glsl
- engines/overlay/shaders/edit_uv_verts_vert.glsl
- engines/overlay/shaders/edit_uv_verts_frag.glsl
- engines/overlay/shaders/edit_uv_faces_vert.glsl
- engines/overlay/shaders/edit_uv_face_dots_vert.glsl
- engines/overlay/shaders/edit_uv_image_vert.glsl
- engines/overlay/shaders/edit_uv_image_mask_frag.glsl
- engines/overlay/shaders/edit_uv_stretching_vert.glsl
- engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl
- engines/overlay/shaders/extra_frag.glsl
- engines/overlay/shaders/extra_vert.glsl
- engines/overlay/shaders/extra_groundline_vert.glsl
- engines/overlay/shaders/extra_lightprobe_grid_vert.glsl
- engines/overlay/shaders/extra_loose_point_frag.glsl
- engines/overlay/shaders/extra_loose_point_vert.glsl
- engines/overlay/shaders/extra_point_vert.glsl
- engines/overlay/shaders/extra_wire_frag.glsl
- engines/overlay/shaders/extra_wire_vert.glsl
- engines/overlay/shaders/facing_frag.glsl
- engines/overlay/shaders/facing_vert.glsl
- engines/overlay/shaders/grid_background_frag.glsl
- engines/overlay/shaders/grid_frag.glsl
- engines/overlay/shaders/grid_vert.glsl
- engines/overlay/shaders/image_vert.glsl
- engines/overlay/shaders/image_frag.glsl
- engines/overlay/shaders/motion_path_line_frag.glsl
- engines/overlay/shaders/motion_path_line_geom.glsl
- engines/overlay/shaders/motion_path_line_vert.glsl
- engines/overlay/shaders/motion_path_point_vert.glsl
- engines/overlay/shaders/outline_detect_frag.glsl
- engines/overlay/shaders/outline_prepass_frag.glsl
- engines/overlay/shaders/outline_prepass_gpencil_frag.glsl
- engines/overlay/shaders/outline_prepass_geom.glsl
- engines/overlay/shaders/outline_prepass_gpencil_vert.glsl
- engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl
- engines/overlay/shaders/outline_prepass_vert.glsl
- engines/overlay/shaders/paint_face_vert.glsl
- engines/overlay/shaders/paint_point_vert.glsl
- engines/overlay/shaders/paint_texture_frag.glsl
- engines/overlay/shaders/paint_texture_vert.glsl
- engines/overlay/shaders/paint_vertcol_frag.glsl
- engines/overlay/shaders/paint_vertcol_vert.glsl
- engines/overlay/shaders/paint_weight_frag.glsl
- engines/overlay/shaders/paint_weight_vert.glsl
- engines/overlay/shaders/paint_wire_vert.glsl
- engines/overlay/shaders/particle_vert.glsl
- engines/overlay/shaders/particle_frag.glsl
- engines/overlay/shaders/sculpt_mask_vert.glsl
- engines/overlay/shaders/sculpt_mask_frag.glsl
- engines/overlay/shaders/volume_velocity_vert.glsl
- engines/overlay/shaders/volume_gridlines_vert.glsl
- engines/overlay/shaders/wireframe_vert.glsl
- engines/overlay/shaders/wireframe_frag.glsl
- engines/overlay/shaders/xray_fade_frag.glsl
+ engines/basic/shaders/basic_conservative_depth_geom.glsl
+ engines/basic/shaders/basic_depth_vert.glsl
+ engines/basic/shaders/basic_depth_pointcloud_vert.glsl
+ engines/basic/shaders/basic_depth_frag.glsl
+
+ engines/overlay/shaders/overlay_antialiasing_frag.glsl
+ engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_dof_vert.glsl
+ engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl
+ engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl
+ engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl
+ engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl
+ engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl
+ engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl
+ engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl
+ engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl
+ engines/overlay/shaders/overlay_armature_stick_frag.glsl
+ engines/overlay/shaders/overlay_armature_stick_vert.glsl
+ engines/overlay/shaders/overlay_armature_wire_frag.glsl
+ engines/overlay/shaders/overlay_armature_wire_vert.glsl
+ engines/overlay/shaders/overlay_background_frag.glsl
+ engines/overlay/shaders/overlay_clipbound_vert.glsl
+ engines/overlay/shaders/overlay_common_lib.glsl
+ engines/overlay/shaders/overlay_depth_only_frag.glsl
+ engines/overlay/shaders/overlay_depth_only_vert.glsl
+ engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl
+ engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl
+ engines/overlay/shaders/overlay_edit_curve_point_vert.glsl
+ engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl
+ engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl
+ engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl
+ engines/overlay/shaders/overlay_edit_gpencil_vert.glsl
+ engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl
+ engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl
+ engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl
+ engines/overlay/shaders/overlay_edit_mesh_frag.glsl
+ engines/overlay/shaders/overlay_edit_mesh_geom.glsl
+ engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_vert.glsl
+ engines/overlay/shaders/overlay_edit_particle_point_vert.glsl
+ engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl
+ engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl
+ engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl
+ engines/overlay/shaders/overlay_edit_uv_image_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl
+ engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl
+ engines/overlay/shaders/overlay_extra_frag.glsl
+ engines/overlay/shaders/overlay_extra_groundline_vert.glsl
+ engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl
+ engines/overlay/shaders/overlay_extra_loose_point_frag.glsl
+ engines/overlay/shaders/overlay_extra_loose_point_vert.glsl
+ engines/overlay/shaders/overlay_extra_point_vert.glsl
+ engines/overlay/shaders/overlay_extra_vert.glsl
+ engines/overlay/shaders/overlay_extra_wire_frag.glsl
+ engines/overlay/shaders/overlay_extra_wire_vert.glsl
+ engines/overlay/shaders/overlay_facing_frag.glsl
+ engines/overlay/shaders/overlay_facing_vert.glsl
+ engines/overlay/shaders/overlay_grid_background_frag.glsl
+ engines/overlay/shaders/overlay_grid_frag.glsl
+ engines/overlay/shaders/overlay_grid_vert.glsl
+ engines/overlay/shaders/overlay_image_frag.glsl
+ engines/overlay/shaders/overlay_image_vert.glsl
+ engines/overlay/shaders/overlay_motion_path_line_frag.glsl
+ engines/overlay/shaders/overlay_motion_path_line_geom.glsl
+ engines/overlay/shaders/overlay_motion_path_line_vert.glsl
+ engines/overlay/shaders/overlay_motion_path_point_vert.glsl
+ engines/overlay/shaders/overlay_outline_detect_frag.glsl
+ engines/overlay/shaders/overlay_outline_prepass_frag.glsl
+ engines/overlay/shaders/overlay_outline_prepass_geom.glsl
+ engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl
+ engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
+ engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl
+ engines/overlay/shaders/overlay_outline_prepass_vert.glsl
+ engines/overlay/shaders/overlay_paint_face_vert.glsl
+ engines/overlay/shaders/overlay_paint_point_vert.glsl
+ engines/overlay/shaders/overlay_paint_texture_frag.glsl
+ engines/overlay/shaders/overlay_paint_texture_vert.glsl
+ engines/overlay/shaders/overlay_paint_vertcol_frag.glsl
+ engines/overlay/shaders/overlay_paint_vertcol_vert.glsl
+ engines/overlay/shaders/overlay_paint_weight_frag.glsl
+ engines/overlay/shaders/overlay_paint_weight_vert.glsl
+ engines/overlay/shaders/overlay_paint_wire_vert.glsl
+ engines/overlay/shaders/overlay_particle_frag.glsl
+ engines/overlay/shaders/overlay_particle_vert.glsl
+ engines/overlay/shaders/overlay_point_varying_color_frag.glsl
+ engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
+ engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
+ engines/overlay/shaders/overlay_sculpt_mask_vert.glsl
+ engines/overlay/shaders/overlay_uniform_color_frag.glsl
+ engines/overlay/shaders/overlay_varying_color.glsl
+ engines/overlay/shaders/overlay_volume_gridlines_vert.glsl
+ engines/overlay/shaders/overlay_volume_velocity_vert.glsl
+ engines/overlay/shaders/overlay_wireframe_frag.glsl
+ engines/overlay/shaders/overlay_wireframe_vert.glsl
+ engines/overlay/shaders/overlay_xray_fade_frag.glsl
engines/overlay/overlay_shader_shared.h
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 00822946fe5..dec7a22aadb 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -23,6 +23,9 @@ struct DrawEngineType;
struct GHash;
struct GPUMaterial;
struct GPUOffScreen;
+struct GPUVertFormat;
+struct CustomDataLayer;
+struct CustomData;
struct GPUViewport;
struct ID;
struct Main;
@@ -218,6 +221,12 @@ void DRW_opengl_context_activate(bool drw_state);
*/
void DRW_draw_cursor_2d_ex(const struct ARegion *region, const float cursor[2]);
+void DRW_cdlayer_attr_aliases_add(struct GPUVertFormat *format,
+ const char *base_name,
+ const struct CustomData *data,
+ const struct CustomDataLayer *cl,
+ bool is_active_render,
+ bool is_active_layer);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/engines/basic/basic_shader.c b/source/blender/draw/engines/basic/basic_shader.c
index d7a8f23e3b3..3d40c627fff 100644
--- a/source/blender/draw/engines/basic/basic_shader.c
+++ b/source/blender/draw/engines/basic/basic_shader.c
@@ -11,9 +11,9 @@
#include "basic_private.h"
-extern char datatoc_depth_frag_glsl[];
-extern char datatoc_depth_vert_glsl[];
-extern char datatoc_conservative_depth_geom_glsl[];
+extern char datatoc_basic_depth_frag_glsl[];
+extern char datatoc_basic_depth_vert_glsl[];
+extern char datatoc_basic_conservative_depth_geom_glsl[];
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_pointcloud_lib_glsl[];
diff --git a/source/blender/draw/engines/basic/shaders/conservative_depth_geom.glsl b/source/blender/draw/engines/basic/shaders/basic_conservative_depth_geom.glsl
index d478f37691e..d478f37691e 100644
--- a/source/blender/draw/engines/basic/shaders/conservative_depth_geom.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_conservative_depth_geom.glsl
diff --git a/source/blender/draw/engines/basic/shaders/depth_frag.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_frag.glsl
index ff4a015c335..ff4a015c335 100644
--- a/source/blender/draw/engines/basic/shaders/depth_frag.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_depth_frag.glsl
diff --git a/source/blender/draw/engines/basic/shaders/depth_pointcloud_vert.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_pointcloud_vert.glsl
index b82edc61cee..b82edc61cee 100644
--- a/source/blender/draw/engines/basic/shaders/depth_pointcloud_vert.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_depth_pointcloud_vert.glsl
diff --git a/source/blender/draw/engines/basic/shaders/depth_vert.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_vert.glsl
index 7046979cf97..7046979cf97 100644
--- a/source/blender/draw/engines/basic/shaders/depth_vert.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_depth_vert.glsl
diff --git a/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh b/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh
index 9914d264c63..bae50eb48fa 100644
--- a/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh
+++ b/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh
@@ -10,7 +10,7 @@
GPU_SHADER_CREATE_INFO(basic_conservative)
.geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3)
- .geometry_source("conservative_depth_geom.glsl");
+ .geometry_source("basic_conservative_depth_geom.glsl");
/** \} */
@@ -20,11 +20,11 @@ GPU_SHADER_CREATE_INFO(basic_conservative)
GPU_SHADER_CREATE_INFO(basic_mesh)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("depth_vert.glsl")
+ .vertex_source("basic_depth_vert.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(basic_pointcloud)
- .vertex_source("depth_pointcloud_vert.glsl")
+ .vertex_source("basic_depth_pointcloud_vert.glsl")
.additional_info("draw_pointcloud");
/** \} */
@@ -54,7 +54,7 @@ GPU_SHADER_CREATE_INFO(basic_pointcloud)
/** \name Depth shader types.
* \{ */
-GPU_SHADER_CREATE_INFO(basic_depth).fragment_source("depth_frag.glsl");
+GPU_SHADER_CREATE_INFO(basic_depth).fragment_source("basic_depth_frag.glsl");
BASIC_OBTYPE_VARIATIONS(basic_depth, "basic_depth");
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index a978d6fe75e..ad218d80cdf 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -682,7 +682,7 @@ typedef struct EEVEE_GeometryMotionData {
/** To disable deform mb if vertcount mismatch. */
int use_deform;
- /* The batch and vbos are not owned. */
+ /* The batch and VBOs are not owned. */
struct GPUBatch *batch; /* Batch for time = t. */
struct GPUVertBuf *vbo[2]; /* VBO for time = t +/- step. */
} EEVEE_GeometryMotionData;
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index 6fd5d97089d..5709621fc05 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -718,7 +718,7 @@ GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair)
if (e_data.cryptomatte_sh[index] == NULL) {
DynStr *ds = BLI_dynstr_new();
BLI_dynstr_append(ds, SHADER_DEFINES);
- BLI_dynstr_append(ds, "#define attrib_load(a) \n");
+ BLI_dynstr_append(ds, "#define attrib_load() \n");
if (is_hair) {
BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
index 186f438b03b..b3b9c7af19c 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
@@ -77,3 +77,13 @@ vec3 coordinate_incoming(vec3 P)
{
return vec3(0.0);
}
+
+float attr_load_temperature_post(float attr)
+{
+ return attr;
+}
+
+vec4 attr_load_color_post(vec4 attr)
+{
+ return attr;
+}
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 1261c855a82..eb409f076f3 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
@@ -126,7 +126,7 @@ BLI_STATIC_ASSERT_ALIGN(VelocityGeometryIndex, 16)
* \{ */
enum eClosureBits : uint32_t {
- /** NOTE: Theses are used as stencil bits. So we are limited to 8bits. */
+ /** NOTE: These are used as stencil bits. So we are limited to 8bits. */
CLOSURE_DIFFUSE = (1u << 0u),
CLOSURE_SSS = (1u << 1u),
CLOSURE_REFLECTION = (1u << 2u),
diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.hh b/source/blender/draw/engines/eevee_next/eevee_velocity.hh
index 1bfd9f8c18f..e2606c061e1 100644
--- a/source/blender/draw/engines/eevee_next/eevee_velocity.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_velocity.hh
@@ -111,7 +111,7 @@ class VelocityModule {
void step_sync(eVelocityStep step, float time);
/* Gather motion data. Returns true if the object **can** have motion. */
- bool step_object_sync(Object *ob, ObjectKey &ob_key, int recalc = 0);
+ bool step_object_sync(Object *ob, ObjectKey &object_key, int recalc = 0);
/* Moves next frame data to previous frame data. Nullify next frame data. */
void step_swap();
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh
index 95ec1760c63..fb74412f557 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_view.hh
@@ -41,7 +41,7 @@ class ShadingView {
/** Matrix to apply to the viewmat. */
const float (*face_matrix_)[4];
- /** Post-fx modules. */
+ /** Post-FX modules. */
// DepthOfField dof_;
// MotionBlur mb_;
VelocityView velocity_;
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
index 1b113e529b6..a65bb7decb6 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
@@ -132,7 +132,9 @@ int curves_attribute_element_id()
{
int id = interp.curves_strand_id;
if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+# ifdef COMMON_HAIR_LIB
id = hair_get_base_id();
+# endif
}
g_curves_attr_id += 1;
@@ -285,7 +287,7 @@ vec3 attr_load_uv(vec3 attr)
/** \name Volume Attribute post
*
* TODO(@fclem): These implementation details should concern the DRWManager and not be a fix on
- * the engine side. But as of now, the engines are reponsible for loading the attributes.
+ * the engine side. But as of now, the engines are responsible for loading the attributes.
*
* \{ */
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
index 277b2e35d8b..0ccf06a9e14 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
@@ -29,7 +29,7 @@ bool closure_select(float weight, inout float total_weight, inout float r)
float x = weight / total_weight;
bool chosen = (r < x);
/* Assuming that if r is in the interval [0,x] or [x,1], it's still uniformly distributed within
- * that interval, so you remaping to [0,1] again to explore this space of probability. */
+ * that interval, so you remapping to [0,1] again to explore this space of probability. */
r = (chosen) ? (r / x) : ((r - x) / (1.0 - x));
return chosen;
}
@@ -333,7 +333,7 @@ vec3 coordinate_screen(vec3 P)
window.xy = vec2(0.5);
}
else {
- /* TODO(fclem): Actual camera tranform. */
+ /* TODO(fclem): Actual camera transform. */
window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5;
window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw;
}
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 49250b5741e..a944bea402e 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
@@ -39,7 +39,10 @@ GPU_SHADER_CREATE_INFO(eevee_geom_curves)
.additional_info("eevee_shared")
.define("MAT_GEOM_CURVES")
.vertex_source("eevee_geom_curves_vert.glsl")
- .additional_info("draw_hair", "draw_resource_id_varying", "draw_resource_handle");
+ .additional_info("draw_hair",
+ "draw_curves_infos",
+ "draw_resource_id_varying",
+ "draw_resource_handle");
GPU_SHADER_CREATE_INFO(eevee_geom_world)
.additional_info("eevee_shared")
@@ -166,7 +169,7 @@ GPU_SHADER_CREATE_INFO(eevee_material_stub).define("EEVEE_MATERIAL_STUBS");
# define EEVEE_MAT_GEOM_VARIATIONS(prefix, ...) \
EEVEE_MAT_FINAL_VARIATION(prefix##_world, "eevee_geom_world", __VA_ARGS__) \
EEVEE_MAT_FINAL_VARIATION(prefix##_gpencil, "eevee_geom_gpencil", __VA_ARGS__) \
- EEVEE_MAT_FINAL_VARIATION(prefix##_hair, "eevee_geom_curves", __VA_ARGS__) \
+ EEVEE_MAT_FINAL_VARIATION(prefix##_curves, "eevee_geom_curves", __VA_ARGS__) \
EEVEE_MAT_FINAL_VARIATION(prefix##_mesh, "eevee_geom_mesh", __VA_ARGS__)
# define EEVEE_MAT_PIPE_VARIATIONS(name, ...) \
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index 9f2f2b4b23d..b9c09e2bc4f 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -36,8 +36,8 @@
#define EXTERNAL_ENGINE "BLENDER_EXTERNAL"
-extern char datatoc_depth_frag_glsl[];
-extern char datatoc_depth_vert_glsl[];
+extern char datatoc_basic_depth_frag_glsl[];
+extern char datatoc_basic_depth_vert_glsl[];
extern char datatoc_common_view_lib_glsl[];
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index 5d8ba06e181..f875254a685 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -1310,13 +1310,11 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
}
else {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ ListBase targets = {NULL, NULL};
- if ((cti && cti->get_constraint_targets) && (curcon->ui_expand_flag & (1 << 0))) {
- ListBase targets = {NULL, NULL};
+ if ((curcon->ui_expand_flag & (1 << 0)) && BKE_constraint_targets_get(curcon, &targets)) {
bConstraintTarget *ct;
- cti->get_constraint_targets(curcon, &targets);
-
for (ct = targets.first; ct; ct = ct->next) {
/* calculate target's matrix */
if (cti->get_target_matrix) {
@@ -1328,9 +1326,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->obmat[3], constraint_color);
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(curcon, &targets, 1);
- }
+ BKE_constraint_targets_flush(curcon, &targets, 1);
}
}
}
diff --git a/source/blender/draw/engines/overlay/shaders/infos/antialiasing_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh
index fe67dd473b7..0dba8b54e35 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/antialiasing_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh
@@ -9,7 +9,7 @@ GPU_SHADER_CREATE_INFO(overlay_antialiasing)
.sampler(2, ImageType::FLOAT_2D, "lineTex")
.push_constant(Type::BOOL, "doSmoothLines")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("antialiasing_frag.glsl")
+ .fragment_source("overlay_antialiasing_frag.glsl")
.additional_info("draw_fullscreen", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_xray_fade)
@@ -18,5 +18,5 @@ GPU_SHADER_CREATE_INFO(overlay_xray_fade)
.sampler(1, ImageType::DEPTH_2D, "xrayDepthTex")
.push_constant(Type::FLOAT, "opacity")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("xray_fade_frag.glsl")
+ .fragment_source("overlay_xray_fade_frag.glsl")
.additional_info("draw_fullscreen");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/armature_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh
index d89272a50cf..9f2acceed97 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/armature_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh
@@ -25,8 +25,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_sphere_outline)
/* Per instance. */
.vertex_in(1, Type::MAT4, "inst_obmat")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_sphere_outline_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_sphere_outline_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_sphere_outline_clipped)
@@ -47,8 +47,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_sphere_solid)
.vertex_in(2, Type::MAT4, "inst_obmat")
// .depth_layout(DepthLayout::GREATER) /* TODO */
.vertex_out(overlay_armature_sphere_solid_iface)
- .vertex_source("armature_sphere_solid_vert.glsl")
- .fragment_source("armature_sphere_solid_frag.glsl")
+ .vertex_source("overlay_armature_sphere_solid_vert.glsl")
+ .fragment_source("overlay_armature_sphere_solid_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_sphere_solid_clipped)
@@ -79,9 +79,9 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_outline)
.vertex_out(overlay_armature_shape_outline_iface)
.geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::LINE_STRIP, 2)
.geometry_out(overlay_armature_wire_iface)
- .vertex_source("armature_shape_outline_vert.glsl")
- .geometry_source("armature_shape_outline_geom.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_shape_outline_vert.glsl")
+ .geometry_source("overlay_armature_shape_outline_geom.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_shape_outline_clipped)
@@ -100,8 +100,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_solid)
.vertex_in(2, Type::MAT4, "inst_obmat")
.depth_write(DepthWrite::GREATER)
.vertex_out(overlay_armature_shape_solid_iface)
- .vertex_source("armature_shape_solid_vert.glsl")
- .fragment_source("armature_shape_solid_frag.glsl")
+ .vertex_source("overlay_armature_shape_solid_vert.glsl")
+ .fragment_source("overlay_armature_shape_solid_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_shape_solid_clipped)
@@ -115,8 +115,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_wire)
/* Per instance. */
.vertex_in(2, Type::MAT4, "inst_obmat")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_shape_wire_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_shape_wire_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_shape_wire_clipped)
@@ -140,8 +140,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_envelope_outline)
.vertex_in(5, Type::VEC4, "outlineColorSize")
.vertex_in(6, Type::VEC3, "xAxis")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_envelope_outline_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_envelope_outline_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_envelope_outline_clipped)
@@ -164,8 +164,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_envelope_solid)
.vertex_in(5, Type::VEC3, "boneColor")
.vertex_out(overlay_armature_envelope_solid_iface)
.push_constant(Type::BOOL, "isDistance")
- .vertex_source("armature_envelope_solid_vert.glsl")
- .fragment_source("armature_envelope_solid_frag.glsl")
+ .vertex_source("overlay_armature_envelope_solid_vert.glsl")
+ .fragment_source("overlay_armature_envelope_solid_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common");
GPU_SHADER_CREATE_INFO(overlay_armature_envelope_solid_clipped)
@@ -198,8 +198,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_stick)
.vertex_in(7, Type::VEC4, "tailColor")
.define("do_wire", "(wireColor.a > 0.0)")
.vertex_out(overlay_armature_stick_iface)
- .vertex_source("armature_stick_vert.glsl")
- .fragment_source("armature_stick_frag.glsl")
+ .vertex_source("overlay_armature_stick_vert.glsl")
+ .fragment_source("overlay_armature_stick_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_stick_clipped)
@@ -218,12 +218,12 @@ GPU_SHADER_CREATE_INFO(overlay_armature_dof)
.vertex_in(1, Type::VEC4, "color")
.vertex_in(2, Type::MAT4, "inst_obmat")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_dof_vert.glsl")
+ .vertex_source("overlay_armature_dof_vert.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire)
.do_static_compilation(true)
- .fragment_source("armature_dof_solid_frag.glsl")
+ .fragment_source("overlay_armature_dof_solid_frag.glsl")
.additional_info("overlay_armature_dof");
GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire_clipped)
@@ -232,7 +232,7 @@ GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire_clipped)
GPU_SHADER_CREATE_INFO(overlay_armature_dof_solid)
.do_static_compilation(true)
- .fragment_source("armature_dof_solid_frag.glsl")
+ .fragment_source("overlay_armature_dof_solid_frag.glsl")
.additional_info("overlay_armature_dof");
GPU_SHADER_CREATE_INFO(overlay_armature_dof_solid_clipped)
@@ -251,8 +251,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_wire)
.vertex_in(1, Type::VEC4, "color")
.push_constant(Type::FLOAT, "alpha")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_wire_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_wire_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_wire_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/background_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_background_info.hh
index c96d302d861..88a012c35c9 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/background_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_background_info.hh
@@ -9,17 +9,15 @@ GPU_SHADER_CREATE_INFO(overlay_background)
.sampler(1, ImageType::DEPTH_2D, "depthBuffer")
.push_constant(Type::INT, "bgType")
.push_constant(Type::VEC4, "colorOverride")
- .fragment_source("background_frag.glsl")
+ .fragment_source("overlay_background_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.additional_info("draw_fullscreen", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_clipbound)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.push_constant(Type::VEC4, "color")
.push_constant(Type::VEC3, "boundbox", 8)
- .vertex_source("clipbound_vert.glsl")
+ .vertex_source("overlay_clipbound_vert.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_view");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/edit_mode_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
index e6f15046838..58f96110887 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/edit_mode_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
@@ -19,7 +19,7 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_common)
.push_constant(Type::BOOL, "selectEdges")
.push_constant(Type::FLOAT, "alpha")
.push_constant(Type::IVEC4, "dataMask")
- .vertex_source("edit_mesh_vert.glsl")
+ .vertex_source("overlay_edit_mesh_vert.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_vert_iface, "")
@@ -29,13 +29,12 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_vert_iface, "")
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_vert)
.do_static_compilation(true)
.builtins(BuiltinBits::POINT_SIZE)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.define("VERT")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::IVEC4, "data")
.vertex_in(2, Type::VEC3, "vnor")
.vertex_out(overlay_edit_mesh_vert_iface)
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_edge_iface, "geometry_in")
@@ -58,8 +57,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge)
.vertex_out(overlay_edit_mesh_edge_iface)
.geometry_out(overlay_edit_mesh_edge_geom_iface)
.geometry_layout(PrimitiveIn::LINES, PrimitiveOut::TRIANGLE_STRIP, 4)
- .geometry_source("edit_mesh_geom.glsl")
- .fragment_source("edit_mesh_frag.glsl")
+ .geometry_source("overlay_edit_mesh_geom.glsl")
+ .fragment_source("overlay_edit_mesh_frag.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge_flat)
@@ -69,13 +68,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge_flat)
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_face)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.define("FACE")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::IVEC4, "data")
.vertex_in(2, Type::VEC3, "vnor")
.vertex_out(overlay_edit_flat_color_iface)
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_facedot)
@@ -86,12 +84,11 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_facedot)
.vertex_in(2, Type::VEC4, "norAndFlag")
.define("vnor", "norAndFlag.xyz")
.vertex_out(overlay_edit_flat_color_iface)
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_normal)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC4, "lnor")
.vertex_in(2, Type::VEC4, "vnor")
@@ -103,8 +100,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_normal)
.push_constant(Type::BOOL, "isConstantScreenSizeNormals")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_mesh_normal_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_mesh_normal_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat_instanced_attr", "draw_globals");
GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_analysis_iface, "").smooth(Type::VEC4, "weightColor");
@@ -116,20 +113,19 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_analysis)
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.fragment_out(0, Type::VEC4, "fragColor")
.vertex_out(overlay_edit_mesh_analysis_iface)
- .vertex_source("edit_mesh_analysis_vert.glsl")
- .fragment_source("edit_mesh_analysis_frag.glsl")
+ .vertex_source("overlay_edit_mesh_analysis_vert.glsl")
+ .fragment_source("overlay_edit_mesh_analysis_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_skin_root)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "size")
.vertex_in(2, Type::VEC3, "local_pos")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_mesh_skin_root_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_mesh_skin_root_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat_instanced_attr", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_vert_clipped)
@@ -193,9 +189,9 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges)
.push_constant(Type::FLOAT, "alpha")
.push_constant(Type::FLOAT, "dashLength")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_edges_vert.glsl")
- .geometry_source("edit_uv_edges_geom.glsl")
- .fragment_source("edit_uv_edges_frag.glsl")
+ .vertex_source("overlay_edit_uv_edges_vert.glsl")
+ .geometry_source("overlay_edit_uv_edges_geom.glsl")
+ .fragment_source("overlay_edit_uv_edges_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges_select)
@@ -205,28 +201,24 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges_select)
GPU_SHADER_CREATE_INFO(overlay_edit_uv_faces)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "au")
.vertex_in(1, Type::INT, "flag")
.push_constant(Type::FLOAT, "uvOpacity")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_faces_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_faces_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_face_dots)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "au")
.vertex_in(1, Type::INT, "flag")
.push_constant(Type::FLOAT, "pointSize")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_face_dots_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_face_dots_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_INTERFACE_INFO(overlay_edit_uv_vert_iface, "")
@@ -236,8 +228,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_uv_vert_iface, "")
GPU_SHADER_CREATE_INFO(overlay_edit_uv_verts)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "au")
.vertex_in(1, Type::INT, "flag")
.push_constant(Type::FLOAT, "pointSize")
@@ -245,19 +235,17 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_verts)
.push_constant(Type::VEC4, "color")
.vertex_out(overlay_edit_uv_vert_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_verts_vert.glsl")
- .fragment_source("edit_uv_verts_frag.glsl")
+ .vertex_source("overlay_edit_uv_verts_vert.glsl")
+ .fragment_source("overlay_edit_uv_verts_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_tiled_image_borders)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_tiled_image_borders_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_INTERFACE_INFO(edit_uv_image_iface, "").smooth(Type::VEC2, "uvs");
@@ -266,13 +254,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_stencil_image)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
.vertex_out(edit_uv_image_iface)
- .vertex_source("edit_uv_image_vert.glsl")
+ .vertex_source("overlay_edit_uv_image_vert.glsl")
.sampler(0, ImageType::FLOAT_2D, "imgTexture")
.push_constant(Type::BOOL, "imgPremultiplied")
.push_constant(Type::BOOL, "imgAlphaBlend")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("image_frag.glsl")
+ .fragment_source("overlay_image_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image)
@@ -282,8 +270,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image)
.sampler(0, ImageType::FLOAT_2D, "imgTexture")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_image_vert.glsl")
- .fragment_source("edit_uv_image_mask_frag.glsl")
+ .vertex_source("overlay_edit_uv_image_vert.glsl")
+ .fragment_source("overlay_edit_uv_image_mask_frag.glsl")
.additional_info("draw_mesh");
/** \} */
@@ -293,14 +281,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image)
* \{ */
GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "pos")
.push_constant(Type::VEC2, "aspect")
.vertex_out(overlay_edit_nopersp_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_stretching_vert.glsl")
- .fragment_source("gpu_shader_2D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_stretching_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching_area)
@@ -328,8 +314,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type::IN
GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle)
.do_static_compilation(true)
.typedef_source("overlay_shader_shared.h")
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_curve_handle_iface)
@@ -338,9 +322,9 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle)
.push_constant(Type::BOOL, "showCurveHandles")
.push_constant(Type::INT, "curveHandleDisplay")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_curve_handle_vert.glsl")
- .geometry_source("edit_curve_handle_geom.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_curve_handle_vert.glsl")
+ .geometry_source("overlay_edit_curve_handle_geom.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle_clipped)
@@ -350,16 +334,14 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_curve_point)
.do_static_compilation(true)
.typedef_source("overlay_shader_shared.h")
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_flat_color_iface)
.push_constant(Type::BOOL, "showCurveHandles")
.push_constant(Type::INT, "curveHandleDisplay")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_curve_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_curve_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_curve_point_clipped)
@@ -368,8 +350,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC3, "nor")
.vertex_in(2, Type::VEC3, "tan")
@@ -377,8 +357,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire)
.push_constant(Type::FLOAT, "normalSize")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_curve_wire_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_curve_wire_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat", "draw_resource_id_uniform", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire_clipped)
@@ -393,14 +373,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_lattice_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_lattice_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point_clipped)
@@ -409,15 +387,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "weight")
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.vertex_out(overlay_edit_smooth_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_lattice_wire_vert.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_lattice_wire_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire_clipped)
@@ -432,16 +408,14 @@ GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "color")
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.push_constant(Type::BOOL, "useWeight")
.vertex_out(overlay_edit_smooth_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_particle_strand_vert.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_particle_strand_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand_clipped)
@@ -450,14 +424,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_particle_point)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "color")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_particle_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_particle_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_particle_point_clipped)
@@ -472,8 +444,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_particle_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil)
.typedef_source("overlay_shader_shared.h")
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "ma")
.vertex_in(2, Type::UINT, "vflag")
@@ -487,13 +457,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil)
.push_constant(Type::VEC4, "gpEditColor")
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_gpencil_vert.glsl")
+ .vertex_source("overlay_edit_gpencil_vert.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_wire)
.do_static_compilation(true)
.vertex_out(overlay_edit_smooth_color_iface)
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("overlay_edit_gpencil");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_wire_clipped)
@@ -504,7 +474,7 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point)
.do_static_compilation(true)
.define("USE_POINTS")
.vertex_out(overlay_edit_flat_color_iface)
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("overlay_edit_gpencil");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point_clipped)
@@ -514,8 +484,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point_clipped)
/* TODO(fclem): Refactor this to take list of point instead of drawing 1 point per drawcall. */
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_flat_color_iface)
@@ -523,8 +491,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point)
.push_constant(Type::FLOAT, "pSize")
.push_constant(Type::VEC4, "pColor")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_gpencil_guide_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_gpencil_guide_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point_clipped)
@@ -542,8 +510,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_depth_only)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("depth_only_vert.glsl")
- .fragment_source("gpu_shader_depth_only_frag.glsl")
+ .vertex_source("overlay_depth_only_vert.glsl")
+ .fragment_source("overlay_depth_only_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_depth_only_clipped)
@@ -558,13 +526,11 @@ GPU_SHADER_CREATE_INFO(overlay_depth_only_clipped)
GPU_SHADER_CREATE_INFO(overlay_uniform_color)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("depth_only_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_depth_only_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_uniform_color_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh
index b9b1b73dbd4..5b50bbcaa55 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh
@@ -21,8 +21,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra)
.vertex_out(overlay_extra_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_vert.glsl")
- .fragment_source("extra_frag.glsl")
+ .vertex_source("overlay_extra_vert.glsl")
+ .fragment_source("overlay_extra_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_select)
@@ -53,8 +53,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_grid)
.push_constant(Type::BOOL, "isTransform")
.vertex_out(overlay_extra_grid_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("extra_lightprobe_grid_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_extra_lightprobe_grid_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_grid_clipped)
@@ -75,8 +75,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_groundline)
.vertex_out(overlay_extra_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_groundline_vert.glsl")
- .fragment_source("extra_frag.glsl")
+ .vertex_source("overlay_extra_groundline_vert.glsl")
+ .fragment_source("overlay_extra_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_groundline_clipped)
@@ -103,8 +103,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_wire)
.vertex_out(overlay_extra_wire_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_wire_vert.glsl")
- .fragment_source("extra_wire_frag.glsl")
+ .vertex_source("overlay_extra_wire_vert.glsl")
+ .fragment_source("overlay_extra_wire_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_wire_select)
@@ -148,8 +148,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_point)
.push_constant(Type::VEC4, "color")
.vertex_out(overlay_extra_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("extra_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_varying_outline_aa_frag.glsl")
+ .vertex_source("overlay_extra_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_varying_outline_aa_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_point_clipped)
@@ -165,8 +165,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_loose_point)
.vertex_out(overlay_extra_loose_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_loose_point_vert.glsl")
- .fragment_source("extra_loose_point_frag.glsl")
+ .vertex_source("overlay_extra_loose_point_vert.glsl")
+ .fragment_source("overlay_extra_loose_point_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_loose_point_clipped)
@@ -194,9 +194,9 @@ GPU_SHADER_CREATE_INFO(overlay_motion_path_line)
.geometry_out(overlay_motion_path_line_iface)
.geometry_layout(PrimitiveIn::LINES, PrimitiveOut::TRIANGLE_STRIP, 4)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("motion_path_line_vert.glsl")
- .geometry_source("motion_path_line_geom.glsl")
- .fragment_source("motion_path_line_frag.glsl")
+ .vertex_source("overlay_motion_path_line_vert.glsl")
+ .geometry_source("overlay_motion_path_line_geom.glsl")
+ .fragment_source("overlay_motion_path_line_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_motion_path_line_clipped)
@@ -215,8 +215,8 @@ GPU_SHADER_CREATE_INFO(overlay_motion_path_point)
.push_constant(Type::VEC3, "customColor")
.vertex_out(overlay_motion_path_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("motion_path_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_motion_path_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_motion_path_point_clipped)
@@ -242,8 +242,8 @@ GPU_SHADER_CREATE_INFO(overlay_image)
.vertex_out(overlay_image_iface)
.sampler(0, ImageType::FLOAT_2D, "imgTexture")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("image_vert.glsl")
- .fragment_source("image_frag.glsl")
+ .vertex_source("overlay_image_vert.glsl")
+ .fragment_source("overlay_image_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_image_clipped)
@@ -266,8 +266,8 @@ GPU_SHADER_CREATE_INFO(overlay_gpencil_canvas)
.push_constant(Type::INT, "halfLineCount")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("edit_gpencil_canvas_vert.glsl")
- .fragment_source("extra_frag.glsl")
+ .vertex_source("overlay_edit_gpencil_canvas_vert.glsl")
+ .fragment_source("overlay_extra_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_gpencil_canvas_clipped)
@@ -289,7 +289,7 @@ GPU_SHADER_CREATE_INFO(overlay_particle)
.vertex_in(1, Type::VEC4, "part_rot")
.vertex_in(2, Type::FLOAT, "part_val")
.vertex_out(overlay_particle_iface)
- .vertex_source("particle_vert.glsl")
+ .vertex_source("overlay_particle_vert.glsl")
.additional_info("draw_globals");
GPU_SHADER_CREATE_INFO(overlay_particle_dot)
@@ -299,7 +299,7 @@ GPU_SHADER_CREATE_INFO(overlay_particle_dot)
.define("pos", "vec3(0.0)")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .fragment_source("particle_frag.glsl")
+ .fragment_source("overlay_particle_frag.glsl")
.additional_info("overlay_particle", "draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_particle_dot_clipped)
@@ -308,13 +308,11 @@ GPU_SHADER_CREATE_INFO(overlay_particle_dot_clipped)
GPU_SHADER_CREATE_INFO(overlay_particle_shape)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
/* Instantiated Attrs. */
.vertex_in(3, Type::VEC3, "pos")
.vertex_in(4, Type::INT, "vclass")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("overlay_particle", "draw_modelmat", "draw_resource_id_uniform");
GPU_SHADER_CREATE_INFO(overlay_particle_shape_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/facing_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_facing_info.hh
index 6d6806eaa80..6d528bbba62 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/facing_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_facing_info.hh
@@ -5,8 +5,8 @@
GPU_SHADER_CREATE_INFO(overlay_facing)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("facing_vert.glsl")
- .fragment_source("facing_frag.glsl")
+ .vertex_source("overlay_facing_vert.glsl")
+ .fragment_source("overlay_facing_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.additional_info("draw_mesh", "draw_globals");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/grid_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_grid_info.hh
index d02014c98a0..a8f1281d53a 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/grid_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_grid_info.hh
@@ -15,8 +15,8 @@ GPU_SHADER_CREATE_INFO(overlay_grid)
.uniform_buf(3, "OVERLAY_GridData", "grid_buf")
.push_constant(Type::VEC3, "plane_axes")
.push_constant(Type::INT, "grid_flag")
- .vertex_source("grid_vert.glsl")
- .fragment_source("grid_frag.glsl")
+ .vertex_source("overlay_grid_vert.glsl")
+ .fragment_source("overlay_grid_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_grid_background)
@@ -25,17 +25,15 @@ GPU_SHADER_CREATE_INFO(overlay_grid_background)
.sampler(0, ImageType::DEPTH_2D, "depthBuffer")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_tiled_image_borders_vert.glsl")
- .fragment_source("grid_background_frag.glsl")
+ .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl")
+ .fragment_source("overlay_grid_background_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_grid_image)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_tiled_image_borders_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_modelmat");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/outline_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh
index 21575747efa..6f6a9c1622d 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/outline_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh
@@ -13,13 +13,13 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass)
.vertex_out(overlay_outline_prepass_iface)
/* Using uint because 16bit uint can contain more ids than int. */
.fragment_out(0, Type::UINT, "out_object_id")
- .fragment_source("outline_prepass_frag.glsl")
+ .fragment_source("overlay_outline_prepass_frag.glsl")
.additional_info("draw_resource_handle");
GPU_SHADER_CREATE_INFO(overlay_outline_prepass_mesh)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("outline_prepass_vert.glsl")
+ .vertex_source("overlay_outline_prepass_vert.glsl")
.additional_info("draw_mesh", "overlay_outline_prepass")
.additional_info("draw_object_infos");
@@ -36,8 +36,8 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_wire)
.vertex_out(overlay_outline_prepass_wire_iface)
.geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::LINE_STRIP, 2)
.geometry_out(overlay_outline_prepass_iface)
- .vertex_source("outline_prepass_vert.glsl")
- .geometry_source("outline_prepass_geom.glsl")
+ .vertex_source("overlay_outline_prepass_vert.glsl")
+ .geometry_source("overlay_outline_prepass_geom.glsl")
.additional_info("draw_mesh", "overlay_outline_prepass")
.additional_info("draw_object_infos");
@@ -56,12 +56,12 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil)
.push_constant(Type::BOOL, "isTransform")
.vertex_out(overlay_outline_prepass_iface)
.vertex_out(overlay_outline_prepass_gpencil_iface)
- .vertex_source("outline_prepass_gpencil_vert.glsl")
+ .vertex_source("overlay_outline_prepass_gpencil_vert.glsl")
.push_constant(Type::BOOL, "gpStrokeOrder3d") /* TODO(fclem): Move to a GPencil object UBO. */
.push_constant(Type::VEC4, "gpDepthPlane") /* TODO(fclem): Move to a GPencil object UBO. */
/* Using uint because 16bit uint can contain more ids than int. */
.fragment_out(0, Type::UINT, "out_object_id")
- .fragment_source("outline_prepass_gpencil_frag.glsl")
+ .fragment_source("overlay_outline_prepass_gpencil_frag.glsl")
.additional_info("draw_gpencil", "draw_resource_handle");
GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil_clipped)
@@ -70,7 +70,7 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil_clipped)
GPU_SHADER_CREATE_INFO(overlay_outline_prepass_pointcloud)
.do_static_compilation(true)
- .vertex_source("outline_prepass_pointcloud_vert.glsl")
+ .vertex_source("overlay_outline_prepass_pointcloud_vert.glsl")
.additional_info("draw_pointcloud", "overlay_outline_prepass")
.additional_info("draw_object_infos");
@@ -95,7 +95,7 @@ GPU_SHADER_CREATE_INFO(overlay_outline_detect)
.sampler(2, ImageType::DEPTH_2D, "sceneDepth")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .fragment_source("outline_detect_frag.glsl")
+ .fragment_source("overlay_outline_detect_frag.glsl")
.additional_info("draw_fullscreen", "draw_view", "draw_globals");
/** \} */
diff --git a/source/blender/draw/engines/overlay/shaders/infos/paint_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_paint_info.hh
index bbec79d515f..3083d5a463b 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/paint_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_paint_info.hh
@@ -10,13 +10,12 @@
GPU_SHADER_CREATE_INFO(overlay_paint_face)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* NOTE: Color already in Linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC4, "nor") /* Select flag on the 4th component. */
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_face_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_paint_face_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_paint_face_clipped)
@@ -40,8 +39,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_point)
.vertex_in(1, Type::VEC4, "nor") /* Select flag on the 4th component. */
.vertex_out(overlay_overlay_paint_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_paint_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_paint_point_clipped)
@@ -70,8 +69,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_texture)
.push_constant(Type::BOOL, "maskInvertStencil")
.push_constant(Type::BOOL, "maskImagePremultiplied")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_texture_vert.glsl")
- .fragment_source("paint_texture_frag.glsl")
+ .vertex_source("overlay_paint_texture_vert.glsl")
+ .fragment_source("overlay_paint_texture_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_paint_texture_clipped)
@@ -97,8 +96,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_vertcol)
.push_constant(Type::FLOAT, "opacity") /* `1.0` by default. */
.push_constant(Type::BOOL, "useAlphaBlend") /* `false` by default. */
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_vertcol_vert.glsl")
- .fragment_source("paint_vertcol_frag.glsl")
+ .vertex_source("overlay_paint_vertcol_vert.glsl")
+ .fragment_source("overlay_paint_vertcol_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_paint_vertcol_clipped)
@@ -129,8 +128,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_weight)
.push_constant(Type::FLOAT, "opacity") /* `1.0` by default. */
.push_constant(Type::BOOL, "drawContours") /* `false` by default. */
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_weight_vert.glsl")
- .fragment_source("paint_weight_frag.glsl")
+ .vertex_source("overlay_paint_weight_vert.glsl")
+ .fragment_source("overlay_paint_weight_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_paint_weight_fake_shading)
@@ -162,14 +161,13 @@ GPU_SHADER_INTERFACE_INFO(overlay_paint_wire_iface, "").flat(Type::VEC4, "finalC
GPU_SHADER_CREATE_INFO(overlay_paint_wire)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* NOTE: Color already in Linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC4, "nor") /* flag stored in w */
.vertex_out(overlay_paint_wire_iface)
.push_constant(Type::BOOL, "useSelect")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_wire_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_paint_wire_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_paint_wire_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/sculpt_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh
index d4f1ca44362..3a53bd388a6 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/sculpt_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh
@@ -15,8 +15,8 @@ GPU_SHADER_CREATE_INFO(overlay_sculpt_mask)
.vertex_in(1, Type::VEC3, "fset")
.vertex_in(2, Type::FLOAT, "msk")
.vertex_out(overlay_sculpt_mask_iface)
- .vertex_source("sculpt_mask_vert.glsl")
- .fragment_source("sculpt_mask_frag.glsl")
+ .vertex_source("overlay_sculpt_mask_vert.glsl")
+ .fragment_source("overlay_sculpt_mask_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.additional_info("draw_mesh", "draw_object_infos", "draw_globals");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_volume_info.hh
index 5853e974eeb..3740b42ba26 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_volume_info.hh
@@ -10,8 +10,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_volume_velocity_iface, "").smooth(Type::VEC4,
GPU_SHADER_CREATE_INFO(overlay_volume_velocity)
.do_static_compilation(true)
- /* Colors are already in linear space. */
- .define("srgbTarget", "false")
.sampler(0, ImageType::FLOAT_3D, "velocityX")
.sampler(1, ImageType::FLOAT_3D, "velocityY")
.sampler(2, ImageType::FLOAT_3D, "velocityZ")
@@ -28,8 +26,8 @@ GPU_SHADER_CREATE_INFO(overlay_volume_velocity)
.push_constant(Type::IVEC3, "adaptiveCellOffset")
.vertex_out(overlay_volume_velocity_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("volume_velocity_vert.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_volume_velocity_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_volume");
GPU_SHADER_CREATE_INFO(overlay_volume_velocity_mac)
@@ -55,8 +53,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_volume_gridlines_iface, "").flat(Type::VEC4, "
GPU_SHADER_CREATE_INFO(overlay_volume_gridlines)
.do_static_compilation(true)
- /* Colors are already in linear space. */
- .define("srgbTarget", "false")
.push_constant(Type::FLOAT, "slicePosition")
.push_constant(Type::INT, "sliceAxis")
/* FluidDomainSettings.res */
@@ -69,8 +65,8 @@ GPU_SHADER_CREATE_INFO(overlay_volume_gridlines)
.push_constant(Type::IVEC3, "adaptiveCellOffset")
.vertex_out(overlay_volume_gridlines_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("volume_gridlines_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_volume_gridlines_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_volume");
GPU_SHADER_CREATE_INFO(overlay_volume_gridlines_flags)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh
index 16b59f6bb7d..1899b191741 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh
@@ -23,8 +23,8 @@ GPU_SHADER_CREATE_INFO(overlay_wireframe)
.vertex_in(1, Type::VEC3, "nor")
.vertex_in(2, Type::FLOAT, "wd") /* wire-data. */
.vertex_out(overlay_wireframe_iface)
- .vertex_source("wireframe_vert.glsl")
- .fragment_source("wireframe_frag.glsl")
+ .vertex_source("overlay_wireframe_vert.glsl")
+ .fragment_source("overlay_wireframe_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
.additional_info("draw_mesh", "draw_object_infos", "draw_globals");
diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl
index f28a809fdab..f28a809fdab 100644
--- a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl
index d46abbf79ee..d46abbf79ee 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_vert.glsl
index b3c9ce5dfd2..b3c9ce5dfd2 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl
index 0a8e279e9b0..0a8e279e9b0 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl
index a90d2e3e406..a90d2e3e406 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl
index 2dd86a57dfd..2dd86a57dfd 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl
index 47c5dada708..47c5dada708 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl
index 29319b3f7ac..29319b3f7ac 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl
index 8e1768846dc..8e1768846dc 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl
index cdbe8c3d7df..cdbe8c3d7df 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl
index cee86956c43..cee86956c43 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl
index 31369e0c3df..31369e0c3df 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl
index e60b6e94492..e60b6e94492 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl
index abbaad8cd10..abbaad8cd10 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_frag.glsl
index 2e42cdf0517..2e42cdf0517 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_vert.glsl
index b5edcd2858b..b5edcd2858b 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl
index 2c454a8becd..2c454a8becd 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_vert.glsl
index c89d0249e4f..c89d0249e4f 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/background_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_background_frag.glsl
index b25dcae9fca..b25dcae9fca 100644
--- a/source/blender/draw/engines/overlay/shaders/background_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_background_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_clipbound_vert.glsl
index c065a66414f..c065a66414f 100644
--- a/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_clipbound_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl b/source/blender/draw/engines/overlay/shaders/overlay_common_lib.glsl
index 65aeb81a4ef..65aeb81a4ef 100644
--- a/source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_common_lib.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl
new file mode 100644
index 00000000000..59efdd8d538
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl
@@ -0,0 +1,6 @@
+
+void main()
+{
+ /* No color output, only depth (line below is implicit). */
+ // gl_FragDepth = gl_FragCoord.z;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl
index d403890f44e..d403890f44e 100644
--- a/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl
index 7d92baea595..7d92baea595 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl
index 186cc010f45..186cc010f45 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_point_vert.glsl
index a30496177c3..a30496177c3 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl
index 183df7e5450..183df7e5450 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl
index 47d9439ed80..47d9439ed80 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl
index a5091345539..a5091345539 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_vert.glsl
index f5d6e89d016..f5d6e89d016 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl
index 38ba80a981a..38ba80a981a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl
index 440dfdc1482..440dfdc1482 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl
index 430ace8726a..430ace8726a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl
index 1e163dc9a9a..1e163dc9a9a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl
index 72b0a43cdb4..72b0a43cdb4 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_frag.glsl
index 2fd155f715c..2fd155f715c 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_geom.glsl
index 82f957b2071..82f957b2071 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl
index 6ff8d0665d1..6ff8d0665d1 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl
index f1fbdac7847..f1fbdac7847 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert.glsl
index 166ac1a37b0..374fb50af75 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert.glsl
@@ -1,7 +1,7 @@
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(edit_mesh_common_lib.glsl)
+#pragma BLENDER_REQUIRE(overlay_edit_mesh_common_lib.glsl)
#ifdef EDGE
/* Ugly but needed to keep the same vertex shader code for other passes. */
diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_point_vert.glsl
index 956b27e948d..956b27e948d 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl
index 6a92206d524..6a92206d524 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl
index 9c0ce4ecc8a..a849cb5160a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(common_overlay_lib.glsl)
+#pragma BLENDER_REQUIRE(overlay_common_lib.glsl)
/**
* We want to know how much a pixel is covered by a line.
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl
index ac8d33cd727..8b19f671139 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(common_overlay_lib.glsl)
+#pragma BLENDER_REQUIRE(overlay_common_lib.glsl)
void do_vertex(
vec4 pos, float selection_fac, vec2 stipple_start, vec2 stipple_pos, float coord, vec2 offset)
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl
index 23f1a44c321..23f1a44c321 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
index 280b31ea463..c0d4393f2da 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
@@ -5,6 +5,6 @@ void main()
vec3 world_pos = point_object_to_world(vec3(au, 0.0));
gl_Position = point_world_to_ndc(world_pos);
- finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorVertexSelect : vec4(colorWire.rgb, 1.0);
+ finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorFaceDot : vec4(colorWire.rgb, 1.0);
gl_PointSize = pointSize;
}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl
index 80ea6228675..80ea6228675 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_image_mask_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl
index a1392abbb92..a1392abbb92 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_image_mask_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_image_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_vert.glsl
index 7ecbb513265..7ecbb513265 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_image_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl
index bb086e8d9f5..bb086e8d9f5 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl
index bc5235b9cab..bc5235b9cab 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl
index c0ea6aebe10..c0ea6aebe10 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl
index 9f9b02ce19d..9f9b02ce19d 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl
index bf29b2b057e..bf29b2b057e 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl
index ff7aae523e7..ff7aae523e7 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl
index 1eee7ab251b..1eee7ab251b 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_frag.glsl
index d92b947ef89..d92b947ef89 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_vert.glsl
index f283934816c..f283934816c 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_point_vert.glsl
index de999c241c0..de999c241c0 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl
index b2578970c9b..b2578970c9b 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl
index f32e3a8564e..f32e3a8564e 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_vert.glsl
index cd217021e8f..cd217021e8f 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/facing_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_facing_frag.glsl
index 8208689d113..8208689d113 100644
--- a/source/blender/draw/engines/overlay/shaders/facing_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_facing_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/facing_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_facing_vert.glsl
index d98caee6a25..d98caee6a25 100644
--- a/source/blender/draw/engines/overlay/shaders/facing_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_facing_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/grid_background_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_background_frag.glsl
index 37958319b44..37958319b44 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_background_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_background_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl
index 25f4984f119..25f4984f119 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_vert.glsl
index b81f1a24358..b81f1a24358 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/image_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl
index e0339507e0f..e0339507e0f 100644
--- a/source/blender/draw/engines/overlay/shaders/image_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/image_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_image_vert.glsl
index 45cddb3610d..45cddb3610d 100644
--- a/source/blender/draw/engines/overlay/shaders/image_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_image_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_frag.glsl
index 324d22501f9..324d22501f9 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_line_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_geom.glsl
index 29346a44863..29346a44863 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl
index bc74a436f5e..bc74a436f5e 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_point_vert.glsl
index 5027525b9b3..5027525b9b3 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl
index 472a589f441..472a589f441 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_frag.glsl
index d1abd74a7b3..d1abd74a7b3 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_geom.glsl
index 8a196620af9..8a196620af9 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl
index b6d5cd96c12..b6d5cd96c12 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
index 4b1470e5723..4b1470e5723 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl
index 371ff628c59..371ff628c59 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl
index 1d0b08f51b2..1d0b08f51b2 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_face_vert.glsl
index 22906bf1526..22906bf1526 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_face_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_point_vert.glsl
index 8736b2a87db..8736b2a87db 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_frag.glsl
index e5af0e7bd88..e5af0e7bd88 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_vert.glsl
index f93d0050950..f93d0050950 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_frag.glsl
index 193fabc65cb..193fabc65cb 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_vert.glsl
index 650070dcfd5..650070dcfd5 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl
index 1befe7506c4..1befe7506c4 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_vert.glsl
index cff79d606d6..cff79d606d6 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_wire_vert.glsl
index 749cc92f082..749cc92f082 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/particle_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl
index a2bcca7b820..a2bcca7b820 100644
--- a/source/blender/draw/engines/overlay/shaders/particle_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/particle_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_particle_vert.glsl
index fb981a8167a..fb981a8167a 100644
--- a/source/blender/draw/engines/overlay/shaders/particle_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_particle_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl
new file mode 100644
index 00000000000..b0da035ef09
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl
@@ -0,0 +1,23 @@
+
+void main()
+{
+ vec2 centered = gl_PointCoord - vec2(0.5);
+ float dist_squared = dot(centered, centered);
+ const float rad_squared = 0.25;
+
+ /* Round point with jaggy edges. */
+ if (dist_squared > rad_squared) {
+ discard;
+ }
+
+#if defined(VERT)
+ fragColor = finalColor;
+
+ float midStroke = 0.5 * rad_squared;
+ if (vertexCrease > 0.0 && dist_squared > midStroke) {
+ fragColor.rgb = mix(finalColor.rgb, colorEdgeCrease.rgb, vertexCrease);
+ }
+#else
+ fragColor = finalColor;
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
new file mode 100644
index 00000000000..c0ea6aebe10
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
@@ -0,0 +1,27 @@
+
+void main()
+{
+ float dist = length(gl_PointCoord - vec2(0.5));
+
+ /* transparent outside of point
+ * --- 0 ---
+ * smooth transition
+ * --- 1 ---
+ * pure outline color
+ * --- 2 ---
+ * smooth transition
+ * --- 3 ---
+ * pure fill color
+ * ...
+ * dist = 0 at center of point */
+
+ float midStroke = 0.5 * (radii[1] + radii[2]);
+
+ if (dist > midStroke) {
+ fragColor.rgb = outlineColor.rgb;
+ fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist));
+ }
+ else {
+ fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist));
+ }
+}
diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
index 9650af755c5..9650af755c5 100644
--- a/source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_vert.glsl
index 36c0e6a0acf..36c0e6a0acf 100644
--- a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl
new file mode 100644
index 00000000000..0a498471b46
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl
@@ -0,0 +1,4 @@
+void main()
+{
+ fragColor = color;
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl b/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl
new file mode 100644
index 00000000000..a27e2849bb3
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl
@@ -0,0 +1,4 @@
+void main()
+{
+ fragColor = finalColor;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_volume_gridlines_vert.glsl
index 11a04dddd2a..11a04dddd2a 100644
--- a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_volume_gridlines_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_volume_velocity_vert.glsl
index a33d27676c3..a33d27676c3 100644
--- a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_volume_velocity_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl
index bc28d7a8a36..bc28d7a8a36 100644
--- a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl
index 41bd7791dd7..41bd7791dd7 100644
--- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/xray_fade_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl
index 9aa2fdc3796..9aa2fdc3796 100644
--- a/source/blender/draw/engines/overlay/shaders/xray_fade_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index fb20bde2f65..9eb35c25bf4 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -97,7 +97,7 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd,
{
const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR);
if (use_single_drawcall) {
- DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, NULL);
+ DRWShadingGroup *grp = workbench_material_setup(wpd, ob, ob->actcol, color_type, NULL);
DRW_shgroup_call_sculpt(grp, ob, false, false);
}
else {
@@ -323,7 +323,8 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
}
}
- if (is_sculpt_pbvh && color_type == V3D_SHADING_TEXTURE_COLOR) {
+ if (is_sculpt_pbvh && color_type == V3D_SHADING_TEXTURE_COLOR &&
+ BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES) {
/* Force use of material color for sculpt. */
color_type = V3D_SHADING_MATERIAL_COLOR;
}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 07105757b2c..fa4a1d93d3e 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -837,7 +837,7 @@ void DRW_render_viewport_size_set(const int size[2]);
/**
* Assume a valid GL context is bound (and that the gl_context_mutex has been acquired).
* This function only setup DST and execute the given function.
- * \warning similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl).
+ * \warning similar to DRW_render_to_image you cannot use default lists (`dfbl` & `dtxl`).
*/
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
struct Depsgraph *depsgraph,
@@ -850,6 +850,7 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
void DRW_cache_restart(void);
/* ViewLayers */
+
void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type);
void **DRW_view_layer_engine_data_ensure_ex(struct ViewLayer *view_layer,
DrawEngineType *engine_type,
@@ -858,6 +859,7 @@ void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type,
void (*callback)(void *storage));
/* DrawData */
+
DrawData *DRW_drawdata_get(ID *id, DrawEngineType *engine_type);
DrawData *DRW_drawdata_ensure(ID *id,
DrawEngineType *engine_type,
diff --git a/source/blender/draw/intern/draw_attributes.cc b/source/blender/draw/intern/draw_attributes.cc
index f84a6c86fac..8fb4210901f 100644
--- a/source/blender/draw/intern/draw_attributes.cc
+++ b/source/blender/draw/intern/draw_attributes.cc
@@ -84,9 +84,9 @@ DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
bool drw_custom_data_match_attribute(const CustomData *custom_data,
const char *name,
int *r_layer_index,
- int *r_type)
+ eCustomDataType *r_type)
{
- const int possible_attribute_types[7] = {
+ const eCustomDataType possible_attribute_types[7] = {
CD_PROP_BOOL,
CD_PROP_INT8,
CD_PROP_INT32,
@@ -97,7 +97,7 @@ bool drw_custom_data_match_attribute(const CustomData *custom_data,
};
for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) {
- const int attr_type = possible_attribute_types[i];
+ const eCustomDataType attr_type = possible_attribute_types[i];
int layer_index = CustomData_get_named_layer(custom_data, attr_type, name);
if (layer_index == -1) {
continue;
diff --git a/source/blender/draw/intern/draw_attributes.h b/source/blender/draw/intern/draw_attributes.h
index c375670cd70..4f82f3b94e9 100644
--- a/source/blender/draw/intern/draw_attributes.h
+++ b/source/blender/draw/intern/draw_attributes.h
@@ -53,7 +53,7 @@ DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
bool drw_custom_data_match_attribute(const CustomData *custom_data,
const char *name,
int *r_layer_index,
- int *r_type);
+ eCustomDataType *r_type);
#ifdef __cplusplus
}
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index fb074cc728e..f846251c66b 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -3410,3 +3410,35 @@ void DRW_batch_cache_free_old(Object *ob, int ctime)
}
/** \} */
+
+void DRW_cdlayer_attr_aliases_add(GPUVertFormat *format,
+ const char *base_name,
+ const CustomData *UNUSED(data),
+ const CustomDataLayer *cl,
+ bool is_active_render,
+ bool is_active_layer)
+{
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ const char *layer_name = cl->name;
+
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+
+ /* Attribute layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "%s%s", base_name, attr_safe_name);
+ GPU_vertformat_alias_add(format, attr_name);
+
+ /* Auto layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
+ GPU_vertformat_alias_add(format, attr_name);
+
+ /* Active render layer name. */
+ if (is_active_render) {
+ GPU_vertformat_alias_add(format, base_name);
+ }
+
+ /* Active display layer name. */
+ if (is_active_layer) {
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", base_name);
+ GPU_vertformat_alias_add(format, attr_name);
+ }
+}
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.hh
index ce3ad9923da..c7127d169e1 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.hh
@@ -7,11 +7,13 @@
#pragma once
-struct DRWSubdivCache;
-struct MeshRenderData;
-struct TaskGraph;
+#include <algorithm>
+
+#include "BLI_utildefines.h"
#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_view3d_enums.h"
#include "BKE_attribute.h"
#include "BKE_object.h"
@@ -22,8 +24,12 @@ struct TaskGraph;
#include "draw_attributes.h"
+struct DRWSubdivCache;
+struct MeshRenderData;
+struct TaskGraph;
+
/* Vertex Group Selection and display options */
-typedef struct DRW_MeshWeightState {
+struct DRW_MeshWeightState {
int defgroup_active;
int defgroup_len;
@@ -31,13 +37,13 @@ typedef struct DRW_MeshWeightState {
char alert_mode;
/* Set of all selected bones for Multi-paint. */
- bool *defgroup_sel; /* [defgroup_len] */
+ bool *defgroup_sel; /* #defgroup_len */
int defgroup_sel_count;
/* Set of all locked and unlocked deform bones for Lock Relative mode. */
- bool *defgroup_locked; /* [defgroup_len] */
- bool *defgroup_unlocked; /* [defgroup_len] */
-} DRW_MeshWeightState;
+ bool *defgroup_locked; /* #defgroup_len */
+ bool *defgroup_unlocked; /* #defgroup_len */
+};
/* DRW_MeshWeightState.flags */
enum {
@@ -46,30 +52,32 @@ enum {
DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE = (1 << 2),
};
-typedef struct DRW_MeshCDMask {
+struct DRW_MeshCDMask {
uint32_t uv : 8;
uint32_t tan : 8;
uint32_t vcol : 8;
uint32_t orco : 1;
uint32_t tan_orco : 1;
uint32_t sculpt_overlays : 1;
- /** Edit uv layer is from the base edit mesh as
- * modifiers could remove it. (see T68857) */
+ /**
+ * Edit uv layer is from the base edit mesh as modifiers could remove it. (see T68857)
+ */
uint32_t edit_uv : 1;
-} DRW_MeshCDMask;
-/* Keep `DRW_MeshCDMask` struct within an `uint32_t`.
+};
+/* Keep `DRW_MeshCDMask` struct within a `uint32_t`.
* bit-wise and atomic operations are used to compare and update the struct.
* See `mesh_cd_layers_type_*` functions. */
BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint32_t), "DRW_MeshCDMask exceeds 32 bits")
-typedef enum eMRIterType {
+
+enum eMRIterType {
MR_ITER_LOOPTRI = 1 << 0,
MR_ITER_POLY = 1 << 1,
MR_ITER_LEDGE = 1 << 2,
MR_ITER_LVERT = 1 << 3,
-} eMRIterType;
+};
ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT)
-typedef enum eMRDataType {
+enum eMRDataType {
MR_DATA_NONE = 0,
MR_DATA_POLY_NOR = 1 << 1,
MR_DATA_LOOP_NOR = 1 << 2,
@@ -78,29 +86,24 @@ typedef enum eMRDataType {
/** Force loop normals calculation. */
MR_DATA_TAN_LOOP_NOR = 1 << 5,
MR_DATA_POLYS_SORTED = 1 << 6,
-} eMRDataType;
+};
ENUM_OPERATORS(eMRDataType, MR_DATA_POLYS_SORTED)
-#ifdef __cplusplus
-extern "C" {
-#endif
-
BLI_INLINE int mesh_render_mat_len_get(const Object *object, const Mesh *me)
{
if (me->edit_mesh != NULL) {
const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
if (editmesh_eval_final != NULL) {
- return MAX2(1, editmesh_eval_final->totcol);
+ return std::max<int>(1, editmesh_eval_final->totcol);
}
}
- return MAX2(1, me->totcol);
+ return std::max<int>(1, me->totcol);
}
-typedef struct MeshBufferList {
- /* Every VBO below contains at least enough
- * data for every loops in the mesh (except fdots and skin roots).
- * For some VBOs, it extends to (in this exact order) :
- * loops + loose_edges*2 + loose_verts */
+struct MeshBufferList {
+ /* Every VBO below contains at least enough data for every loop in the mesh
+ * (except fdots and skin roots). For some VBOs, it extends to (in this exact order) :
+ * loops + loose_edges * 2 + loose_verts */
struct {
GPUVertBuf *pos_nor; /* extend */
GPUVertBuf *lnor; /* extend */
@@ -133,14 +136,17 @@ typedef struct MeshBufferList {
/* Index Buffers:
* Only need to be updated when topology changes. */
struct {
- /* Indices to vloops. */
- GPUIndexBuf *tris; /* Ordered per material. */
- GPUIndexBuf *lines; /* Loose edges last. */
- GPUIndexBuf *lines_loose; /* sub buffer of `lines` only containing the loose edges. */
+ /* Indices to vloops. Ordered per material. */
+ GPUIndexBuf *tris;
+ /* Loose edges last. */
+ GPUIndexBuf *lines;
+ /* Sub buffer of `lines` only containing the loose edges. */
+ GPUIndexBuf *lines_loose;
GPUIndexBuf *points;
GPUIndexBuf *fdots;
/* 3D overlays. */
- GPUIndexBuf *lines_paint_mask; /* no loose edges. */
+ /* no loose edges. */
+ GPUIndexBuf *lines_paint_mask;
GPUIndexBuf *lines_adjacency;
/* Uv overlays. (visibility can differ from 3D view) */
GPUIndexBuf *edituv_tris;
@@ -148,9 +154,9 @@ typedef struct MeshBufferList {
GPUIndexBuf *edituv_points;
GPUIndexBuf *edituv_fdots;
} ibo;
-} MeshBufferList;
+};
-typedef struct MeshBatchList {
+struct MeshBatchList {
/* Surfaces / Render */
GPUBatch *surface;
GPUBatch *surface_weights;
@@ -180,19 +186,22 @@ typedef struct MeshBatchList {
GPUBatch *all_edges;
GPUBatch *loose_edges;
GPUBatch *edge_detection;
- GPUBatch *wire_edges; /* Individual edges with face normals. */
- GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */
- GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */
+ /* Individual edges with face normals. */
+ GPUBatch *wire_edges;
+ /* Loops around faces. no edges between selected faces */
+ GPUBatch *wire_loops;
+ /* Same as wire_loops but only has uvs. */
+ GPUBatch *wire_loops_uvs;
GPUBatch *sculpt_overlays;
-} MeshBatchList;
+};
#define MBC_BATCH_LEN (sizeof(MeshBatchList) / sizeof(void *))
-#define MBC_VBO_LEN (sizeof(((MeshBufferList){0}).vbo) / sizeof(void *))
-#define MBC_IBO_LEN (sizeof(((MeshBufferList){0}).ibo) / sizeof(void *))
+#define MBC_VBO_LEN (sizeof(MeshBufferList::vbo) / sizeof(void *))
+#define MBC_IBO_LEN (sizeof(MeshBufferList::ibo) / sizeof(void *))
#define MBC_BATCH_INDEX(batch) (offsetof(MeshBatchList, batch) / sizeof(void *))
-typedef enum DRWBatchFlag {
+enum DRWBatchFlag {
MBC_SURFACE = (1u << MBC_BATCH_INDEX(surface)),
MBC_SURFACE_WEIGHTS = (1u << MBC_BATCH_INDEX(surface_weights)),
MBC_EDIT_TRIANGLES = (1u << MBC_BATCH_INDEX(edit_triangles)),
@@ -221,23 +230,25 @@ typedef enum DRWBatchFlag {
MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(wire_loops)),
MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(wire_loops_uvs)),
MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(sculpt_overlays)),
-} DRWBatchFlag;
+ MBC_SURFACE_PER_MAT = (1u << MBC_BATCH_LEN),
+};
+ENUM_OPERATORS(DRWBatchFlag, MBC_SURFACE_PER_MAT);
BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields");
-typedef struct MeshExtractLooseGeom {
+struct MeshExtractLooseGeom {
int edge_len;
int vert_len;
int *verts;
int *edges;
-} MeshExtractLooseGeom;
+};
/**
* Data that are kept around between extractions to reduce rebuilding time.
*
* - Loose geometry.
*/
-typedef struct MeshBufferCache {
+struct MeshBufferCache {
MeshBufferList buff;
MeshExtractLooseGeom loose_geom;
@@ -247,7 +258,7 @@ typedef struct MeshBufferCache {
int *mat_tri_len;
int visible_tri_len;
} poly_sorted;
-} MeshBufferCache;
+};
#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \
for (MeshBufferCache *mbc = &batch_cache->final; \
@@ -256,7 +267,7 @@ typedef struct MeshBufferCache {
&batch_cache->cage : \
((mbc == &batch_cache->cage) ? &batch_cache->uv_cage : NULL))
-typedef struct MeshBatchCache {
+struct MeshBatchCache {
MeshBufferCache final, cage, uv_cage;
MeshBatchList batch;
@@ -266,22 +277,23 @@ typedef struct MeshBatchCache {
GPUBatch **surface_per_mat;
- struct DRWSubdivCache *subdiv_cache;
+ DRWSubdivCache *subdiv_cache;
- DRWBatchFlag batch_requested; /* DRWBatchFlag */
- DRWBatchFlag batch_ready; /* DRWBatchFlag */
+ DRWBatchFlag batch_requested;
+ DRWBatchFlag batch_ready;
- /* settings to determine if cache is invalid */
+ /* Settings to determine if cache is invalid. */
int edge_len;
int tri_len;
int poly_len;
int vert_len;
int mat_len;
- bool is_dirty; /* Instantly invalidates cache, skipping mesh check */
+ /* Instantly invalidates cache, skipping mesh check */
+ bool is_dirty;
bool is_editmode;
bool is_uvsyncsel;
- struct DRW_MeshWeightState weight_state;
+ DRW_MeshWeightState weight_state;
DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
@@ -302,13 +314,15 @@ typedef struct MeshBatchCache {
eV3DShadingColorType color_type;
bool pbvh_is_drawing;
-} MeshBatchCache;
+};
#define MBC_EDITUV \
(MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \
MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS)
-void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
+namespace blender::draw {
+
+void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
Object *object,
@@ -320,14 +334,12 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
bool do_final,
bool do_uvedit,
const Scene *scene,
- const struct ToolSettings *ts,
+ const ToolSettings *ts,
bool use_hide);
void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
MeshBufferCache *mbc,
- struct DRWSubdivCache *subdiv_cache,
- struct MeshRenderData *mr);
+ DRWSubdivCache *subdiv_cache,
+ MeshRenderData *mr);
-#ifdef __cplusplus
-}
-#endif
+} // namespace blender::draw
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 3d44d3d1b3f..00005fd7b4c 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -24,11 +24,11 @@
#include "GPU_capabilities.h"
-#include "draw_cache_extract.h"
+#include "draw_cache_extract.hh"
#include "draw_cache_inline.h"
#include "draw_subdivision.h"
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
// #define DEBUG_TIME
@@ -551,21 +551,21 @@ static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *t
/** \name Extract Loop
* \{ */
-static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
- MeshBatchCache *cache,
- MeshBufferCache *mbc,
- Object *object,
- Mesh *me,
-
- const bool is_editmode,
- const bool is_paint_mode,
- const bool is_mode_active,
- const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
- const Scene *scene,
- const ToolSettings *ts,
- const bool use_hide)
+void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
+ MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ Object *object,
+ Mesh *me,
+
+ const bool is_editmode,
+ const bool is_paint_mode,
+ const bool is_mode_active,
+ const float obmat[4][4],
+ const bool do_final,
+ const bool do_uvedit,
+ const Scene *scene,
+ const ToolSettings *ts,
+ const bool use_hide)
{
/* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph.
* This sub-graph starts with an extract_render_data_node. This fills/converts the required
@@ -772,10 +772,10 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
/** \name Subdivision Extract Loop
* \{ */
-static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
- MeshBufferCache *mbc,
- DRWSubdivCache *subdiv_cache,
- MeshRenderData *mr)
+void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ DRWSubdivCache *subdiv_cache,
+ MeshRenderData *mr)
{
/* Create an array containing all the extractors that needs to be executed. */
ExtractorRunDatas extractors;
@@ -908,46 +908,3 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
/** \} */
} // namespace blender::draw
-
-extern "C" {
-void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
- MeshBatchCache *cache,
- MeshBufferCache *mbc,
- Object *object,
- Mesh *me,
-
- const bool is_editmode,
- const bool is_paint_mode,
- const bool is_mode_active,
- const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
- const Scene *scene,
- const ToolSettings *ts,
- const bool use_hide)
-{
- blender::draw::mesh_buffer_cache_create_requested(task_graph,
- cache,
- mbc,
- object,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- obmat,
- do_final,
- do_uvedit,
- scene,
- ts,
- use_hide);
-}
-
-void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
- MeshBufferCache *mbc,
- DRWSubdivCache *subdiv_cache,
- MeshRenderData *mr)
-{
- blender::draw::mesh_buffer_cache_create_requested_subdiv(cache, mbc, subdiv_cache, mr);
-}
-
-} // extern "C"
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc
index 0a93f346b37..baea0c7b646 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc
@@ -9,7 +9,7 @@
#include "MEM_guardedalloc.h"
-#include "BLI_alloca.h"
+#include "BLI_array.hh"
#include "BLI_bitmap.h"
#include "BLI_math.h"
#include "BLI_task.h"
@@ -22,7 +22,7 @@
#include "ED_mesh.h"
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
/* ---------------------------------------------------------------------- */
/** \name Update Loose Geometry
@@ -78,7 +78,8 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe
{
BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
- cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__);
+ cache->loose_geom.edges = static_cast<int *>(
+ MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__));
const MEdge *med = mr->medge;
for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
if (med->flag & ME_LOOSEEDGE) {
@@ -89,19 +90,20 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe
BLI_BITMAP_ENABLE(lvert_map, med->v2);
}
if (cache->loose_geom.edge_len < mr->edge_len) {
- cache->loose_geom.edges = MEM_reallocN(
- cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges));
+ cache->loose_geom.edges = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges)));
}
- cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__);
+ cache->loose_geom.verts = static_cast<int *>(
+ MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__));
for (int v = 0; v < mr->vert_len; v++) {
if (!BLI_BITMAP_TEST(lvert_map, v)) {
cache->loose_geom.verts[cache->loose_geom.vert_len++] = v;
}
}
if (cache->loose_geom.vert_len < mr->vert_len) {
- cache->loose_geom.verts = MEM_reallocN(
- cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts));
+ cache->loose_geom.verts = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)));
}
MEM_freeN(lvert_map);
@@ -112,15 +114,16 @@ static void mesh_render_data_lverts_bm(const MeshRenderData *mr, MeshBufferCache
int elem_id;
BMIter iter;
BMVert *eve;
- cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__);
+ cache->loose_geom.verts = static_cast<int *>(
+ MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__));
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
- if (eve->e == NULL) {
+ if (eve->e == nullptr) {
cache->loose_geom.verts[cache->loose_geom.vert_len++] = elem_id;
}
}
if (cache->loose_geom.vert_len < mr->vert_len) {
- cache->loose_geom.verts = MEM_reallocN(
- cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts));
+ cache->loose_geom.verts = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)));
}
}
@@ -129,15 +132,16 @@ static void mesh_render_data_ledges_bm(const MeshRenderData *mr, MeshBufferCache
int elem_id;
BMIter iter;
BMEdge *ede;
- cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__);
+ cache->loose_geom.edges = static_cast<int *>(
+ MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__));
BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
- if (ede->l == NULL) {
+ if (ede->l == nullptr) {
cache->loose_geom.edges[cache->loose_geom.edge_len++] = elem_id;
}
}
if (cache->loose_geom.edge_len < mr->edge_len) {
- cache->loose_geom.edges = MEM_reallocN(
- cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges));
+ cache->loose_geom.edges = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges)));
}
}
@@ -192,12 +196,13 @@ static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferC
static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache)
{
- int *tri_first_index = MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__);
+ int *tri_first_index = static_cast<int *>(
+ MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__));
int *mat_tri_len = mesh_render_data_mat_tri_len_build(mr);
/* Apply offset. */
int visible_tri_len = 0;
- int *mat_tri_offs = BLI_array_alloca(mat_tri_offs, mr->mat_len);
+ blender::Array<int, 32> mat_tri_offs(mr->mat_len);
{
for (int i = 0; i < mr->mat_len; i++) {
mat_tri_offs[i] = visible_tri_len;
@@ -245,8 +250,8 @@ static void mesh_render_data_mat_tri_len_bm_range_fn(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
- MeshRenderData *mr = userdata;
- int *mat_tri_len = tls->userdata_chunk;
+ MeshRenderData *mr = static_cast<MeshRenderData *>(userdata);
+ int *mat_tri_len = static_cast<int *>(tls->userdata_chunk);
BMesh *bm = mr->bm;
BMFace *efa = BM_face_at_index(bm, iter);
@@ -260,8 +265,8 @@ static void mesh_render_data_mat_tri_len_mesh_range_fn(void *__restrict userdata
const int iter,
const TaskParallelTLS *__restrict tls)
{
- MeshRenderData *mr = userdata;
- int *mat_tri_len = tls->userdata_chunk;
+ MeshRenderData *mr = static_cast<MeshRenderData *>(userdata);
+ int *mat_tri_len = static_cast<int *>(tls->userdata_chunk);
const MPoly *mp = &mr->mpoly[iter];
if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
@@ -274,9 +279,9 @@ static void mesh_render_data_mat_tri_len_reduce_fn(const void *__restrict userda
void *__restrict chunk_join,
void *__restrict chunk)
{
- const MeshRenderData *mr = userdata;
- int *dst_mat_len = chunk_join;
- int *src_mat_len = chunk;
+ const MeshRenderData *mr = static_cast<const MeshRenderData *>(userdata);
+ int *dst_mat_len = static_cast<int *>(chunk_join);
+ int *src_mat_len = static_cast<int *>(chunk);
for (int i = 0; i < mr->mat_len; i++) {
dst_mat_len[i] += src_mat_len[i];
}
@@ -288,7 +293,7 @@ static int *mesh_render_data_mat_tri_len_build_threaded(MeshRenderData *mr,
{
/* Extending the #MatOffsetUserData with an int per material slot. */
size_t mat_tri_len_size = sizeof(int) * mr->mat_len;
- int *mat_tri_len = MEM_callocN(mat_tri_len_size, __func__);
+ int *mat_tri_len = static_cast<int *>(MEM_callocN(mat_tri_len_size, __func__));
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -330,8 +335,9 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
/* NOTE(campbell): It's possible to skip allocating tessellation,
* the tessellation can be calculated as part of the iterator, see: P2188.
* The overall advantage is small (around 1%), so keep this as-is. */
- mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI");
- if (mr->poly_normals != NULL) {
+ mr->mlooptri = static_cast<MLoopTri *>(
+ MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI"));
+ if (mr->poly_normals != nullptr) {
BKE_mesh_recalc_looptri_with_normals(me->mloop,
me->mpoly,
me->mvert,
@@ -350,7 +356,7 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
/* #BMesh */
if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
/* Edit mode ensures this is valid, no need to calculate. */
- BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL));
+ BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != nullptr));
}
}
}
@@ -368,8 +374,10 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
mr->poly_normals = BKE_mesh_poly_normals_ensure(mr->me);
}
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
- mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
- short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL);
+ mr->loop_normals = static_cast<float(*)[3]>(
+ MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__));
+ short(*clnors)[2] = static_cast<short(*)[2]>(
+ CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL));
BKE_mesh_normals_loop_split(mr->me->mvert,
mr->vert_normals,
mr->vert_len,
@@ -383,9 +391,9 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
mr->poly_len,
is_auto_smooth,
split_angle,
- NULL,
+ nullptr,
clnors,
- NULL);
+ nullptr);
}
}
else {
@@ -395,9 +403,9 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
}
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
- const float(*vert_coords)[3] = NULL;
- const float(*vert_normals)[3] = NULL;
- const float(*poly_normals)[3] = NULL;
+ const float(*vert_coords)[3] = nullptr;
+ const float(*vert_normals)[3] = nullptr;
+ const float(*poly_normals)[3] = nullptr;
if (mr->edit_data && mr->edit_data->vertexCos) {
vert_coords = mr->bm_vert_coords;
@@ -405,7 +413,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
poly_normals = mr->bm_poly_normals;
}
- mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
+ mr->loop_normals = static_cast<float(*)[3]>(
+ MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__));
const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
BM_loops_calc_normal_vcos(mr->bm,
vert_coords,
@@ -414,8 +423,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
is_auto_smooth,
split_angle,
mr->loop_normals,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
clnors_offset,
false);
}
@@ -432,7 +441,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
const bool do_uvedit,
const ToolSettings *ts)
{
- MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
+ MeshRenderData *mr = static_cast<MeshRenderData *>(MEM_callocN(sizeof(*mr), __func__));
mr->toolsettings = ts;
mr->mat_len = mesh_render_mat_len_get(object, me);
@@ -446,7 +455,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->bm = me->edit_mesh->bm;
mr->edit_bmesh = me->edit_mesh;
mr->me = (do_final) ? editmesh_eval_final : editmesh_eval_cage;
- mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL;
+ mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : nullptr;
if (mr->edit_data) {
EditMeshData *emd = mr->edit_data;
@@ -491,9 +500,12 @@ MeshRenderData *mesh_render_data_create(Object *object,
#endif
if (use_mapped) {
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+ mr->v_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
}
@@ -503,19 +515,22 @@ MeshRenderData *mesh_render_data_create(Object *object,
/* Seems like the mesh_eval_final do not have the right origin indices.
* Force not mapped in this case. */
if (has_mdata && do_final && editmesh_eval_final != editmesh_eval_cage) {
- // mr->edit_bmesh = NULL;
+ // mr->edit_bmesh = nullptr;
mr->extract_type = MR_EXTRACT_MESH;
}
}
else {
mr->me = me;
- mr->edit_bmesh = NULL;
+ mr->edit_bmesh = nullptr;
bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original;
if (use_mapped) {
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+ mr->v_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
}
@@ -531,14 +546,14 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->poly_len = mr->me->totpoly;
mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
- mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT);
- mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE);
- mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP);
- mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY);
+ mr->mvert = static_cast<MVert *>(CustomData_get_layer(&mr->me->vdata, CD_MVERT));
+ mr->medge = static_cast<MEdge *>(CustomData_get_layer(&mr->me->edata, CD_MEDGE));
+ mr->mloop = static_cast<MLoop *>(CustomData_get_layer(&mr->me->ldata, CD_MLOOP));
+ mr->mpoly = static_cast<MPoly *>(CustomData_get_layer(&mr->me->pdata, CD_MPOLY));
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+ mr->v_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
}
else {
/* #BMesh */
@@ -560,8 +575,8 @@ void mesh_render_data_free(MeshRenderData *mr)
MEM_SAFE_FREE(mr->loop_normals);
/* Loose geometry are owned by #MeshBufferCache. */
- mr->ledges = NULL;
- mr->lverts = NULL;
+ mr->ledges = nullptr;
+ mr->lverts = nullptr;
MEM_freeN(mr);
}
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 0755d5967d5..4fa5813d476 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -156,11 +156,15 @@ struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt);
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Hair
+/** \name Curves
* \{ */
int DRW_curves_material_count_get(struct Curves *curves);
+struct GPUBatch *DRW_curves_batch_cache_get_edit_points(struct Curves *curves);
+
+void DRW_curves_batch_cache_create_requested(struct Object *ob);
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -352,16 +356,6 @@ struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *ob
/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Curves
- * \{ */
-
-struct GPUBatch *DRW_curves_batch_cache_get_edit_points(struct Curves *curves);
-
-void DRW_curves_batch_cache_create_requested(const struct Object *ob);
-
-/** \} */
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc
index 68f210105b0..68ca1153c96 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -52,11 +52,14 @@ struct CurvesBatchCache {
GPUBatch *edit_points;
- /* To determine if cache is invalid. */
+ /* Whether the cache is invalid. */
bool is_dirty;
- /** Needed when updating material data (e.g. attributes) as the same curves might be used for
- * multiple objects with different materials. */
+ /**
+ * The draw cache extraction is currently not multi-threaded for multiple objects, but if it was,
+ * some locking would be necessary because multiple objects can use the same curves data with
+ * different materials, etc. This is a placeholder to make multi-threading easier in the future.
+ */
ThreadMutex render_mutex;
};
@@ -84,13 +87,13 @@ static void curves_batch_cache_init(Curves &curves)
static void curves_discard_attributes(CurvesEvalCache &curves_cache)
{
- for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ for (const int i : IndexRange(GPU_MAX_ATTR)) {
GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_attributes_buf[i]);
DRW_TEXTURE_FREE_SAFE(curves_cache.proc_attributes_tex[i]);
}
- for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
- for (int j = 0; j < GPU_MAX_ATTR; j++) {
+ for (const int i : IndexRange(MAX_HAIR_SUBDIV)) {
+ for (const int j : IndexRange(GPU_MAX_ATTR)) {
GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].attributes_buf[j]);
DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].attributes_tex[j]);
}
@@ -112,10 +115,10 @@ static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache)
DRW_TEXTURE_FREE_SAFE(curves_cache.strand_tex);
DRW_TEXTURE_FREE_SAFE(curves_cache.strand_seg_tex);
- for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ for (const int i : IndexRange(MAX_HAIR_SUBDIV)) {
GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].proc_buf);
DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].proc_tex);
- for (int j = 0; j < MAX_THICKRES; j++) {
+ for (const int j : IndexRange(MAX_THICKRES)) {
GPU_BATCH_DISCARD_SAFE(curves_cache.final[i].proc_hairs[j]);
}
}
@@ -160,7 +163,7 @@ void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode)
cache->is_dirty = true;
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
}
@@ -181,7 +184,7 @@ void DRW_curves_batch_cache_free_old(Curves *curves, int ctime)
bool do_discard = false;
- for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ for (const int i : IndexRange(MAX_HAIR_SUBDIV)) {
CurvesEvalFinalCache &final_cache = cache->curves_cache.final[i];
if (drw_attributes_overlap(&final_cache.attr_used_over_time, &final_cache.attr_used)) {
@@ -512,14 +515,14 @@ static bool curves_ensure_attributes(const Curves &curves,
ListBase gpu_attrs = GPU_material_attributes(gpu_material);
LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
const char *name = gpu_attr->name;
- int type = gpu_attr->type;
- int layer = -1;
- eAttrDomain domain;
- if (drw_custom_data_match_attribute(cd_curve, name, &layer, &type)) {
+ int layer_index;
+ eCustomDataType type;
+ eAttrDomain domain;
+ if (drw_custom_data_match_attribute(cd_curve, name, &layer_index, &type)) {
domain = ATTR_DOMAIN_CURVE;
}
- else if (drw_custom_data_match_attribute(cd_point, name, &layer, &type)) {
+ else if (drw_custom_data_match_attribute(cd_point, name, &layer_index, &type)) {
domain = ATTR_DOMAIN_POINT;
}
else {
@@ -527,8 +530,6 @@ static bool curves_ensure_attributes(const Curves &curves,
}
switch (type) {
- default:
- break;
case CD_PROP_BOOL:
case CD_PROP_INT8:
case CD_PROP_INT32:
@@ -536,24 +537,24 @@ static bool curves_ensure_attributes(const Curves &curves,
case CD_PROP_FLOAT2:
case CD_PROP_FLOAT3:
case CD_PROP_COLOR: {
- if (layer != -1) {
- DRW_AttributeRequest *req = drw_attributes_add_request(
- &attrs_needed, (eCustomDataType)type, layer, domain);
- if (req) {
- BLI_strncpy(req->attribute_name, name, sizeof(req->attribute_name));
- }
+ DRW_AttributeRequest *request = drw_attributes_add_request(
+ &attrs_needed, type, layer_index, domain);
+ if (request) {
+ BLI_strncpy(request->attribute_name, name, sizeof(request->attribute_name));
}
+
break;
}
+ default:
+ break;
}
}
CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv];
- const bool attr_overlap = drw_attributes_overlap(&final_cache.attr_used, &attrs_needed);
- if (attr_overlap == false) {
+ if (!drw_attributes_overlap(&final_cache.attr_used, &attrs_needed)) {
/* Some new attributes have been added, free all and start over. */
- for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ for (const int i : IndexRange(GPU_MAX_ATTR)) {
GPU_VERTBUF_DISCARD_SAFE(cache.curves_cache.proc_attributes_buf[i]);
DRW_TEXTURE_FREE_SAFE(cache.curves_cache.proc_attributes_tex[i]);
}
@@ -563,7 +564,7 @@ static bool curves_ensure_attributes(const Curves &curves,
bool need_tf_update = false;
- for (int i = 0; i < final_cache.attr_used.num_requests; i++) {
+ for (const int i : IndexRange(final_cache.attr_used.num_requests)) {
const DRW_AttributeRequest &request = final_cache.attr_used.requests[i];
if (cache.curves_cache.proc_attributes_buf[i] != nullptr) {
@@ -635,7 +636,7 @@ GPUBatch *DRW_curves_batch_cache_get_edit_points(Curves *curves)
return DRW_batch_request(&cache.edit_points);
}
-void DRW_curves_batch_cache_create_requested(const Object *ob)
+void DRW_curves_batch_cache_create_requested(Object *ob)
{
Curves *curves = static_cast<Curves *>(ob->data);
CurvesBatchCache &cache = curves_batch_cache_get(*curves);
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.cc
index a7fd484c72f..7c02ee2c033 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc
@@ -7,15 +7,19 @@
* \brief Mesh API for render engines
*/
+#include <optional>
+
#include "MEM_guardedalloc.h"
-#include "BLI_alloca.h"
#include "BLI_bitmap.h"
#include "BLI_buffer.h"
#include "BLI_edgehash.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
+#include "BLI_map.hh"
#include "BLI_math_bits.h"
#include "BLI_math_vector.h"
+#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -52,13 +56,17 @@
#include "ED_mesh.h"
#include "ED_uvedit.h"
-#include "draw_cache_extract.h"
+#include "draw_cache_extract.hh"
#include "draw_cache_inline.h"
#include "draw_subdivision.h"
#include "draw_cache_impl.h" /* own include */
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
+
+using blender::IndexRange;
+using blender::Map;
+using blender::Span;
/* ---------------------------------------------------------------------- */
/** \name Dependencies between buffer and batch
@@ -69,21 +77,7 @@
#define BUFFER_INDEX(buff_name) ((offsetof(MeshBufferList, buff_name) - offsetof(MeshBufferList, vbo)) / sizeof(void *))
#define BUFFER_LEN (sizeof(MeshBufferList) / sizeof(void *))
-#define _BATCH_FLAG1(b) (1u << MBC_BATCH_INDEX(b))
-#define _BATCH_FLAG2(b1, b2) _BATCH_FLAG1(b1) | _BATCH_FLAG1(b2)
-#define _BATCH_FLAG3(b1, b2, b3) _BATCH_FLAG2(b1, b2) | _BATCH_FLAG1(b3)
-#define _BATCH_FLAG4(b1, b2, b3, b4) _BATCH_FLAG3(b1, b2, b3) | _BATCH_FLAG1(b4)
-#define _BATCH_FLAG5(b1, b2, b3, b4, b5) _BATCH_FLAG4(b1, b2, b3, b4) | _BATCH_FLAG1(b5)
-#define _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) _BATCH_FLAG5(b1, b2, b3, b4, b5) | _BATCH_FLAG1(b6)
-#define _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) | _BATCH_FLAG1(b7)
-#define _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) | _BATCH_FLAG1(b8)
-#define _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) | _BATCH_FLAG1(b9)
-#define _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) | _BATCH_FLAG1(b10)
-#define _BATCH_FLAG18(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18) _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) | _BATCH_FLAG8(b11, b12, b13, b14, b15, b16, b17, b18)
-
-#define BATCH_FLAG(...) VA_NARGS_CALL_OVERLOAD(_BATCH_FLAG, __VA_ARGS__)
-
-#define _BATCH_MAP1(a) g_buffer_deps[BUFFER_INDEX(a)]
+#define _BATCH_MAP1(a) batches_that_use_buffer(BUFFER_INDEX(a))
#define _BATCH_MAP2(a, b) _BATCH_MAP1(a) | _BATCH_MAP1(b)
#define _BATCH_MAP3(a, b, c) _BATCH_MAP2(a, b) | _BATCH_MAP1(c)
#define _BATCH_MAP4(a, b, c, d) _BATCH_MAP3(a, b, c) | _BATCH_MAP1(d)
@@ -96,132 +90,110 @@
#define BATCH_MAP(...) VA_NARGS_CALL_OVERLOAD(_BATCH_MAP, __VA_ARGS__)
-#ifndef NDEBUG
-# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag) \
- g_buffer_deps_d[buffer_index] |= batch_flag; \
- BLI_assert(g_buffer_deps[buffer_index] & batch_flag)
-
-# define _MDEPS_ASSERT2(b, n1) MDEPS_ASSERT_INDEX(BUFFER_INDEX(n1), b)
-# define _MDEPS_ASSERT3(b, n1, n2) _MDEPS_ASSERT2(b, n1); _MDEPS_ASSERT2(b, n2)
-# define _MDEPS_ASSERT4(b, n1, n2, n3) _MDEPS_ASSERT3(b, n1, n2); _MDEPS_ASSERT2(b, n3)
-# define _MDEPS_ASSERT5(b, n1, n2, n3, n4) _MDEPS_ASSERT4(b, n1, n2, n3); _MDEPS_ASSERT2(b, n4)
-# define _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5) _MDEPS_ASSERT5(b, n1, n2, n3, n4); _MDEPS_ASSERT2(b, n5)
-# define _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6) _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5); _MDEPS_ASSERT2(b, n6)
-# define _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7) _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6); _MDEPS_ASSERT2(b, n7)
-# define _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20) _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7); _MDEPS_ASSERT8(b, n8, n9, n10, n11, n12, n13, n14); _MDEPS_ASSERT7(b, n15, n16, n17, n18, n19, n20)
-# define _MDEPS_ASSERT22(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21) _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20); _MDEPS_ASSERT2(b, n21);
-
-# define MDEPS_ASSERT_FLAG(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_ASSERT, __VA_ARGS__)
-# define MDEPS_ASSERT(batch_name, ...) MDEPS_ASSERT_FLAG(BATCH_FLAG(batch_name), __VA_ARGS__)
-# define MDEPS_ASSERT_MAP_INDEX(buff_index) BLI_assert(g_buffer_deps_d[buff_index] == g_buffer_deps[buff_index])
-# define MDEPS_ASSERT_MAP(buff_name) MDEPS_ASSERT_MAP_INDEX(BUFFER_INDEX(buff_name))
-#else
-# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag)
-# define MDEPS_ASSERT_FLAG(...)
-# define MDEPS_ASSERT(batch_name, ...)
-# define MDEPS_ASSERT_MAP_INDEX(buff_index)
-# define MDEPS_ASSERT_MAP(buff_name)
-#endif
-
/* clang-format on */
#define TRIS_PER_MAT_INDEX BUFFER_LEN
-#define SURFACE_PER_MAT_FLAG (1u << MBC_BATCH_LEN)
-
-static const DRWBatchFlag g_buffer_deps[] = {
- [BUFFER_INDEX(vbo.pos_nor)] = BATCH_FLAG(surface,
- surface_weights,
- edit_triangles,
- edit_vertices,
- edit_edges,
- edit_vnor,
- edit_lnor,
- edit_mesh_analysis,
- edit_selection_verts,
- edit_selection_edges,
- edit_selection_faces,
- all_verts,
- all_edges,
- loose_edges,
- edge_detection,
- wire_edges,
- wire_loops,
- sculpt_overlays) |
- SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.lnor)] = BATCH_FLAG(surface, edit_lnor, wire_loops) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.edge_fac)] = BATCH_FLAG(wire_edges),
- [BUFFER_INDEX(vbo.weights)] = BATCH_FLAG(surface_weights),
- [BUFFER_INDEX(vbo.uv)] = BATCH_FLAG(surface,
- edituv_faces_stretch_area,
- edituv_faces_stretch_angle,
- edituv_faces,
- edituv_edges,
- edituv_verts,
- wire_loops_uvs) |
- SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.tan)] = SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.vcol)] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.sculpt_data)] = BATCH_FLAG(sculpt_overlays),
- [BUFFER_INDEX(vbo.orco)] = SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.edit_data)] = BATCH_FLAG(edit_triangles, edit_edges, edit_vertices),
- [BUFFER_INDEX(vbo.edituv_data)] = BATCH_FLAG(edituv_faces,
- edituv_faces_stretch_area,
- edituv_faces_stretch_angle,
- edituv_edges,
- edituv_verts),
- [BUFFER_INDEX(vbo.edituv_stretch_area)] = BATCH_FLAG(edituv_faces_stretch_area),
- [BUFFER_INDEX(vbo.edituv_stretch_angle)] = BATCH_FLAG(edituv_faces_stretch_angle),
- [BUFFER_INDEX(vbo.mesh_analysis)] = BATCH_FLAG(edit_mesh_analysis),
- [BUFFER_INDEX(vbo.fdots_pos)] = BATCH_FLAG(edit_fdots, edit_selection_fdots),
- [BUFFER_INDEX(vbo.fdots_nor)] = BATCH_FLAG(edit_fdots),
- [BUFFER_INDEX(vbo.fdots_uv)] = BATCH_FLAG(edituv_fdots),
- [BUFFER_INDEX(vbo.fdots_edituv_data)] = BATCH_FLAG(edituv_fdots),
- [BUFFER_INDEX(vbo.skin_roots)] = BATCH_FLAG(edit_skin_roots),
- [BUFFER_INDEX(vbo.vert_idx)] = BATCH_FLAG(edit_selection_verts),
- [BUFFER_INDEX(vbo.edge_idx)] = BATCH_FLAG(edit_selection_edges),
- [BUFFER_INDEX(vbo.poly_idx)] = BATCH_FLAG(edit_selection_faces),
- [BUFFER_INDEX(vbo.fdot_idx)] = BATCH_FLAG(edit_selection_fdots),
- [BUFFER_INDEX(vbo.attr) + 0] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 1] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 2] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 3] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 4] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 5] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 6] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 7] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 8] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 9] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 10] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 11] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 12] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 13] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 14] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
-
- [BUFFER_INDEX(ibo.tris)] = BATCH_FLAG(surface,
- surface_weights,
- edit_triangles,
- edit_lnor,
- edit_mesh_analysis,
- edit_selection_faces,
- sculpt_overlays),
- [BUFFER_INDEX(ibo.lines)] = BATCH_FLAG(
- edit_edges, edit_selection_edges, all_edges, wire_edges),
- [BUFFER_INDEX(ibo.lines_loose)] = BATCH_FLAG(loose_edges),
- [BUFFER_INDEX(ibo.points)] = BATCH_FLAG(edit_vnor, edit_vertices, edit_selection_verts),
- [BUFFER_INDEX(ibo.fdots)] = BATCH_FLAG(edit_fdots, edit_selection_fdots),
- [BUFFER_INDEX(ibo.lines_paint_mask)] = BATCH_FLAG(wire_loops),
- [BUFFER_INDEX(ibo.lines_adjacency)] = BATCH_FLAG(edge_detection),
- [BUFFER_INDEX(ibo.edituv_tris)] = BATCH_FLAG(
- edituv_faces, edituv_faces_stretch_area, edituv_faces_stretch_angle),
- [BUFFER_INDEX(ibo.edituv_lines)] = BATCH_FLAG(edituv_edges, wire_loops_uvs),
- [BUFFER_INDEX(ibo.edituv_points)] = BATCH_FLAG(edituv_verts),
- [BUFFER_INDEX(ibo.edituv_fdots)] = BATCH_FLAG(edituv_fdots),
- [TRIS_PER_MAT_INDEX] = SURFACE_PER_MAT_FLAG,
-};
-
-#ifndef NDEBUG
-static DRWBatchFlag g_buffer_deps_d[ARRAY_SIZE(g_buffer_deps)] = {0};
-#endif
+
+static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index)
+{
+ switch (buffer_index) {
+ case BUFFER_INDEX(vbo.pos_nor):
+ return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_VERTICES |
+ MBC_EDIT_EDGES | MBC_EDIT_VNOR | MBC_EDIT_LNOR | MBC_EDIT_MESH_ANALYSIS |
+ MBC_EDIT_SELECTION_VERTS | MBC_EDIT_SELECTION_EDGES | MBC_EDIT_SELECTION_FACES |
+ MBC_ALL_VERTS | MBC_ALL_EDGES | MBC_LOOSE_EDGES | MBC_EDGE_DETECTION |
+ MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.lnor):
+ return MBC_SURFACE | MBC_EDIT_LNOR | MBC_WIRE_LOOPS | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.edge_fac):
+ return MBC_WIRE_EDGES;
+ case BUFFER_INDEX(vbo.weights):
+ return MBC_SURFACE_WEIGHTS;
+ case BUFFER_INDEX(vbo.uv):
+ return MBC_SURFACE | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE |
+ MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_WIRE_LOOPS_UVS |
+ MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.tan):
+ return MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.vcol):
+ return MBC_SURFACE | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.sculpt_data):
+ return MBC_SCULPT_OVERLAYS;
+ case BUFFER_INDEX(vbo.orco):
+ return MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.edit_data):
+ return MBC_EDIT_TRIANGLES | MBC_EDIT_EDGES | MBC_EDIT_VERTICES;
+ case BUFFER_INDEX(vbo.edituv_data):
+ return MBC_EDITUV_FACES | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE |
+ MBC_EDITUV_EDGES | MBC_EDITUV_VERTS;
+ case BUFFER_INDEX(vbo.edituv_stretch_area):
+ return MBC_EDITUV_FACES_STRETCH_AREA;
+ case BUFFER_INDEX(vbo.edituv_stretch_angle):
+ return MBC_EDITUV_FACES_STRETCH_ANGLE;
+ case BUFFER_INDEX(vbo.mesh_analysis):
+ return MBC_EDIT_MESH_ANALYSIS;
+ case BUFFER_INDEX(vbo.fdots_pos):
+ return MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS;
+ case BUFFER_INDEX(vbo.fdots_nor):
+ return MBC_EDIT_FACEDOTS;
+ case BUFFER_INDEX(vbo.fdots_uv):
+ return MBC_EDITUV_FACEDOTS;
+ case BUFFER_INDEX(vbo.fdots_edituv_data):
+ return MBC_EDITUV_FACEDOTS;
+ case BUFFER_INDEX(vbo.skin_roots):
+ return MBC_SKIN_ROOTS;
+ case BUFFER_INDEX(vbo.vert_idx):
+ return MBC_EDIT_SELECTION_VERTS;
+ case BUFFER_INDEX(vbo.edge_idx):
+ return MBC_EDIT_SELECTION_EDGES;
+ case BUFFER_INDEX(vbo.poly_idx):
+ return MBC_EDIT_SELECTION_FACES;
+ case BUFFER_INDEX(vbo.fdot_idx):
+ return MBC_EDIT_SELECTION_FACEDOTS;
+ case BUFFER_INDEX(vbo.attr[0]):
+ case BUFFER_INDEX(vbo.attr[1]):
+ case BUFFER_INDEX(vbo.attr[2]):
+ case BUFFER_INDEX(vbo.attr[3]):
+ case BUFFER_INDEX(vbo.attr[4]):
+ case BUFFER_INDEX(vbo.attr[5]):
+ case BUFFER_INDEX(vbo.attr[6]):
+ case BUFFER_INDEX(vbo.attr[7]):
+ case BUFFER_INDEX(vbo.attr[8]):
+ case BUFFER_INDEX(vbo.attr[9]):
+ case BUFFER_INDEX(vbo.attr[10]):
+ case BUFFER_INDEX(vbo.attr[11]):
+ case BUFFER_INDEX(vbo.attr[12]):
+ case BUFFER_INDEX(vbo.attr[13]):
+ case BUFFER_INDEX(vbo.attr[14]):
+ return MBC_SURFACE | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(ibo.tris):
+ return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR |
+ MBC_EDIT_MESH_ANALYSIS | MBC_EDIT_SELECTION_FACES | MBC_SCULPT_OVERLAYS;
+ case BUFFER_INDEX(ibo.lines):
+ return MBC_EDIT_EDGES | MBC_EDIT_SELECTION_EDGES | MBC_ALL_EDGES | MBC_WIRE_EDGES;
+ case BUFFER_INDEX(ibo.lines_loose):
+ return MBC_LOOSE_EDGES;
+ case BUFFER_INDEX(ibo.points):
+ return MBC_EDIT_VNOR | MBC_EDIT_VERTICES | MBC_EDIT_SELECTION_VERTS;
+ case BUFFER_INDEX(ibo.fdots):
+ return MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS;
+ case BUFFER_INDEX(ibo.lines_paint_mask):
+ return MBC_WIRE_LOOPS;
+ case BUFFER_INDEX(ibo.lines_adjacency):
+ return MBC_EDGE_DETECTION;
+ case BUFFER_INDEX(ibo.edituv_tris):
+ return MBC_EDITUV_FACES | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE;
+ case BUFFER_INDEX(ibo.edituv_lines):
+ return MBC_EDITUV_EDGES | MBC_WIRE_LOOPS_UVS;
+ case BUFFER_INDEX(ibo.edituv_points):
+ return MBC_EDITUV_VERTS;
+ case BUFFER_INDEX(ibo.edituv_fdots):
+ return MBC_EDITUV_FACEDOTS;
+ case TRIS_PER_MAT_INDEX:
+ return MBC_SURFACE_PER_MAT;
+ }
+ return (DRWBatchFlag)0;
+}
static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache);
static void mesh_batch_cache_clear(Mesh *me);
@@ -229,14 +201,14 @@ static void mesh_batch_cache_clear(Mesh *me);
static void mesh_batch_cache_discard_batch(MeshBatchCache *cache, const DRWBatchFlag batch_map)
{
for (int i = 0; i < MBC_BATCH_LEN; i++) {
- DRWBatchFlag batch_requested = (1u << i);
+ DRWBatchFlag batch_requested = (DRWBatchFlag)(1u << i);
if (batch_map & batch_requested) {
GPU_BATCH_DISCARD_SAFE(((GPUBatch **)&cache->batch)[i]);
cache->batch_ready &= ~batch_requested;
}
}
- if (batch_map & SURFACE_PER_MAT_FLAG) {
+ if (batch_map & MBC_SURFACE_PER_MAT) {
mesh_batch_cache_discard_surface_batches(cache);
}
}
@@ -266,9 +238,9 @@ BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a)
BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *me)
{
- if (me->edit_mesh != NULL) {
+ if (me->edit_mesh != nullptr) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
- if (editmesh_eval_final != NULL) {
+ if (editmesh_eval_final != nullptr) {
return editmesh_eval_final;
}
}
@@ -374,14 +346,15 @@ static void mesh_cd_calc_active_mloopcol_layer(const Object *object,
DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = editmesh_final_or_this(object, me);
- Mesh me_query = {0};
+ Mesh me_query = blender::dna::shallow_zero_initialize();
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
- BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id);
+ BKE_id_attribute_copy_domains_temp(
+ ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id);
int layer_i = BKE_id_attribute_to_index(
&me_query.id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -395,7 +368,7 @@ static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
const CustomData *cd_ldata,
const char name[])
{
- CustomDataLayer *layer = NULL;
+ const CustomDataLayer *layer = nullptr;
eAttrDomain domain;
if (name[0]) {
@@ -451,10 +424,10 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
/* Create a mesh with final customdata domains
* we can query with attribute API. */
- Mesh me_query = {0};
+ Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
- ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, NULL, &me_query.id);
+ ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, nullptr, &me_query.id);
/* See: DM_vertex_attributes_from_gpu for similar logic */
DRW_MeshCDMask cd_used;
@@ -466,10 +439,9 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
ListBase gpu_attrs = GPU_material_attributes(gpumat);
LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
const char *name = gpu_attr->name;
- int type = gpu_attr->type;
+ eCustomDataType type = static_cast<eCustomDataType>(gpu_attr->type);
int layer = -1;
- /* ATTR_DOMAIN_NUM is standard for "invalid value". */
- eAttrDomain domain = ATTR_DOMAIN_NUM;
+ std::optional<eAttrDomain> domain;
if (type == CD_AUTO_FROM_NAME) {
/* We need to deduce what exact layer is used.
@@ -535,7 +507,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
}
else {
layer = -1;
- domain = ATTR_DOMAIN_NUM;
}
}
@@ -602,8 +573,8 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
break;
}
- if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
- drw_attributes_add_request(attributes, type, layer, domain);
+ if (layer != -1 && domain.has_value()) {
+ drw_attributes_add_request(attributes, type, layer, *domain);
}
break;
}
@@ -613,11 +584,13 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
case CD_PROP_INT32:
case CD_PROP_FLOAT:
case CD_PROP_FLOAT2: {
- if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
- drw_attributes_add_request(attributes, type, layer, domain);
+ if (layer != -1 && domain.has_value()) {
+ drw_attributes_add_request(attributes, type, layer, *domain);
}
break;
}
+ default:
+ break;
}
}
}
@@ -654,13 +627,14 @@ static void drw_mesh_weight_state_copy(struct DRW_MeshWeightState *wstate_dst,
memcpy(wstate_dst, wstate_src, sizeof(*wstate_dst));
if (wstate_src->defgroup_sel) {
- wstate_dst->defgroup_sel = MEM_dupallocN(wstate_src->defgroup_sel);
+ wstate_dst->defgroup_sel = static_cast<bool *>(MEM_dupallocN(wstate_src->defgroup_sel));
}
if (wstate_src->defgroup_locked) {
- wstate_dst->defgroup_locked = MEM_dupallocN(wstate_src->defgroup_locked);
+ wstate_dst->defgroup_locked = static_cast<bool *>(MEM_dupallocN(wstate_src->defgroup_locked));
}
if (wstate_src->defgroup_unlocked) {
- wstate_dst->defgroup_unlocked = MEM_dupallocN(wstate_src->defgroup_unlocked);
+ wstate_dst->defgroup_unlocked = static_cast<bool *>(
+ MEM_dupallocN(wstate_src->defgroup_unlocked));
}
}
@@ -764,14 +738,15 @@ BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag
static bool mesh_batch_cache_valid(Object *object, Mesh *me)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
- if (cache == NULL) {
+ if (cache == nullptr) {
return false;
}
if (object->sculpt && object->sculpt->pbvh) {
- if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh)) {
+ if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh) ||
+ BKE_pbvh_draw_cache_invalid(object->sculpt->pbvh)) {
return false;
}
@@ -781,7 +756,7 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me)
}
}
- if (cache->is_editmode != (me->edit_mesh != NULL)) {
+ if (cache->is_editmode != (me->edit_mesh != nullptr)) {
return false;
}
@@ -798,16 +773,17 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me)
static void mesh_batch_cache_init(Object *object, Mesh *me)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
if (!cache) {
- cache = me->runtime.batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ me->runtime.batch_cache = MEM_cnew<MeshBatchCache>(__func__);
+ cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
}
else {
memset(cache, 0, sizeof(*cache));
}
- cache->is_editmode = me->edit_mesh != NULL;
+ cache->is_editmode = me->edit_mesh != nullptr;
if (object->sculpt && object->sculpt->pbvh) {
cache->pbvh_is_drawing = BKE_pbvh_is_drawing(object->sculpt->pbvh);
@@ -821,12 +797,14 @@ static void mesh_batch_cache_init(Object *object, Mesh *me)
}
cache->mat_len = mesh_render_mat_len_get(object, me);
- cache->surface_per_mat = MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__);
- cache->tris_per_mat = MEM_callocN(sizeof(*cache->tris_per_mat) * cache->mat_len, __func__);
+ cache->surface_per_mat = static_cast<GPUBatch **>(
+ MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__));
+ cache->tris_per_mat = static_cast<GPUIndexBuf **>(
+ MEM_callocN(sizeof(*cache->tris_per_mat) * cache->mat_len, __func__));
cache->is_dirty = false;
- cache->batch_ready = 0;
- cache->batch_requested = 0;
+ cache->batch_ready = (DRWBatchFlag)0;
+ cache->batch_requested = (DRWBatchFlag)0;
drw_mesh_weight_state_clear(&cache->weight_state);
}
@@ -841,7 +819,7 @@ void DRW_mesh_batch_cache_validate(Object *object, Mesh *me)
static MeshBatchCache *mesh_batch_cache_get(Mesh *me)
{
- return me->runtime.batch_cache;
+ return static_cast<MeshBatchCache *>(me->runtime.batch_cache);
}
static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache,
@@ -950,8 +928,8 @@ static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache)
void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
- if (cache == NULL) {
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
+ if (cache == nullptr) {
return;
}
DRWBatchFlag batch_map;
@@ -1032,13 +1010,13 @@ static void mesh_batch_cache_free_subdiv_cache(MeshBatchCache *cache)
if (cache->subdiv_cache) {
draw_subdiv_cache_free(cache->subdiv_cache);
MEM_freeN(cache->subdiv_cache);
- cache->subdiv_cache = NULL;
+ cache->subdiv_cache = nullptr;
}
}
static void mesh_batch_cache_clear(Mesh *me)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
if (!cache) {
return;
}
@@ -1061,7 +1039,7 @@ static void mesh_batch_cache_clear(Mesh *me)
MEM_SAFE_FREE(cache->surface_per_mat);
cache->mat_len = 0;
- cache->batch_ready = 0;
+ cache->batch_ready = (DRWBatchFlag)0;
drw_mesh_weight_state_clear(&cache->weight_state);
mesh_batch_cache_free_subdiv_cache(cache);
@@ -1110,11 +1088,12 @@ static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Me
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
- Mesh me_query = {0};
- BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id);
+ Mesh me_query = blender::dna::shallow_zero_initialize();
+ BKE_id_attribute_copy_domains_temp(
+ ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id);
- CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id);
+ const CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id);
int active_i = BKE_id_attribute_to_index(
&me_query.id, active, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -1157,7 +1136,7 @@ GPUBatch *DRW_mesh_batch_cache_get_loose_edges(Mesh *me)
MeshBatchCache *cache = mesh_batch_cache_get(me);
mesh_batch_cache_add_request(cache, MBC_LOOSE_EDGES);
if (cache->no_loose_wire) {
- return NULL;
+ return nullptr;
}
return DRW_batch_request(&cache->batch.loose_edges);
@@ -1276,7 +1255,7 @@ GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *me)
/* Request surface to trigger the vbo filling. Otherwise it may do nothing. */
mesh_batch_cache_request_surface_batches(cache);
- DRW_vbo_request(NULL, &cache->final.buff.vbo.pos_nor);
+ DRW_vbo_request(nullptr, &cache->final.buff.vbo.pos_nor);
return cache->final.buff.vbo.pos_nor;
}
@@ -1398,10 +1377,10 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Object *object,
edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA);
- if (tot_area != NULL) {
+ if (tot_area != nullptr) {
*tot_area = &cache->tot_area;
}
- if (tot_uv_area != NULL) {
+ if (tot_uv_area != nullptr) {
*tot_uv_area = &cache->tot_uv_area;
}
return DRW_batch_request(&cache->batch.edituv_faces_stretch_area);
@@ -1471,9 +1450,9 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Object *object, Mesh *me)
void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
- if (cache == NULL) {
+ if (cache == nullptr) {
return;
}
@@ -1513,7 +1492,7 @@ static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, M
* happening in release builds). */
BLI_task_graph_work_and_wait(task_graph);
for (int i = 0; i < MBC_BATCH_LEN; i++) {
- BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
+ BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], (GPUPrimType)0));
}
for (int i = 0; i < MBC_VBO_LEN; i++) {
BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.buff.vbo)[i]));
@@ -1544,7 +1523,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
const bool use_hide)
{
BLI_assert(task_graph);
- const ToolSettings *ts = NULL;
+ const ToolSettings *ts = nullptr;
if (scene) {
ts = scene->toolsettings;
}
@@ -1559,24 +1538,43 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
return;
}
+#ifdef DEBUG
+ /* Map the index of a buffer to a flag containing all batches that use it. */
+ Map<int, DRWBatchFlag> batches_that_use_buffer_local;
+
+ auto assert_deps_valid = [&](DRWBatchFlag batch_flag, Span<int> used_buffer_indices) {
+ for (const int buffer_index : used_buffer_indices) {
+ batches_that_use_buffer_local.add_or_modify(
+ buffer_index,
+ [&](DRWBatchFlag *value) { *value = batch_flag; },
+ [&](DRWBatchFlag *value) { *value |= batch_flag; });
+ BLI_assert(batches_that_use_buffer(buffer_index) & batch_flag);
+ }
+ };
+#else
+ auto assert_deps_valid = [&](DRWBatchFlag UNUSED(batch_flag),
+ Span<int> UNUSED(used_buffer_indices)) {};
+
+#endif
+
/* Sanity check. */
- if ((me->edit_mesh != NULL) && (ob->mode & OB_MODE_EDIT)) {
- BLI_assert(BKE_object_get_editmesh_eval_final(ob) != NULL);
+ if ((me->edit_mesh != nullptr) && (ob->mode & OB_MODE_EDIT)) {
+ BLI_assert(BKE_object_get_editmesh_eval_final(ob) != nullptr);
}
- const bool is_editmode = (me->edit_mesh != NULL) &&
- (BKE_object_get_editmesh_eval_final(ob) != NULL) &&
+ const bool is_editmode = (me->edit_mesh != nullptr) &&
+ (BKE_object_get_editmesh_eval_final(ob) != nullptr) &&
DRW_object_is_in_edit_mode(ob);
/* This could be set for paint mode too, currently it's only used for edit-mode. */
const bool is_mode_active = is_editmode && DRW_object_is_in_edit_mode(ob);
DRWBatchFlag batch_requested = cache->batch_requested;
- cache->batch_requested = 0;
+ cache->batch_requested = (DRWBatchFlag)0;
if (batch_requested & MBC_SURFACE_WEIGHTS) {
/* Check vertex weights. */
- if ((cache->batch.surface_weights != NULL) && (ts != NULL)) {
+ if ((cache->batch.surface_weights != nullptr) && (ts != nullptr)) {
struct DRW_MeshWeightState wstate;
BLI_assert(ob->type == OB_MESH);
drw_mesh_weight_state_extract(ob, me, ts, is_paint_mode, &wstate);
@@ -1593,7 +1591,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if (cache->cd_needed.orco != 0) {
/* Orco is always extracted from final mesh. */
Mesh *me_final = (me->edit_mesh) ? BKE_object_get_editmesh_eval_final(ob) : me;
- if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) {
+ if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == nullptr) {
/* Skip orco calculation */
cache->cd_needed.orco = 0;
}
@@ -1692,7 +1690,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
* per redraw when smooth shading is enabled. */
const bool do_update_sculpt_normals = ob->sculpt && ob->sculpt->pbvh;
if (do_update_sculpt_normals) {
- Mesh *mesh = ob->data;
+ Mesh *mesh = static_cast<Mesh *>(ob->data);
BKE_pbvh_update_normals(ob->sculpt->pbvh, mesh->runtime.subdiv_ccg);
}
@@ -1712,27 +1710,15 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
MeshBufferList *mbuflist = &cache->final.buff;
/* Initialize batches and request VBO's & IBO's. */
- MDEPS_ASSERT(surface,
- ibo.tris,
- vbo.lnor,
- vbo.pos_nor,
- vbo.uv,
- vbo.vcol,
- vbo.attr[0],
- vbo.attr[1],
- vbo.attr[2],
- vbo.attr[3],
- vbo.attr[4],
- vbo.attr[5],
- vbo.attr[6],
- vbo.attr[7],
- vbo.attr[8],
- vbo.attr[9],
- vbo.attr[10],
- vbo.attr[11],
- vbo.attr[12],
- vbo.attr[13],
- vbo.attr[14]);
+ assert_deps_valid(
+ MBC_SURFACE,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor),
+ BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.attr[0]),
+ BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]), BUFFER_INDEX(vbo.attr[3]),
+ BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]), BUFFER_INDEX(vbo.attr[6]),
+ BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]), BUFFER_INDEX(vbo.attr[9]),
+ BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]), BUFFER_INDEX(vbo.attr[12]),
+ BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])});
if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.surface, &mbuflist->ibo.tris);
/* Order matters. First ones override latest VBO's attributes. */
@@ -1746,52 +1732,61 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
drw_add_attributes_vbo(cache->batch.surface, mbuflist, &cache->attr_used);
}
- MDEPS_ASSERT(all_verts, vbo.pos_nor);
+ assert_deps_valid(MBC_ALL_VERTS, {BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) {
DRW_vbo_request(cache->batch.all_verts, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(sculpt_overlays, ibo.tris, vbo.pos_nor, vbo.sculpt_data);
+ assert_deps_valid(
+ MBC_SCULPT_OVERLAYS,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.sculpt_data)});
if (DRW_batch_requested(cache->batch.sculpt_overlays, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.sculpt_overlays, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.sculpt_data);
}
- MDEPS_ASSERT(all_edges, ibo.lines, vbo.pos_nor);
+ assert_deps_valid(MBC_ALL_EDGES, {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.all_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.all_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.all_edges, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(loose_edges, ibo.lines_loose, vbo.pos_nor);
+ assert_deps_valid(MBC_LOOSE_EDGES, {BUFFER_INDEX(ibo.lines_loose), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(NULL, &mbuflist->ibo.lines);
+ DRW_ibo_request(nullptr, &mbuflist->ibo.lines);
DRW_ibo_request(cache->batch.loose_edges, &mbuflist->ibo.lines_loose);
DRW_vbo_request(cache->batch.loose_edges, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(edge_detection, ibo.lines_adjacency, vbo.pos_nor);
+ assert_deps_valid(MBC_EDGE_DETECTION,
+ {BUFFER_INDEX(ibo.lines_adjacency), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) {
DRW_ibo_request(cache->batch.edge_detection, &mbuflist->ibo.lines_adjacency);
DRW_vbo_request(cache->batch.edge_detection, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(surface_weights, ibo.tris, vbo.pos_nor, vbo.weights);
+ assert_deps_valid(
+ MBC_SURFACE_WEIGHTS,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.weights)});
if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.surface_weights, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.weights);
}
- MDEPS_ASSERT(wire_loops, ibo.lines_paint_mask, vbo.lnor, vbo.pos_nor);
+ assert_deps_valid(
+ MBC_WIRE_LOOPS,
+ {BUFFER_INDEX(ibo.lines_paint_mask), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_loops, &mbuflist->ibo.lines_paint_mask);
/* Order matters. First ones override latest VBO's attributes. */
DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.lnor);
DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(wire_edges, ibo.lines, vbo.pos_nor, vbo.edge_fac);
+ assert_deps_valid(
+ MBC_WIRE_EDGES,
+ {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_fac)});
if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.edge_fac);
}
- MDEPS_ASSERT(wire_loops_uvs, ibo.edituv_lines, vbo.uv);
+ assert_deps_valid(MBC_WIRE_LOOPS_UVS, {BUFFER_INDEX(ibo.edituv_lines), BUFFER_INDEX(vbo.uv)});
if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_loops_uvs, &mbuflist->ibo.edituv_lines);
/* For paint overlay. Active layer should have been queried. */
@@ -1799,7 +1794,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
DRW_vbo_request(cache->batch.wire_loops_uvs, &mbuflist->vbo.uv);
}
}
- MDEPS_ASSERT(edit_mesh_analysis, ibo.tris, vbo.pos_nor, vbo.mesh_analysis);
+ assert_deps_valid(
+ MBC_EDIT_MESH_ANALYSIS,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.mesh_analysis)});
if (DRW_batch_requested(cache->batch.edit_mesh_analysis, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_mesh_analysis, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbuflist->vbo.pos_nor);
@@ -1807,29 +1804,16 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
/* Per Material */
- MDEPS_ASSERT_FLAG(SURFACE_PER_MAT_FLAG,
- vbo.lnor,
- vbo.pos_nor,
- vbo.uv,
- vbo.tan,
- vbo.vcol,
- vbo.orco,
- vbo.attr[0],
- vbo.attr[1],
- vbo.attr[2],
- vbo.attr[3],
- vbo.attr[4],
- vbo.attr[5],
- vbo.attr[6],
- vbo.attr[7],
- vbo.attr[8],
- vbo.attr[9],
- vbo.attr[10],
- vbo.attr[11],
- vbo.attr[12],
- vbo.attr[13],
- vbo.attr[14]);
- MDEPS_ASSERT_INDEX(TRIS_PER_MAT_INDEX, SURFACE_PER_MAT_FLAG);
+ assert_deps_valid(
+ MBC_SURFACE_PER_MAT,
+ {BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.uv),
+ BUFFER_INDEX(vbo.tan), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.orco),
+ BUFFER_INDEX(vbo.attr[0]), BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]),
+ BUFFER_INDEX(vbo.attr[3]), BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]),
+ BUFFER_INDEX(vbo.attr[6]), BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]),
+ BUFFER_INDEX(vbo.attr[9]), BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]),
+ BUFFER_INDEX(vbo.attr[12]), BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])});
+ assert_deps_valid(MBC_SURFACE_PER_MAT, {TRIS_PER_MAT_INDEX});
for (int i = 0; i < cache->mat_len; i++) {
if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->surface_per_mat[i], &cache->tris_per_mat[i]);
@@ -1855,66 +1839,83 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mbuflist = (do_cage) ? &cache->cage.buff : &cache->final.buff;
/* Edit Mesh */
- MDEPS_ASSERT(edit_triangles, ibo.tris, vbo.pos_nor, vbo.edit_data);
+ assert_deps_valid(
+ MBC_EDIT_TRIANGLES,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_triangles, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.edit_data);
}
- MDEPS_ASSERT(edit_vertices, ibo.points, vbo.pos_nor, vbo.edit_data);
+ assert_deps_valid(
+ MBC_EDIT_VERTICES,
+ {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_vertices, &mbuflist->ibo.points);
DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.edit_data);
}
- MDEPS_ASSERT(edit_edges, ibo.lines, vbo.pos_nor, vbo.edit_data);
+ assert_deps_valid(
+ MBC_EDIT_EDGES,
+ {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edit_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.edit_data);
}
- MDEPS_ASSERT(edit_vnor, ibo.points, vbo.pos_nor);
+ assert_deps_valid(MBC_EDIT_VNOR, {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.edit_vnor, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_vnor, &mbuflist->ibo.points);
DRW_vbo_request(cache->batch.edit_vnor, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(edit_lnor, ibo.tris, vbo.pos_nor, vbo.lnor);
+ assert_deps_valid(MBC_EDIT_LNOR,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.lnor)});
if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_lnor, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.lnor);
}
- MDEPS_ASSERT(edit_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdots_nor);
+ assert_deps_valid(
+ MBC_EDIT_FACEDOTS,
+ {BUFFER_INDEX(ibo.fdots), BUFFER_INDEX(vbo.fdots_pos), BUFFER_INDEX(vbo.fdots_nor)});
if (DRW_batch_requested(cache->batch.edit_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_fdots, &mbuflist->ibo.fdots);
DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_pos);
DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_nor);
}
- MDEPS_ASSERT(edit_skin_roots, vbo.skin_roots);
+ assert_deps_valid(MBC_SKIN_ROOTS, {BUFFER_INDEX(vbo.skin_roots)});
if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_POINTS)) {
DRW_vbo_request(cache->batch.edit_skin_roots, &mbuflist->vbo.skin_roots);
}
/* Selection */
- MDEPS_ASSERT(edit_selection_verts, ibo.points, vbo.pos_nor, vbo.vert_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_VERTS,
+ {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.vert_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_selection_verts, &mbuflist->ibo.points);
DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.vert_idx);
}
- MDEPS_ASSERT(edit_selection_edges, ibo.lines, vbo.pos_nor, vbo.edge_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_EDGES,
+ {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edit_selection_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.edge_idx);
}
- MDEPS_ASSERT(edit_selection_faces, ibo.tris, vbo.pos_nor, vbo.poly_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_FACES,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.poly_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_selection_faces, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.poly_idx);
}
- MDEPS_ASSERT(edit_selection_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdot_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_FACEDOTS,
+ {BUFFER_INDEX(ibo.fdots), BUFFER_INDEX(vbo.fdots_pos), BUFFER_INDEX(vbo.fdot_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_selection_fdots, &mbuflist->ibo.fdots);
DRW_vbo_request(cache->batch.edit_selection_fdots, &mbuflist->vbo.fdots_pos);
@@ -1929,131 +1930,145 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mbuflist = (do_uvcage) ? &cache->uv_cage.buff : &cache->final.buff;
/* Edit UV */
- MDEPS_ASSERT(edituv_faces, ibo.edituv_tris, vbo.uv, vbo.edituv_data);
+ assert_deps_valid(
+ MBC_EDITUV_FACES,
+ {BUFFER_INDEX(ibo.edituv_tris), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces, &mbuflist->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.edituv_data);
}
- MDEPS_ASSERT(edituv_faces_stretch_area,
- ibo.edituv_tris,
- vbo.uv,
- vbo.edituv_data,
- vbo.edituv_stretch_area);
+ assert_deps_valid(MBC_EDITUV_FACES_STRETCH_AREA,
+ {BUFFER_INDEX(ibo.edituv_tris),
+ BUFFER_INDEX(vbo.uv),
+ BUFFER_INDEX(vbo.edituv_data),
+ BUFFER_INDEX(vbo.edituv_stretch_area)});
if (DRW_batch_requested(cache->batch.edituv_faces_stretch_area, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_data);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_stretch_area);
}
- MDEPS_ASSERT(edituv_faces_stretch_angle,
- ibo.edituv_tris,
- vbo.uv,
- vbo.edituv_data,
- vbo.edituv_stretch_angle);
+ assert_deps_valid(MBC_EDITUV_FACES_STRETCH_ANGLE,
+ {BUFFER_INDEX(ibo.edituv_tris),
+ BUFFER_INDEX(vbo.uv),
+ BUFFER_INDEX(vbo.edituv_data),
+ BUFFER_INDEX(vbo.edituv_stretch_angle)});
if (DRW_batch_requested(cache->batch.edituv_faces_stretch_angle, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_data);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_stretch_angle);
}
- MDEPS_ASSERT(edituv_edges, ibo.edituv_lines, vbo.uv, vbo.edituv_data);
+ assert_deps_valid(
+ MBC_EDITUV_EDGES,
+ {BUFFER_INDEX(ibo.edituv_lines), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edituv_edges, &mbuflist->ibo.edituv_lines);
DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.edituv_data);
}
- MDEPS_ASSERT(edituv_verts, ibo.edituv_points, vbo.uv, vbo.edituv_data);
+ assert_deps_valid(
+ MBC_EDITUV_VERTS,
+ {BUFFER_INDEX(ibo.edituv_points), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edituv_verts, &mbuflist->ibo.edituv_points);
DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.edituv_data);
}
- MDEPS_ASSERT(edituv_fdots, ibo.edituv_fdots, vbo.fdots_uv, vbo.fdots_edituv_data);
+ assert_deps_valid(MBC_EDITUV_FACEDOTS,
+ {BUFFER_INDEX(ibo.edituv_fdots),
+ BUFFER_INDEX(vbo.fdots_uv),
+ BUFFER_INDEX(vbo.fdots_edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edituv_fdots, &mbuflist->ibo.edituv_fdots);
DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_uv);
DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_edituv_data);
}
- MDEPS_ASSERT_MAP(vbo.lnor);
- MDEPS_ASSERT_MAP(vbo.pos_nor);
- MDEPS_ASSERT_MAP(vbo.uv);
- MDEPS_ASSERT_MAP(vbo.vcol);
- MDEPS_ASSERT_MAP(vbo.sculpt_data);
- MDEPS_ASSERT_MAP(vbo.weights);
- MDEPS_ASSERT_MAP(vbo.edge_fac);
- MDEPS_ASSERT_MAP(vbo.mesh_analysis);
- MDEPS_ASSERT_MAP(vbo.tan);
- MDEPS_ASSERT_MAP(vbo.orco);
- MDEPS_ASSERT_MAP(vbo.edit_data);
- MDEPS_ASSERT_MAP(vbo.fdots_pos);
- MDEPS_ASSERT_MAP(vbo.fdots_nor);
- MDEPS_ASSERT_MAP(vbo.skin_roots);
- MDEPS_ASSERT_MAP(vbo.vert_idx);
- MDEPS_ASSERT_MAP(vbo.edge_idx);
- MDEPS_ASSERT_MAP(vbo.poly_idx);
- MDEPS_ASSERT_MAP(vbo.fdot_idx);
- MDEPS_ASSERT_MAP(vbo.edituv_data);
- MDEPS_ASSERT_MAP(vbo.edituv_stretch_area);
- MDEPS_ASSERT_MAP(vbo.edituv_stretch_angle);
- MDEPS_ASSERT_MAP(vbo.fdots_uv);
- MDEPS_ASSERT_MAP(vbo.fdots_edituv_data);
- for (int i = 0; i < GPU_MAX_ATTR; i++) {
- MDEPS_ASSERT_MAP(vbo.attr[i]);
- }
-
- MDEPS_ASSERT_MAP(ibo.tris);
- MDEPS_ASSERT_MAP(ibo.lines);
- MDEPS_ASSERT_MAP(ibo.lines_loose);
- MDEPS_ASSERT_MAP(ibo.lines_adjacency);
- MDEPS_ASSERT_MAP(ibo.lines_paint_mask);
- MDEPS_ASSERT_MAP(ibo.points);
- MDEPS_ASSERT_MAP(ibo.fdots);
- MDEPS_ASSERT_MAP(ibo.edituv_tris);
- MDEPS_ASSERT_MAP(ibo.edituv_lines);
- MDEPS_ASSERT_MAP(ibo.edituv_points);
- MDEPS_ASSERT_MAP(ibo.edituv_fdots);
-
- MDEPS_ASSERT_MAP_INDEX(TRIS_PER_MAT_INDEX);
+#ifdef DEBUG
+ auto assert_final_deps_valid = [&](const int buffer_index) {
+ BLI_assert(batches_that_use_buffer(buffer_index) ==
+ batches_that_use_buffer_local.lookup(buffer_index));
+ };
+ assert_final_deps_valid(BUFFER_INDEX(vbo.lnor));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.pos_nor));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.uv));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.vcol));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.sculpt_data));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.weights));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edge_fac));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.mesh_analysis));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.tan));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.orco));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edit_data));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_pos));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_nor));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.skin_roots));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.vert_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edge_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.poly_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdot_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_data));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_stretch_area));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_stretch_angle));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_uv));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_edituv_data));
+ for (const int i : IndexRange(GPU_MAX_ATTR)) {
+ assert_final_deps_valid(BUFFER_INDEX(vbo.attr[i]));
+ }
+
+ assert_final_deps_valid(BUFFER_INDEX(ibo.tris));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines_loose));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines_adjacency));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines_paint_mask));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.points));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.fdots));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_tris));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_lines));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_points));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_fdots));
+
+ assert_final_deps_valid(TRIS_PER_MAT_INDEX);
+#endif
if (do_uvcage) {
- mesh_buffer_cache_create_requested(task_graph,
- cache,
- &cache->uv_cage,
- ob,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- ob->obmat,
- false,
- true,
- scene,
- ts,
- true);
+ blender::draw::mesh_buffer_cache_create_requested(task_graph,
+ cache,
+ &cache->uv_cage,
+ ob,
+ me,
+ is_editmode,
+ is_paint_mode,
+ is_mode_active,
+ ob->obmat,
+ false,
+ true,
+ scene,
+ ts,
+ true);
}
if (do_cage) {
- mesh_buffer_cache_create_requested(task_graph,
- cache,
- &cache->cage,
- ob,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- ob->obmat,
- false,
- false,
- scene,
- ts,
- true);
+ blender::draw::mesh_buffer_cache_create_requested(task_graph,
+ cache,
+ &cache->cage,
+ ob,
+ me,
+ is_editmode,
+ is_paint_mode,
+ is_mode_active,
+ ob->obmat,
+ false,
+ false,
+ scene,
+ ts,
+ true);
}
if (do_subdivision) {
- DRW_create_subdivision(scene,
- ob,
+ DRW_create_subdivision(ob,
me,
cache,
&cache->final,
@@ -2072,20 +2087,20 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mesh_batch_cache_free_subdiv_cache(cache);
}
- mesh_buffer_cache_create_requested(task_graph,
- cache,
- &cache->final,
- ob,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- ob->obmat,
- true,
- false,
- scene,
- ts,
- use_hide);
+ blender::draw::mesh_buffer_cache_create_requested(task_graph,
+ cache,
+ &cache->final,
+ ob,
+ me,
+ is_editmode,
+ is_paint_mode,
+ is_mode_active,
+ ob->obmat,
+ true,
+ false,
+ scene,
+ ts,
+ use_hide);
/* Ensure that all requested batches have finished.
* Ideally we want to remove this sync, but there are cases where this doesn't work.
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 0cee50ec8b0..b37a420b555 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -39,10 +39,10 @@
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
-#include "draw_cache_extract.h"
+#include "draw_cache_extract.hh"
#include "draw_cache_impl.h"
#include "draw_cache_inline.h"
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
extern "C" char datatoc_common_subdiv_custom_data_interp_comp_glsl[];
extern "C" char datatoc_common_subdiv_ibo_lines_comp_glsl[];
@@ -221,7 +221,7 @@ static GPUShader *get_patch_evaluation_shader(int shader_type)
"#define OSD_PATCH_BASIS_GLSL\n"
"#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
"#define FDOTS_EVALUATION\n"
- "#define FOTS_NORMALS\n";
+ "#define FDOTS_NORMALS\n";
}
else if (shader_type == SHADER_PATCH_EVALUATION_ORCO) {
defines =
@@ -867,10 +867,10 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
ctx->subdiv_loop_subdiv_edge_index = cache->subdiv_loop_subdiv_edge_index;
ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index;
- ctx->v_origindex = static_cast<int *>(
+ ctx->v_origindex = static_cast<const int *>(
CustomData_get_layer(&ctx->coarse_mesh->vdata, CD_ORIGINDEX));
- ctx->e_origindex = static_cast<int *>(
+ ctx->e_origindex = static_cast<const int *>(
CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX));
if (cache->num_subdiv_verts) {
@@ -1052,14 +1052,10 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache)
static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
Subdiv *subdiv,
Mesh *mesh_eval,
- const Scene *scene,
- const SubsurfModifierData *smd,
- const bool is_final_render)
+ const SubsurfRuntimeData *runtime_data)
{
- const int requested_levels = (is_final_render) ? smd->renderLevels : smd->levels;
- const int level = get_render_subsurf_level(&scene->r, requested_levels, is_final_render);
SubdivToMeshSettings to_mesh_settings;
- to_mesh_settings.resolution = (1 << level) + 1;
+ to_mesh_settings.resolution = runtime_data->resolution;
to_mesh_settings.use_optimal_display = false;
if (cache->resolution != to_mesh_settings.resolution) {
@@ -1837,6 +1833,7 @@ void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++);
/* Outputs */
GPU_vertbuf_bind_as_ssbo(lnor, binding_point++);
@@ -2005,8 +2002,7 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache,
MEM_freeN(per_polygon_mat_offset);
}
-static bool draw_subdiv_create_requested_buffers(const Scene *scene,
- Object *ob,
+static bool draw_subdiv_create_requested_buffers(Object *ob,
Mesh *mesh,
struct MeshBatchCache *batch_cache,
MeshBufferCache *mbc,
@@ -2020,16 +2016,10 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
const bool use_hide,
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
- SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>(
- BKE_modifiers_findby_session_uuid(ob, &mesh->runtime.subsurf_session_uuid));
- BLI_assert(smd);
-
- const bool is_final_render = DRW_state_is_scene_render();
+ SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
+ BLI_assert(runtime_data && runtime_data->has_gpu_subdiv);
- SubdivSettings settings;
- BKE_subsurf_modifier_subdiv_settings_init(&settings, smd, is_final_render);
-
- if (settings.level == 0) {
+ if (runtime_data->settings.level == 0) {
return false;
}
@@ -2040,9 +2030,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
bm = mesh->edit_mesh->bm;
}
- BKE_subsurf_modifier_ensure_runtime(smd);
-
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh_eval, true);
if (!subdiv) {
return false;
}
@@ -2063,13 +2051,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
}
DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache);
- if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, scene, smd, is_final_render)) {
+ if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, runtime_data)) {
return false;
}
/* Edges which do not come from coarse edges should not be drawn in edit mode, only in object
* mode when optimal display in turned off. */
- const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges) || is_editmode;
+ const bool optimal_display = runtime_data->use_optimal_display || is_editmode;
draw_cache->bm = bm;
draw_cache->mesh = mesh_eval;
@@ -2077,14 +2065,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
draw_cache->optimal_display = optimal_display;
draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops);
- /* Copy topology information for stats display. Use `mesh` directly, as `mesh_eval` could be the
- * edit mesh. */
- mesh->runtime.subsurf_totvert = draw_cache->num_subdiv_verts;
- mesh->runtime.subsurf_totedge = draw_cache->num_subdiv_edges;
- mesh->runtime.subsurf_totpoly = draw_cache->num_subdiv_quads;
- mesh->runtime.subsurf_totloop = draw_cache->num_subdiv_loops;
+ /* Copy topology information for stats display. */
+ runtime_data->stats_totvert = draw_cache->num_subdiv_verts;
+ runtime_data->stats_totedge = draw_cache->num_subdiv_edges;
+ runtime_data->stats_totpoly = draw_cache->num_subdiv_quads;
+ runtime_data->stats_totloop = draw_cache->num_subdiv_loops;
- draw_cache->use_custom_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) &&
+ draw_cache->use_custom_loop_normals = (runtime_data->use_loop_normals) &&
(mesh_eval->flag & ME_AUTOSMOOTH) &&
CustomData_has_layer(&mesh_eval->ldata,
CD_CUSTOMLOOPNORMAL);
@@ -2099,7 +2086,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
draw_subdiv_cache_update_extra_coarse_face_data(draw_cache, mesh_eval, mr);
- mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr);
+ blender::draw::mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr);
mesh_render_data_free(mr);
@@ -2206,8 +2193,7 @@ blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWS
static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr;
-void DRW_create_subdivision(const Scene *scene,
- Object *ob,
+void DRW_create_subdivision(Object *ob,
Mesh *mesh,
struct MeshBatchCache *batch_cache,
MeshBufferCache *mbc,
@@ -2230,8 +2216,7 @@ void DRW_create_subdivision(const Scene *scene,
const double begin_time = PIL_check_seconds_timer();
#endif
- if (!draw_subdiv_create_requested_buffers(scene,
- ob,
+ if (!draw_subdiv_create_requested_buffers(ob,
mesh,
batch_cache,
mbc,
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index b6b0c94f4bf..d31c98e0dee 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -93,7 +93,7 @@ void DRW_curves_free(void);
/**
* Add attributes bindings of volume grids to an existing shading group.
* No draw call is added so the caller can decide how to use the data.
- * \return nullptr if there is something to draw.
+ * \return nullptr if there is nothing to draw.
*/
struct DRWShadingGroup *DRW_shgroup_volume_create_sub(struct Scene *scene,
struct Object *ob,
diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc
index 39d4845994f..c40f2275968 100644
--- a/source/blender/draw/intern/draw_curves.cc
+++ b/source/blender/draw/intern/draw_curves.cc
@@ -13,6 +13,9 @@
#include "DNA_curves_types.h"
#include "DNA_customdata_types.h"
+#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
+
#include "GPU_batch.h"
#include "GPU_capabilities.h"
#include "GPU_compute.h"
@@ -325,6 +328,28 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
float hair_rad_tip = 0.0f;
bool hair_close_tip = true;
+ /* Use the radius of the root and tip of the first curve for now. This is a workaround that we
+ * use for now because we can't use a per-point radius yet. */
+ Curves &curves_id = *static_cast<Curves *>(object->data);
+ const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
+ curves_id.geometry);
+ if (curves.curves_num() >= 1) {
+ CurveComponent curves_component;
+ curves_component.replace(&curves_id, GeometryOwnershipType::ReadOnly);
+ blender::VArray<float> radii = curves_component.attribute_get_for_read(
+ "radius", ATTR_DOMAIN_POINT, 0.005f);
+ const blender::IndexRange first_curve_points = curves.points_for_curve(0);
+ const float first_radius = radii[first_curve_points.first()];
+ const float last_radius = radii[first_curve_points.last()];
+ const float middle_radius = radii[first_curve_points.size() / 2];
+ hair_rad_root = radii[first_curve_points.first()];
+ hair_rad_tip = radii[first_curve_points.last()];
+ hair_rad_shape = std::clamp(
+ safe_divide(middle_radius - first_radius, last_radius - first_radius) * 2.0f - 1.0f,
+ -1.0f,
+ 1.0f);
+ }
+
DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_tex);
if (curves_cache->length_tex) {
DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex);
diff --git a/source/blender/draw/intern/draw_curves_private.h b/source/blender/draw/intern/draw_curves_private.h
index ed4dd50dfbe..7d54e1089d6 100644
--- a/source/blender/draw/intern/draw_curves_private.h
+++ b/source/blender/draw/intern/draw_curves_private.h
@@ -35,22 +35,26 @@ typedef struct CurvesEvalFinalCache {
GPUVertBuf *proc_buf;
GPUTexture *proc_tex;
- /* Just contains a huge index buffer used to draw the final curves. */
+ /** Just contains a huge index buffer used to draw the final curves. */
GPUBatch *proc_hairs[MAX_THICKRES];
- /* Points per curve, at least 2. */
+ /** Points per curve, at least 2. */
int strands_res;
- /* Attributes currently being or about to be drawn. */
+ /** Attributes currently being drawn or about to be drawn. */
DRW_Attributes attr_used;
- /* Attributes which were used at some point. This is used for garbage collection, to remove
- * attributes which are not used in shaders anymore due to user edits. */
+ /**
+ * Attributes that were used at some point. This is used for garbage collection, to remove
+ * attributes that are not used in shaders anymore due to user edits.
+ */
DRW_Attributes attr_used_over_time;
- /* Last time, in seconds, the `attr_used` and `attr_used_over_time` were exactly the same.
+ /**
+ * The last time in seconds that the `attr_used` and `attr_used_over_time` were exactly the same.
* If the delta between this time and the current scene time is greater than the timeout set in
- * user preferences (`U.vbotimeout`) then garbage collection is performed. */
+ * user preferences (`U.vbotimeout`) then garbage collection is performed.
+ */
int last_attr_matching_time;
/* Output of the subdivision stage: vertex buffers sized to subdiv level. This is only attributes
@@ -61,7 +65,7 @@ typedef struct CurvesEvalFinalCache {
/* Curves procedural display: Evaluation is done on the GPU. */
typedef struct CurvesEvalCache {
- /* Input control points */
+ /* Input control point positions combined with parameter data. */
GPUVertBuf *proc_point_buf;
GPUTexture *point_tex;
@@ -78,8 +82,8 @@ typedef struct CurvesEvalCache {
CurvesEvalFinalCache final[MAX_HAIR_SUBDIV];
- /* For point attributes, which need subdivision, these are the input data.
- * For spline attributes, which need not subdivision, these are the final data. */
+ /* For point attributes, which need subdivision, these buffers contain the input data.
+ * For curve domain attributes, which do not need subdivision, these are the final data. */
GPUVertBuf *proc_attributes_buf[GPU_MAX_ATTR];
GPUTexture *proc_attributes_tex[GPU_MAX_ATTR];
@@ -89,7 +93,7 @@ typedef struct CurvesEvalCache {
} CurvesEvalCache;
/**
- * Ensure all textures and buffers needed for GPU accelerated drawing.
+ * Ensure all necessary textures and buffers exist for GPU accelerated drawing.
*/
bool curves_ensure_procedural_data(struct Object *object,
struct CurvesEvalCache **r_hair_cache,
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index f0960c5324b..188d9114cd7 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -1238,7 +1238,8 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd)
&update_frustum,
&draw_frustum,
(void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb,
- scd);
+ scd,
+ scd->use_mats);
if (SCULPT_DEBUG_BUFFERS) {
int debug_node_nr = 0;
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
index 8920a2dcd51..2d9f4713feb 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -185,8 +185,7 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache);
/** \} */
-void DRW_create_subdivision(const struct Scene *scene,
- struct Object *ob,
+void DRW_create_subdivision(struct Object *ob,
struct Mesh *mesh,
struct MeshBatchCache *batch_cache,
struct MeshBufferCache *mbc,
diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc
index 8d9a6f486e2..c4e58ab24cb 100644
--- a/source/blender/draw/intern/draw_volume.cc
+++ b/source/blender/draw/intern/draw_volume.cc
@@ -129,12 +129,14 @@ static DRWShadingGroup *drw_volume_object_grids_init(Object *ob,
volume_infos.temperature_bias = 0.0f;
/* Bind volume grid textures. */
- int grid_id = 0;
+ int grid_id = 0, grids_len = 0;
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) {
const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, attr->name);
const DRWVolumeGrid *drw_grid = (volume_grid) ?
DRW_volume_batch_cache_get_grid(volume, volume_grid) :
nullptr;
+ /* Count number of valid attributes. */
+ grids_len += int(volume_grid != nullptr);
/* Handle 3 cases here:
* - Grid exists and texture was loaded -> use texture.
@@ -145,7 +147,13 @@ static DRWShadingGroup *drw_volume_object_grids_init(Object *ob,
grid_default_texture(attr->default_value);
DRW_shgroup_uniform_texture(grp, attr->input_name, grid_tex);
- copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(), drw_grid->object_to_texture);
+ copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(),
+ (drw_grid) ? drw_grid->object_to_texture : g_data.dummy_grid_mat);
+ }
+ /* Render nothing if there is no attribute for the shader to render.
+ * This also avoids an assert caused by the bounding box being zero in size. */
+ if (grids_len == 0) {
+ return nullptr;
}
volume_infos.push_update();
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.c b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc
index 9dc82fa3d32..ec7d3a933b4 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.c
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc
@@ -13,7 +13,7 @@
#include "ED_uvedit.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -29,7 +29,7 @@ void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuf
eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
{
- eMRIterType type = 0;
+ eMRIterType type = (eMRIterType)0;
SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI);
SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY);
SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE);
@@ -128,7 +128,7 @@ void mesh_render_data_loop_flag(const MeshRenderData *mr,
return;
}
MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_ofs);
- if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) {
+ if (luv != nullptr && (luv->flag & MLOOPUV_PINNED)) {
eattr->v_flag |= VFLAG_VERT_UV_PINNED;
}
if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) {
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
index b88cd9e77d2..8052b277d45 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
@@ -17,11 +17,7 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
-#include "draw_cache_extract.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "draw_cache_extract.hh"
struct DRWSubdivCache;
@@ -31,13 +27,13 @@ struct DRWSubdivCache;
/** \name Mesh Render Data
* \{ */
-typedef enum eMRExtractType {
+enum eMRExtractType {
MR_EXTRACT_BMESH,
MR_EXTRACT_MAPPED,
MR_EXTRACT_MESH,
-} eMRExtractType;
+};
-typedef struct MeshRenderData {
+struct MeshRenderData {
eMRExtractType extract_type;
int poly_len, edge_len, vert_len, loop_len;
@@ -95,7 +91,7 @@ typedef struct MeshRenderData {
int *mat_tri_len;
int visible_tri_len;
} poly_sorted;
-} MeshRenderData;
+};
BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
{
@@ -159,71 +155,71 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e
/* TODO(jbakker): move parameters inside a struct. */
-typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data);
-typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
- const MLoopTri *mlt,
- int elt_index,
- void *data);
-typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
- const BMFace *f,
- int f_index,
- void *data);
-typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
- const MPoly *mp,
- int mp_index,
+using ExtractTriBMeshFn = void(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data);
+using ExtractTriMeshFn = void(const MeshRenderData *mr,
+ const MLoopTri *mlt,
+ int elt_index,
+ void *data);
+using ExtractPolyBMeshFn = void(const MeshRenderData *mr,
+ const BMFace *f,
+ int f_index,
void *data);
-typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
- const BMEdge *eed,
- int ledge_index,
- void *data);
-typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
- const MEdge *med,
+using ExtractPolyMeshFn = void(const MeshRenderData *mr,
+ const MPoly *mp,
+ int mp_index,
+ void *data);
+using ExtractLEdgeBMeshFn = void(const MeshRenderData *mr,
+ const BMEdge *eed,
int ledge_index,
void *data);
-typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
- const BMVert *eve,
- int lvert_index,
- void *data);
-typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
- const MVert *mv,
+using ExtractLEdgeMeshFn = void(const MeshRenderData *mr,
+ const MEdge *med,
+ int ledge_index,
+ void *data);
+using ExtractLVertBMeshFn = void(const MeshRenderData *mr,
+ const BMVert *eve,
int lvert_index,
void *data);
-typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
- void *buffer,
- void *data);
-typedef void(ExtractInitFn)(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buffer,
- void *r_data);
-typedef void(ExtractFinishFn)(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buffer,
- void *data);
-typedef void(ExtractTaskReduceFn)(void *userdata, void *task_userdata);
-
-typedef void(ExtractInitSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *data);
-typedef void(ExtractIterSubdivBMeshFn)(const struct DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
- void *data,
- uint subdiv_quad_index,
- const BMFace *coarse_quad);
-typedef void(ExtractIterSubdivMeshFn)(const struct DRWSubdivCache *subdiv_cache,
+using ExtractLVertMeshFn = void(const MeshRenderData *mr,
+ const MVert *mv,
+ int lvert_index,
+ void *data);
+using ExtractLooseGeomSubdivFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *buffer,
+ void *data);
+using ExtractInitFn = void(const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buffer,
+ void *r_data);
+using ExtractFinishFn = void(const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buffer,
+ void *data);
+using ExtractTaskReduceFn = void(void *userdata, void *task_userdata);
+
+using ExtractInitSubdivFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buf,
+ void *data);
+using ExtractIterSubdivBMeshFn = void(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
void *data,
uint subdiv_quad_index,
- const MPoly *coarse_quad);
-typedef void(ExtractFinishSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *data);
-
-typedef struct MeshExtract {
+ const BMFace *coarse_quad);
+using ExtractIterSubdivMeshFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad);
+using ExtractFinishSubdivFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buf,
+ void *data);
+
+struct MeshExtract {
/** Executed on main thread and return user data for iteration functions. */
ExtractInitFn *init;
/** Executed on one (or more if use_threading) worker thread(s). */
@@ -254,7 +250,7 @@ typedef struct MeshExtract {
* buffer.
*/
size_t mesh_buffer_offset;
-} MeshExtract;
+};
/** \} */
@@ -291,14 +287,14 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
/* draw_cache_extract_mesh_extractors.c */
-typedef struct EditLoopData {
+struct EditLoopData {
uchar v_flag;
uchar e_flag;
/* This is used for both vertex and edge creases. The edge crease value is stored in the bottom 4
* bits, while the vertex crease is stored in the upper 4 bits. */
uchar crease;
uchar bweight;
-} EditLoopData;
+};
void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist);
eMRIterType mesh_extract_iter_type(const MeshExtract *ext);
@@ -359,7 +355,3 @@ extern const MeshExtract extract_edge_idx;
extern const MeshExtract extract_vert_idx;
extern const MeshExtract extract_fdot_idx;
extern const MeshExtract extract_attr[GPU_MAX_ATTR];
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
index 2c4e7bfa802..9824602b129 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -584,9 +584,7 @@ constexpr MeshExtract create_extractor_edituv_fdots()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_tris = blender::draw::create_extractor_edituv_tris();
const MeshExtract extract_edituv_lines = blender::draw::create_extractor_edituv_lines();
const MeshExtract extract_edituv_points = blender::draw::create_extractor_edituv_points();
const MeshExtract extract_edituv_fdots = blender::draw::create_extractor_edituv_fdots();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
index 4bf732caf0a..4eebea1b79f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -95,6 +95,4 @@ constexpr MeshExtract create_extractor_fdots()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots = blender::draw::create_extractor_fdots();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
index 3cecaf81b8a..4e89b34c0a0 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
@@ -7,7 +7,7 @@
#include "MEM_guardedalloc.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -183,10 +183,18 @@ static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
uint *flags_data = static_cast<uint *>(GPU_vertbuf_get_data(flags));
- const MEdge *medge = mr->medge;
-
- for (DRWSubdivLooseEdge edge : loose_edges) {
- *flags_data++ = (medge[edge.coarse_edge_index].flag & ME_HIDE) != 0;
+ if (mr->extract_type == MR_EXTRACT_MESH) {
+ const MEdge *medge = mr->medge;
+ for (DRWSubdivLooseEdge edge : loose_edges) {
+ *flags_data++ = (medge[edge.coarse_edge_index].flag & ME_HIDE) != 0;
+ }
+ }
+ else {
+ BMesh *bm = mr->bm;
+ for (DRWSubdivLooseEdge edge : loose_edges) {
+ const BMEdge *bm_edge = BM_edge_at_index(bm, edge.coarse_edge_index);
+ *flags_data++ = BM_elem_flag_test_bool(bm_edge, BM_ELEM_HIDDEN) != 0;
+ }
}
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
@@ -320,9 +328,7 @@ constexpr MeshExtract create_extractor_lines_loose_only()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_lines = blender::draw::create_extractor_lines();
const MeshExtract extract_lines_with_lines_loose =
blender::draw::create_extractor_lines_with_lines_loose();
const MeshExtract extract_lines_loose_only = blender::draw::create_extractor_lines_loose_only();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
index de464fb286f..9ba9453dada 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
@@ -11,7 +11,7 @@
#include "MEM_guardedalloc.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -253,6 +253,4 @@ constexpr MeshExtract create_extractor_lines_adjacency()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_lines_adjacency = blender::draw::create_extractor_lines_adjacency();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
index 286c7ea9c43..713a533492f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
@@ -12,7 +12,7 @@
#include "MEM_guardedalloc.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -181,6 +181,4 @@ constexpr MeshExtract create_extractor_lines_paint_mask()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_lines_paint_mask = blender::draw::create_extractor_lines_paint_mask();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
index 503ce0e79e9..e746b37fd30 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
@@ -10,7 +10,7 @@
#include "MEM_guardedalloc.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -322,6 +322,4 @@ constexpr MeshExtract create_extractor_points()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_points = blender::draw::create_extractor_points();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
index 6ca5692f387..4c8d1d0002a 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
@@ -7,7 +7,7 @@
#include "MEM_guardedalloc.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -243,7 +243,5 @@ constexpr MeshExtract create_extractor_tris_single_mat()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_tris = blender::draw::create_extractor_tris();
const MeshExtract extract_tris_single_mat = blender::draw::create_extractor_tris_single_mat();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
index fa41facb751..fb6b5e1904b 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -16,7 +16,7 @@
#include "draw_attributes.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -27,21 +27,16 @@ namespace blender::draw {
static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, eAttrDomain domain)
{
switch (domain) {
- default: {
- return nullptr;
- }
- case ATTR_DOMAIN_POINT: {
+ case ATTR_DOMAIN_POINT:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
- }
- case ATTR_DOMAIN_CORNER: {
+ case ATTR_DOMAIN_CORNER:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
- }
- case ATTR_DOMAIN_FACE: {
+ case ATTR_DOMAIN_FACE:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
- }
- case ATTR_DOMAIN_EDGE: {
+ case ATTR_DOMAIN_EDGE:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->edata : &mr->me->edata;
- }
+ default:
+ return nullptr;
}
}
@@ -50,7 +45,7 @@ static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, eAttrDom
* etc.) directly map to available GPU types. Booleans are still converted as attributes are vec4
* in the shader.
*/
-template<typename AttributeType, typename VBOType> struct attribute_type_converter {
+template<typename AttributeType, typename VBOType> struct AttributeTypeConverter {
static VBOType convert_value(AttributeType value)
{
if constexpr (std::is_same_v<AttributeType, VBOType>) {
@@ -67,7 +62,7 @@ struct gpuMeshCol {
ushort r, g, b, a;
};
-template<> struct attribute_type_converter<MPropCol, gpuMeshCol> {
+template<> struct AttributeTypeConverter<MPropCol, gpuMeshCol> {
static gpuMeshCol convert_value(MPropCol value)
{
gpuMeshCol result;
@@ -86,53 +81,42 @@ static uint gpu_component_size_for_attribute_type(eCustomDataType type)
case CD_PROP_BOOL:
case CD_PROP_INT8:
case CD_PROP_INT32:
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
/* TODO(@kevindietrich): should be 1 when scalar attributes conversion is handled by us. See
* comment #extract_attr_init. */
return 3;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
return 2;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
return 3;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return 4;
- }
- default: {
+ default:
return 0;
- }
}
}
static GPUVertFetchMode get_fetch_mode_for_type(eCustomDataType type)
{
switch (type) {
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
return GPU_FETCH_INT_TO_FLOAT;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return GPU_FETCH_INT_TO_FLOAT_UNIT;
- }
- default: {
+ default:
return GPU_FETCH_FLOAT;
- }
}
}
static GPUVertCompType get_comp_type_for_type(eCustomDataType type)
{
switch (type) {
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
return GPU_COMP_I32;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return GPU_COMP_U16;
- }
- default: {
+ default:
return GPU_COMP_F32;
- }
}
}
@@ -184,41 +168,36 @@ static void fill_vertbuf_with_attribute(const MeshRenderData *mr,
const AttributeType *attr_data = static_cast<const AttributeType *>(
CustomData_get_layer_n(custom_data, request.cd_type, layer_index));
- using converter = attribute_type_converter<AttributeType, VBOType>;
+ using Converter = AttributeTypeConverter<AttributeType, VBOType>;
switch (request.domain) {
- default: {
- BLI_assert(false);
- break;
- }
- case ATTR_DOMAIN_POINT: {
+ case ATTR_DOMAIN_POINT:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
- *vbo_data = converter::convert_value(attr_data[mloop->v]);
+ *vbo_data = Converter::convert_value(attr_data[mloop->v]);
}
break;
- }
- case ATTR_DOMAIN_CORNER: {
+ case ATTR_DOMAIN_CORNER:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++) {
- *vbo_data = converter::convert_value(attr_data[ml_index]);
+ *vbo_data = Converter::convert_value(attr_data[ml_index]);
}
break;
- }
- case ATTR_DOMAIN_EDGE: {
+ case ATTR_DOMAIN_EDGE:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
- *vbo_data = converter::convert_value(attr_data[mloop->e]);
+ *vbo_data = Converter::convert_value(attr_data[mloop->e]);
}
break;
- }
- case ATTR_DOMAIN_FACE: {
+ case ATTR_DOMAIN_FACE:
for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) {
const MPoly &poly = mpoly[mp_index];
- const VBOType value = converter::convert_value(attr_data[mp_index]);
+ const VBOType value = Converter::convert_value(attr_data[mp_index]);
for (int l = 0; l < poly.totloop; l++) {
*vbo_data++ = value;
}
}
break;
- }
+ default:
+ BLI_assert_unreachable();
+ break;
}
}
@@ -231,9 +210,9 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
BLI_assert(custom_data);
const int layer_index = request.layer_index;
- int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
+ const int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
- using converter = attribute_type_converter<AttributeType, VBOType>;
+ using Converter = AttributeTypeConverter<AttributeType, VBOType>;
BMIter f_iter;
BMFace *efa;
@@ -255,10 +234,10 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->e, cd_ofs));
}
else {
- BLI_assert(false);
+ BLI_assert_unreachable();
continue;
}
- *vbo_data = converter::convert_value(*attr_data);
+ *vbo_data = Converter::convert_value(*attr_data);
vbo_data++;
} while ((l_iter = l_iter->next) != l_first);
}
@@ -297,37 +276,29 @@ static void extract_attr_init(const MeshRenderData *mr,
* Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a similar
* texture as for volume attribute, so we can control the conversion ourselves. */
switch (request.cd_type) {
- case CD_PROP_BOOL: {
+ case CD_PROP_BOOL:
extract_attr_generic<bool, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_INT8: {
+ case CD_PROP_INT8:
extract_attr_generic<int8_t, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
extract_attr_generic<int32_t, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
extract_attr_generic<float, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
extract_attr_generic<float2>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
extract_attr_generic<float3>(mr, vbo, request);
break;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request);
break;
- }
- default: {
- BLI_assert(false);
- }
+ default:
+ BLI_assert_unreachable();
}
}
@@ -353,37 +324,29 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop));
switch (request.cd_type) {
- case CD_PROP_BOOL: {
+ case CD_PROP_BOOL:
extract_attr_generic<bool, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_INT8: {
+ case CD_PROP_INT8:
extract_attr_generic<int8_t, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
extract_attr_generic<int32_t, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
extract_attr_generic<float, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
extract_attr_generic<float2>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
extract_attr_generic<float3>(mr, src_data, request);
break;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request);
break;
- }
- default: {
- BLI_assert(false);
- }
+ default:
+ BLI_assert_unreachable();
}
GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
@@ -430,7 +393,7 @@ EXTRACT_INIT_WRAPPER(12)
EXTRACT_INIT_WRAPPER(13)
EXTRACT_INIT_WRAPPER(14)
-template<int index>
+template<int Index>
constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn)
{
MeshExtract extractor = {nullptr};
@@ -439,7 +402,7 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
- extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[index]);
+ extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[Index]);
return extractor;
}
@@ -447,7 +410,6 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF
} // namespace blender::draw
-extern "C" {
#define CREATE_EXTRACTOR_ATTR(index) \
blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index, \
blender::draw::extract_attr_init_subdiv##index)
@@ -469,4 +431,3 @@ const MeshExtract extract_attr[GPU_MAX_ATTR] = {
CREATE_EXTRACTOR_ATTR(13),
CREATE_EXTRACTOR_ATTR(14),
};
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
index f3b41efe1c3..a11f740239a 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
@@ -10,7 +10,7 @@
#include "GPU_capabilities.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -303,6 +303,4 @@ constexpr MeshExtract create_extractor_edge_fac()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edge_fac = blender::draw::create_extractor_edge_fac();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
index 1e158a7e6d7..3bb706e82cd 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -367,6 +367,4 @@ constexpr MeshExtract create_extractor_edit_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edit_data = blender::draw::create_extractor_edit_data();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
index f79fe345f5a..6d54fce2a0d 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -199,6 +199,4 @@ constexpr MeshExtract create_extractor_edituv_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_data = blender::draw::create_extractor_edituv_data();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
index fb4b95885fc..5d6dd14b57a 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
@@ -9,7 +9,7 @@
#include "BKE_mesh.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -292,7 +292,5 @@ constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_stretch_angle =
blender::draw::create_extractor_edituv_edituv_stretch_angle();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
index ab397cc1717..70dcc24f946 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
@@ -9,7 +9,7 @@
#include "BKE_mesh.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -180,7 +180,5 @@ constexpr MeshExtract create_extractor_edituv_stretch_area()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_stretch_area =
blender::draw::create_extractor_edituv_stretch_area();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc
index 1c4f6112877..64bec0adad4 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -81,6 +81,4 @@ constexpr MeshExtract create_extractor_fdots_edituv_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_edituv_data = blender::draw::create_extractor_fdots_edituv_data();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
index 909c9ac2300..8d189db9f12 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -180,7 +180,5 @@ constexpr MeshExtract create_extractor_fdots_nor_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_nor = blender::draw::create_extractor_fdots_nor();
const MeshExtract extract_fdots_nor_hq = blender::draw::create_extractor_fdots_nor_hq();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
index 1671a1cd1e7..822b5928c49 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -139,6 +139,4 @@ constexpr MeshExtract create_extractor_fdots_pos()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_pos = blender::draw::create_extractor_fdots_pos();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
index e7a3cb03903..de21c63e5fd 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -109,6 +109,4 @@ constexpr MeshExtract create_extractor_fdots_uv()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_uv = blender::draw::create_extractor_fdots_uv();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
index 8bc8b32fdf3..42a9a58bbe4 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -234,7 +234,5 @@ constexpr MeshExtract create_extractor_lnor_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_lnor = blender::draw::create_extractor_lnor();
const MeshExtract extract_lnor_hq = blender::draw::create_extractor_lnor_hq();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
index 968c1f693fb..b57e2f6b807 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
@@ -14,7 +14,7 @@
#include "BKE_editmesh_bvh.h"
#include "BKE_editmesh_cache.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -633,6 +633,4 @@ constexpr MeshExtract create_extractor_mesh_analysis()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_mesh_analysis = blender::draw::create_extractor_mesh_analysis();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
index 94674a54f12..68d838e9e62 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -94,6 +94,4 @@ constexpr MeshExtract create_extractor_orco()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_orco = blender::draw::create_extractor_orco();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
index f80b33e28f2..313744bdd27 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
@@ -7,7 +7,7 @@
#include "MEM_guardedalloc.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -234,7 +234,7 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
if (subdiv_cache->use_custom_loop_normals) {
Mesh *coarse_mesh = subdiv_cache->mesh;
- const float(*lnors)[3] = static_cast<float(*)[3]>(
+ const float(*lnors)[3] = static_cast<const float(*)[3]>(
CustomData_get_layer(&coarse_mesh->ldata, CD_NORMAL));
BLI_assert(lnors != nullptr);
@@ -552,7 +552,5 @@ constexpr MeshExtract create_extractor_pos_nor_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_pos_nor = blender::draw::create_extractor_pos_nor();
const MeshExtract extract_pos_nor_hq = blender::draw::create_extractor_pos_nor_hq();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
index 5658ed85c8b..0d959e324f8 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
@@ -12,7 +12,7 @@
#include "BKE_paint.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -215,6 +215,4 @@ constexpr MeshExtract create_extractor_sculpt_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_sculpt_data = blender::draw::create_extractor_sculpt_data();
-}
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 f4c54b2f881..6230e1974be 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
@@ -6,7 +6,7 @@
*/
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -411,9 +411,7 @@ constexpr MeshExtract create_extractor_fdot_idx()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_poly_idx = blender::draw::create_extractor_poly_idx();
const MeshExtract extract_edge_idx = blender::draw::create_extractor_edge_idx();
const MeshExtract extract_vert_idx = blender::draw::create_extractor_vert_idx();
const MeshExtract extract_fdot_idx = blender::draw::create_extractor_fdot_idx();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc
index bb6331dd377..a275f247cad 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -72,6 +72,4 @@ constexpr MeshExtract create_extractor_skin_roots()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_skin_roots = blender::draw::create_extractor_skin_roots();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
index 91cd675d32f..83453d6ef38 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
@@ -14,7 +14,7 @@
#include "BKE_mesh.h"
#include "BKE_mesh_tangent.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -367,7 +367,5 @@ constexpr MeshExtract create_extractor_tan_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_tan = blender::draw::create_extractor_tan();
const MeshExtract extract_tan_hq = blender::draw::create_extractor_tan_hq();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
index 2808a0a3a71..ddb8ed9b25b 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
@@ -8,7 +8,7 @@
#include "BLI_string.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -168,6 +168,4 @@ constexpr MeshExtract create_extractor_uv()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_uv = blender::draw::create_extractor_uv();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
index 91ac3f22617..84ab20f8f90 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
@@ -12,7 +12,9 @@
#include "BLI_vector.hh"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
+
+namespace blender::draw {
struct VColRef {
const CustomDataLayer *layer;
@@ -25,11 +27,11 @@ struct VColRef {
* corresponds to the integer position of the attribute
* within the global color attribute list.
*/
-static blender::Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
- const CustomData *cd_ldata,
- const uint vcol_layers)
+static Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
+ const CustomData *cd_ldata,
+ const uint vcol_layers)
{
- blender::Vector<VColRef> refs;
+ Vector<VColRef> refs;
uint layeri = 0;
auto buildList = [&](const CustomData *cdata, eAttrDomain domain) {
@@ -64,8 +66,6 @@ static blender::Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
return refs;
}
-namespace blender::draw {
-
/* ---------------------------------------------------------------------- */
/** \name Extract VCol
* \{ */
@@ -73,16 +73,16 @@ namespace blender::draw {
/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */
static void init_vcol_format(GPUVertFormat *format,
const MeshBatchCache *cache,
- CustomData *cd_vdata,
- CustomData *cd_ldata,
- CustomDataLayer *active,
- CustomDataLayer *render)
+ const CustomData *cd_vdata,
+ const CustomData *cd_ldata,
+ const CustomDataLayer *active,
+ const CustomDataLayer *render)
{
GPU_vertformat_deinterleave(format);
const uint32_t vcol_layers = cache->cd_used.vcol;
- blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
+ Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
for (const VColRef &ref : refs) {
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
@@ -118,7 +118,7 @@ static GPUVertFormat *get_coarse_vcol_format()
return &format;
}
-using gpuMeshVcol = struct gpuMeshVcol {
+struct gpuMeshVcol {
ushort r, g, b, a;
};
@@ -130,16 +130,18 @@ static void extract_vcol_init(const MeshRenderData *mr,
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
GPUVertFormat format = {0};
- CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
- CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ const CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata :
+ &mr->me->vdata;
+ const CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata :
+ &mr->me->ldata;
Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
- CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
+ const CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
const uint32_t vcol_layers = cache->cd_used.vcol;
init_vcol_format(&format, cache, cd_vdata, cd_ldata, active_color, render_color);
@@ -149,10 +151,10 @@ static void extract_vcol_init(const MeshRenderData *mr,
gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo);
- blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
+ Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
for (const VColRef &ref : refs) {
- CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
+ const CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
if (mr->extract_type == MR_EXTRACT_BMESH) {
int cd_ofs = ref.layer->offset;
@@ -168,10 +170,10 @@ static void extract_vcol_init(const MeshRenderData *mr,
BMFace *f;
BM_ITER_MESH (f, &iter, mr->bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter = f->l_first;
+ const BMLoop *l_iter = f->l_first;
do {
- BMElem *elem = is_point ? reinterpret_cast<BMElem *>(l_iter->v) :
- reinterpret_cast<BMElem *>(l_iter);
+ const BMElem *elem = is_point ? reinterpret_cast<const BMElem *>(l_iter->v) :
+ reinterpret_cast<const BMElem *>(l_iter);
if (is_byte) {
const MLoopCol *mloopcol = (const MLoopCol *)BM_ELEM_CD_GET_VOID_P(elem, cd_ofs);
vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
@@ -193,17 +195,17 @@ static void extract_vcol_init(const MeshRenderData *mr,
}
else {
int totloop = mr->loop_len;
- int idx = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
+ const int idx = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
- MLoopCol *mcol = nullptr;
- MPropCol *pcol = nullptr;
+ const MLoopCol *mcol = nullptr;
+ const MPropCol *pcol = nullptr;
const MLoop *mloop = mr->mloop;
if (ref.layer->type == CD_PROP_COLOR) {
- pcol = static_cast<MPropCol *>(cdata->layers[idx].data);
+ pcol = static_cast<const MPropCol *>(cdata->layers[idx].data);
}
else {
- mcol = static_cast<MLoopCol *>(cdata->layers[idx].data);
+ mcol = static_cast<const MLoopCol *>(cdata->layers[idx].data);
}
const bool is_corner = ref.domain == ATTR_DOMAIN_CORNER;
@@ -237,7 +239,7 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
void *UNUSED(data))
{
GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
- Mesh *coarse_mesh = subdiv_cache->mesh;
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
bool extract_bmesh = mr->extract_type == MR_EXTRACT_BMESH;
@@ -251,8 +253,8 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
- CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
+ const CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
GPUVertFormat format = {0};
init_vcol_format(
@@ -270,7 +272,7 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
const uint vcol_layers = cache->cd_used.vcol;
- blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
+ Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
/* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in
* a single buffer. */
@@ -299,14 +301,15 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
const bool is_byte = ref.layer->type == CD_PROP_BYTE_COLOR;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter = f->l_first;
+ const BMLoop *l_iter = f->l_first;
do {
- BMElem *elem = is_vert ? reinterpret_cast<BMElem *>(l_iter->v) :
- reinterpret_cast<BMElem *>(l_iter);
+ const BMElem *elem = is_vert ? reinterpret_cast<const BMElem *>(l_iter->v) :
+ reinterpret_cast<const BMElem *>(l_iter);
if (is_byte) {
- MLoopCol *mcol2 = static_cast<MLoopCol *>(BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
+ const MLoopCol *mcol2 = static_cast<const MLoopCol *>(
+ BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]);
vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]);
@@ -314,7 +317,8 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
vcol->a = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f));
}
else {
- MPropCol *pcol2 = static_cast<MPropCol *>(BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
+ const MPropCol *pcol2 = static_cast<const MPropCol *>(
+ BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
vcol->r = unit_float_to_ushort_clamp(pcol2->color[0]);
vcol->g = unit_float_to_ushort_clamp(pcol2->color[1]);
@@ -328,14 +332,14 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
}
else {
const MLoop *ml = coarse_mesh->mloop;
- MLoopCol *mcol = nullptr;
- MPropCol *pcol = nullptr;
+ const MLoopCol *mcol = nullptr;
+ const MPropCol *pcol = nullptr;
if (ref.layer->type == CD_PROP_COLOR) {
- pcol = static_cast<MPropCol *>(cdata->layers[layer_i].data);
+ pcol = static_cast<const MPropCol *>(cdata->layers[layer_i].data);
}
else {
- mcol = static_cast<MLoopCol *>(cdata->layers[layer_i].data);
+ mcol = static_cast<const MLoopCol *>(cdata->layers[layer_i].data);
}
for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, ml++) {
@@ -380,6 +384,4 @@ constexpr MeshExtract create_extractor_vcol()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_vcol = blender::draw::create_extractor_vcol();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
index 89aa16ca0c7..c64cca4dff5 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
@@ -10,7 +10,7 @@
#include "BKE_deform.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -208,6 +208,4 @@ constexpr MeshExtract create_extractor_weights()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_weights = blender::draw::create_extractor_weights();
-}
diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index dfa2f307800..e235da91e8d 100644
--- a/source/blender/draw/intern/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
@@ -5,6 +5,8 @@
* of data the CPU has to precompute and transfer for each update.
*/
+#define COMMON_HAIR_LIB
+
/* TODO(fclem): Keep documentation but remove the uniform declaration. */
#ifndef USE_GPU_SHADER_CREATE_INFO
diff --git a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
index 55e4ac20271..d76a7369f79 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
@@ -139,20 +139,20 @@ void set_vertex_pos(inout PosNorLoop vertex_data, vec3 pos)
vertex_data.z = pos.z;
}
-void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, uint flag)
+/* Set the vertex normal but preserve the existing flag. This is for when we compute manually the
+ * vertex normals when we cannot use the limit surface, in which case the flag and the normal are
+ * set by two separate compute pass. */
+void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor)
{
vertex_data.nx = nor.x;
vertex_data.ny = nor.y;
vertex_data.nz = nor.z;
- vertex_data.flag = float(flag);
}
-/* Set the vertex normal but preserve the existing flag. This is for when we compute manually the
- * vertex normals when we cannot use the limit surface, in which case the flag and the normal are
- * set by two separate compute pass. */
-void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor)
+void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, float flag)
{
- set_vertex_nor(vertex_data, nor, 0);
+ set_vertex_nor(vertex_data, nor);
+ vertex_data.flag = flag;
}
void add_newell_cross_v3_v3v3(inout vec3 n, vec3 v_prev, vec3 v_curr)
diff --git a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
index 0ffb216fc6f..e146ccb343a 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
@@ -459,9 +459,9 @@ void main()
vec3 nor = vec3(0.0);
int origindex = input_vert_origindex[loop_index];
- uint flag = 0;
+ float flag = 0.0;
if (origindex == -1) {
- flag = -1;
+ flag = -1.0;
}
PosNorLoop vertex_data;
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
index b7bcfd2d369..f5c4c7895aa 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
@@ -11,7 +11,12 @@ layout(std430, binding = 2) readonly buffer extraCoarseFaceData
uint extra_coarse_face_data[];
};
-layout(std430, binding = 3) writeonly buffer outputLoopNormals
+layout(std430, binding = 3) readonly buffer inputVertOrigIndices
+{
+ int input_vert_origindex[];
+};
+
+layout(std430, binding = 4) writeonly buffer outputLoopNormals
{
LoopNormal output_lnor[];
};
@@ -60,13 +65,15 @@ void main()
loop_normal.nx = face_normal.x;
loop_normal.ny = face_normal.y;
loop_normal.nz = face_normal.z;
- loop_normal.flag = 0.0;
-
- if (is_face_selected(coarse_quad_index)) {
- loop_normal.flag = 1.0;
- }
for (int i = 0; i < 4; i++) {
+ int origindex = input_vert_origindex[start_loop_index + i];
+ float flag = 0.0;
+ if (origindex == -1) {
+ flag = -1.0;
+ }
+ loop_normal.flag = flag;
+
output_lnor[start_loop_index + i] = loop_normal;
}
}
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index c2d517588b2..9eeabf2d05e 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -4351,15 +4351,15 @@ void ANIM_channel_setting_set(bAnimContext *ac,
/* --------------------------- */
-/* size of icons */
+/** Size of icons. */
#define ICON_WIDTH (0.85f * U.widget_unit)
-/* width of sliders */
+/** Width of sliders. */
#define SLIDER_WIDTH (4 * U.widget_unit)
-/* min-width of rename textboxes */
+/** Min-width of rename text-boxes. */
#define RENAME_TEXT_MIN_WIDTH (U.widget_unit)
-/* width of graph editor color bands */
+/** Width of graph editor color bands. */
#define GRAPH_COLOR_BAND_WIDTH (0.3f * U.widget_unit)
-/* extra offset for the visibility icons in the graph editor */
+/** Extra offset for the visibility icons in the graph editor. */
#define GRAPH_ICON_VISIBILITY_OFFSET (GRAPH_COLOR_BAND_WIDTH * 1.5f)
/* Helper - Check if a channel needs renaming */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index f148bb5b77d..b223a1493fd 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -711,14 +711,14 @@ static bool animedit_poll_channels_active(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test */
if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* Poll callback for Animation Editor channels list region + not in NLA-tweak-mode for NLA. */
@@ -730,21 +730,21 @@ static bool animedit_poll_channels_nla_tweakmode_off(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test */
if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
- return 0;
+ return false;
}
/* NLA tweak-mode test. */
if (area->spacetype == SPACE_NLA) {
if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) {
- return 0;
+ return false;
}
}
- return 1;
+ return true;
}
/* ****************** Rearrange Channels Operator ******************* */
@@ -791,7 +791,7 @@ static bool rearrange_island_ok(tReorderChannelIsland *island)
{
/* island must not be untouchable */
if (island->flag & REORDER_ISLAND_UNTOUCHABLE) {
- return 0;
+ return false;
}
/* island should be selected to be moved */
@@ -809,10 +809,10 @@ static bool rearrange_island_top(ListBase *list, tReorderChannelIsland *island)
/* make it first element */
BLI_insertlinkbefore(list, list->first, island);
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island)
@@ -833,11 +833,11 @@ static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island)
/* push it up */
BLI_insertlinkbefore(list, prev, island);
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island)
@@ -1083,7 +1083,7 @@ static bool rearrange_animchannel_islands(ListBase *list,
/* don't waste effort on an empty list */
if (BLI_listbase_is_empty(list)) {
- return 0;
+ return false;
}
/* group channels into islands */
@@ -1589,7 +1589,7 @@ static bool animchannels_grouping_poll(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test - must be suitable modes only */
@@ -1602,7 +1602,7 @@ static bool animchannels_grouping_poll(bContext *C)
/* dopesheet and action only - all others are for other datatypes or have no groups */
if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0) {
- return 0;
+ return false;
}
break;
@@ -1612,17 +1612,17 @@ static bool animchannels_grouping_poll(bContext *C)
/* drivers can't have groups... */
if (sipo->mode != SIPO_MODE_ANIMATION) {
- return 0;
+ return false;
}
break;
}
/* unsupported... */
default:
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* ----------------------------------------------------------- */
@@ -2428,15 +2428,15 @@ static bool animchannels_enable_poll(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test - Action/Dopesheet/etc. and Graph only */
if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH) == 0) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static int animchannels_enable_exec(bContext *C, wmOperator *UNUSED(op))
@@ -2504,7 +2504,7 @@ static bool animchannels_select_filter_poll(bContext *C)
ScrArea *area = CTX_wm_area(C);
if (area == NULL) {
- return 0;
+ return false;
}
/* animation editor with dopesheet */
@@ -2791,13 +2791,35 @@ static bool rename_anim_channels(bAnimContext *ac, int channel_index)
return false;
}
- /* don't allow renaming linked channels */
- if ((ale->fcurve_owner_id != NULL &&
- (ID_IS_LINKED(ale->fcurve_owner_id) || ID_IS_OVERRIDE_LIBRARY(ale->fcurve_owner_id))) ||
- (ale->id != NULL && (ID_IS_LINKED(ale->id) || ID_IS_OVERRIDE_LIBRARY(ale->id)))) {
+ /* Don't allow renaming linked/liboverride channels. */
+ if (ale->fcurve_owner_id != NULL &&
+ (ID_IS_LINKED(ale->fcurve_owner_id) || ID_IS_OVERRIDE_LIBRARY(ale->fcurve_owner_id))) {
ANIM_animdata_freelist(&anim_data);
return false;
}
+ if (ale->id != NULL) {
+ if (ID_IS_LINKED(ale->id)) {
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+ /* There is one exception to not allowing renaming on liboverride channels: locally-inserted
+ * NLA tracks. */
+ if (ID_IS_OVERRIDE_LIBRARY(ale->id)) {
+ switch (ale->type) {
+ case ANIMTYPE_NLATRACK: {
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+ if ((nlt->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0) {
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+ break;
+ }
+ default:
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+ }
+ }
/* check that channel can be renamed */
acf = ANIM_channel_get_typeinfo(ale);
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 8519b2061f2..ad06b185132 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -543,7 +543,6 @@ void ED_markers_draw(const bContext *C, int flag)
View2D *v2d = UI_view2d_fromcontext(C);
int cfra = CTX_data_scene(C)->r.cfra;
- const float line_width = GPU_line_width_get();
GPU_line_width(1.0f);
rctf markers_region_rect;
@@ -578,7 +577,6 @@ void ED_markers_draw(const bContext *C, int flag)
}
}
- GPU_line_width(line_width);
GPU_matrix_pop();
}
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 1b759f5dfa2..c6f68228807 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -180,7 +180,7 @@ static int add_driver_with_target(ReportList *UNUSED(reports),
}
else if ((RNA_property_unit(src_prop) == PROP_UNIT_ROTATION) &&
(RNA_property_unit(dst_prop) != PROP_UNIT_ROTATION)) {
- /* Rotation Source: radians -> normal, so convert src to degrees
+ /* Rotation Source: radians -> normal, so convert src to degrees
* (However, if both input and output is a rotation, don't apply such corrections)
*/
BLI_strncpy(driver->expression, "degrees(var)", sizeof(driver->expression));
diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc
index 3356ef4d47d..8dc598e6e2d 100644
--- a/source/blender/editors/animation/keyframes_keylist.cc
+++ b/source/blender/editors/animation/keyframes_keylist.cc
@@ -132,7 +132,7 @@ static void ED_keylist_runtime_init_listbase(AnimKeylist *keylist)
return;
}
- keylist->runtime.list_wrapper.first = &keylist->runtime.key_columns[0];
+ keylist->runtime.list_wrapper.first = keylist->runtime.key_columns.data();
keylist->runtime.list_wrapper.last = &keylist->runtime.key_columns[keylist->column_len - 1];
}
@@ -309,7 +309,7 @@ static void keylist_first_last(const struct AnimKeylist *keylist,
const struct ActKeyColumn **last_column)
{
if (keylist->is_runtime_initialized) {
- *first_column = &keylist->runtime.key_columns[0];
+ *first_column = keylist->runtime.key_columns.data();
*last_column = &keylist->runtime.key_columns[keylist->column_len - 1];
}
else {
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 941125b9ad5..aa99a4e50c3 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -3094,8 +3094,13 @@ bool ED_autokeyframe_pchan(
return false;
}
-bool ED_autokeyframe_property(
- bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra)
+bool ED_autokeyframe_property(bContext *C,
+ Scene *scene,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ int rnaindex,
+ float cfra,
+ const bool only_if_property_keyed)
{
Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -3114,7 +3119,9 @@ bool ED_autokeyframe_property(
fcu = BKE_fcurve_find_by_rna_context_ui(
C, ptr, prop, rnaindex_check, NULL, &action, &driven, &special);
- if (fcu == NULL) {
+ /* Only early out when we actually want an existing F-curve already
+ * (e.g. auto-keyframing from buttons). */
+ if (fcu == NULL && (driven || special || only_if_property_keyed)) {
return changed;
}
@@ -3150,23 +3157,28 @@ bool ED_autokeyframe_property(
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
const eInsertKeyFlags flag = ANIM_get_keyframing_flags(scene, true);
+ char *path = RNA_path_from_ID_to_property(ptr, prop);
- /* NOTE: We use rnaindex instead of fcu->array_index,
- * because a button may control all items of an array at once.
- * E.g., color wheels (see T42567). */
- BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1));
+ if (only_if_property_keyed) {
+ /* NOTE: We use rnaindex instead of fcu->array_index,
+ * because a button may control all items of an array at once.
+ * E.g., color wheels (see T42567). */
+ BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1));
+ }
changed = insert_keyframe(bmain,
reports,
id,
action,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
+ (fcu && fcu->grp) ? fcu->grp->name : NULL,
+ fcu ? fcu->rna_path : path,
rnaindex,
&anim_eval_context,
ts->keyframe_type,
NULL,
flag) != 0;
-
+ if (path) {
+ MEM_freeN(path);
+ }
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
}
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index f9b973733af..dd43e3e6613 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -375,13 +375,10 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
/* does this constraint have a subtarget in
* this armature?
*/
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
+ if (BKE_constraint_targets_get(curcon, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if ((ct->tar == ob) && (ct->subtarget[0])) {
oldtarget = get_named_editbone(editbones, ct->subtarget);
@@ -409,9 +406,7 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
+ BKE_constraint_targets_flush(curcon, &targets, 0);
}
}
}
@@ -1152,7 +1147,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
if (axis_delta == 0.0f) {
- /* both mirrored bones exist and point to eachother and overlap exactly.
+ /* Both mirrored bones exist and point to each other and overlap exactly.
*
* in this case there's no well defined solution, so de-select both and skip.
*/
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index e1f2605481f..1f02e24666d 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -109,13 +109,10 @@ static void constraint_bone_name_fix(Object *ob,
bConstraintTarget *ct;
for (curcon = conlist->first; curcon; curcon = curcon->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
+ if (BKE_constraint_targets_get(curcon, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == ob) {
if (STREQ(ct->subtarget, oldname)) {
@@ -124,9 +121,7 @@ static void constraint_bone_name_fix(Object *ob,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
+ BKE_constraint_targets_flush(curcon, &targets, 0);
}
/* action constraints */
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index be4829c02be..950178e865d 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -68,14 +68,11 @@ static void joined_armature_fix_links_constraints(Main *bmain,
bool changed = false;
for (con = lb->first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == srcArm) {
if (ct->subtarget[0] == '\0') {
@@ -90,9 +87,7 @@ static void joined_armature_fix_links_constraints(Main *bmain,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
/* action constraint? (pose constraints only) */
@@ -459,14 +454,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
if (ob->type == OB_ARMATURE) {
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
/* Any targets which point to original armature
* are redirected to the new one only if:
@@ -487,9 +479,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
}
@@ -498,14 +488,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
/* fix object-level constraints */
if (ob != origArm) {
for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
/* any targets which point to original armature are redirected to the new one only if:
* - the target isn't origArm/newArm itself
@@ -525,9 +512,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index e0e5693c79b..ea54c3014ca 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -1431,7 +1431,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con
ret = OPERATOR_PASS_THROUGH;
break;
- /* quicky compare to original */
+ /* Quickly compare to original. */
case EVT_TABKEY:
pld->flag &= ~PL_PREVIEW_SHOWORIGINAL;
pld->redraw = PL_PREVIEW_REDRAWALL;
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 8790a10f3e5..b6b5d3ee495 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -680,13 +680,10 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
if (pchan->bone->flag & BONE_SELECTED) {
for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
Object *ob = ct->tar;
@@ -702,9 +699,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 1);
- }
+ BKE_constraint_targets_flush(con, &targets, 1);
}
}
}
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index dc49a5ed531..4c0df48f65b 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -5597,7 +5597,8 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
vc.v3d,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
- .snap_select = (vc.obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
+ .snap_target_select = (vc.obedit != NULL) ? SCE_SNAP_TARGET_NOT_ACTIVE :
+ SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_FINAL,
},
mval,
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 598779c6ace..6946c09e6f1 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -105,7 +105,7 @@ struct CurveDrawData {
} radius;
struct {
- float mouse[2];
+ float mval[2];
/* Used in case we can't calculate the depth. */
float location_world[3];
@@ -463,8 +463,8 @@ static void curve_draw_event_add(wmOperator *op, const wmEvent *event)
}
copy_v3_v3(cdd->prev.location_world, selem->location_world);
- float len_sq = len_squared_v2v2(cdd->prev.mouse, selem->mval);
- copy_v2_v2(cdd->prev.mouse, selem->mval);
+ float len_sq = len_squared_v2v2(cdd->prev.mval, selem->mval);
+ copy_v2_v2(cdd->prev.mval, selem->mval);
if (cdd->sample.use_substeps && cdd->prev.selem) {
const struct StrokeElem selem_target = *selem;
@@ -1165,7 +1165,7 @@ static int curve_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
if (cdd->state == CURVE_DRAW_PAINTING) {
const float mval_fl[2] = {UNPACK2(event->mval)};
- if (len_squared_v2v2(mval_fl, cdd->prev.mouse) > square_f(STROKE_SAMPLE_DIST_MIN_PX)) {
+ if (len_squared_v2v2(mval_fl, cdd->prev.mval) > square_f(STROKE_SAMPLE_DIST_MIN_PX)) {
curve_draw_event_add(op, event);
}
}
diff --git a/source/blender/editors/curve/editcurve_pen.c b/source/blender/editors/curve/editcurve_pen.c
index a98b165e99d..729ad46877a 100644
--- a/source/blender/editors/curve/editcurve_pen.c
+++ b/source/blender/editors/curve/editcurve_pen.c
@@ -843,7 +843,7 @@ static bool insert_point_to_segment(const ViewContext *vc, const wmEvent *event)
{
Curve *cu = vc->obedit->data;
CutData cd = init_cut_data(event);
- float mval[2] = {UNPACK2(event->mval)};
+ const float mval[2] = {UNPACK2(event->mval)};
const float threshold_dist_px = ED_view3d_select_dist_px() * SEL_DIST_FACTOR;
const bool near_spline = update_cut_data_for_all_nurbs(
vc, BKE_curve_editNurbs_get(cu), mval, threshold_dist_px, &cd);
@@ -985,7 +985,7 @@ static void extrude_vertices_from_selected_endpoints(EditNurb *editnurb,
else {
BPoint *last_bp = nu1->bp + nu1->pntsu - 1;
const bool first_sel = nu1->bp->f1 & SELECT;
- const bool last_sel = last_bp->f1 & SELECT;
+ const bool last_sel = last_bp->f1 & SELECT && nu1->pntsu > 1;
if (first_sel) {
if (last_sel) {
BPoint *new_bp = (BPoint *)MEM_mallocN((nu1->pntsu + 2) * sizeof(BPoint), __func__);
@@ -1134,7 +1134,7 @@ static bool is_spline_nearby(ViewContext *vc,
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
CutData cd = init_cut_data(event);
- float mval[2] = {UNPACK2(event->mval)};
+ const float mval[2] = {UNPACK2(event->mval)};
const bool nearby = update_cut_data_for_all_nurbs(vc, nurbs, mval, sel_dist, &cd);
if (nearby) {
diff --git a/source/blender/editors/curves/CMakeLists.txt b/source/blender/editors/curves/CMakeLists.txt
index a5d8390e7f2..3c31e8014ff 100644
--- a/source/blender/editors/curves/CMakeLists.txt
+++ b/source/blender/editors/curves/CMakeLists.txt
@@ -7,6 +7,7 @@ set(INC
../../blentranslation
../../depsgraph
../../functions
+ ../../geometry
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc
index 85214e1608d..25bcba6cfb3 100644
--- a/source/blender/editors/curves/intern/curves_ops.cc
+++ b/source/blender/editors/curves/intern/curves_ops.cc
@@ -17,6 +17,7 @@
#include "WM_api.h"
+#include "BKE_attribute_math.hh"
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
@@ -45,6 +46,8 @@
#include "RNA_enum_types.h"
#include "RNA_prototypes.h"
+#include "GEO_reverse_uv_sampler.hh"
+
/**
* The code below uses a suffix naming convention to indicate the coordinate space:
* `cu`: Local space of the curves object that is being edited.
@@ -184,25 +187,20 @@ static void try_convert_single_object(Object &curves_ob,
}
Mesh &surface_me = *static_cast<Mesh *>(surface_ob.data);
+ BVHTreeFromMesh surface_bvh;
+ BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_me, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
+
const Span<float3> positions_cu = curves.positions();
- const VArray<int> looptri_indices = curves.surface_triangle_indices();
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&surface_me),
BKE_mesh_runtime_looptri_len(&surface_me)};
- /* Find indices of curves that can be transferred to the old hair system. */
- Vector<int> curves_indices_to_transfer;
- for (const int curve_i : curves.curves_range()) {
- const int looptri_i = looptri_indices[curve_i];
- if (looptri_i >= 0 && looptri_i < looptris.size()) {
- curves_indices_to_transfer.append(curve_i);
- }
- else {
- *r_could_not_convert_some_curves = true;
- }
+ if (looptris.is_empty()) {
+ *r_could_not_convert_some_curves = true;
}
- const int hairs_num = curves_indices_to_transfer.size();
- if (hairs_num == 0) {
+ const int hair_num = curves.curves_num();
+ if (hair_num == 0) {
return;
}
@@ -228,8 +226,8 @@ static void try_convert_single_object(Object &curves_ob,
psys_changed_type(&surface_ob, particle_system);
MutableSpan<ParticleData> particles{
- static_cast<ParticleData *>(MEM_calloc_arrayN(hairs_num, sizeof(ParticleData), __func__)),
- hairs_num};
+ static_cast<ParticleData *>(MEM_calloc_arrayN(hair_num, sizeof(ParticleData), __func__)),
+ hair_num};
/* The old hair system still uses #MFace, so make sure those are available on the mesh. */
BKE_mesh_tessface_calc(&surface_me);
@@ -250,17 +248,23 @@ static void try_convert_single_object(Object &curves_ob,
const float4x4 world_to_surface_mat = surface_to_world_mat.inverted();
const float4x4 curves_to_surface_mat = world_to_surface_mat * curves_to_world_mat;
- for (const int new_hair_i : curves_indices_to_transfer.index_range()) {
- const int curve_i = curves_indices_to_transfer[new_hair_i];
+ for (const int new_hair_i : IndexRange(hair_num)) {
+ const int curve_i = new_hair_i;
const IndexRange points = curves.points_for_curve(curve_i);
- const int looptri_i = looptri_indices[curve_i];
- const MLoopTri &looptri = looptris[looptri_i];
- const int poly_i = looptri.poly;
-
const float3 &root_pos_cu = positions_cu[points.first()];
const float3 root_pos_su = curves_to_surface_mat * root_pos_cu;
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(
+ surface_bvh.tree, root_pos_su, &nearest, surface_bvh.nearest_callback, &surface_bvh);
+ BLI_assert(nearest.index >= 0);
+
+ const int looptri_i = nearest.index;
+ const MLoopTri &looptri = looptris[looptri_i];
+ const int poly_i = looptri.poly;
+
const int mface_i = find_mface_for_root_position(
surface_me, poly_to_mface_map[poly_i], root_pos_su);
const MFace &mface = surface_me.mface[mface_i];
@@ -520,7 +524,7 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
{
const AttachMode attach_mode = static_cast<AttachMode>(RNA_enum_get(op->ptr, "attach_mode"));
- std::atomic<bool> found_invalid_looptri_index = false;
+ std::atomic<bool> found_invalid_uv = false;
CTX_DATA_BEGIN (C, Object *, curves_ob, selected_objects) {
if (curves_ob->type != OB_CURVES) {
@@ -537,9 +541,19 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
}
Mesh &surface_mesh = *static_cast<Mesh *>(surface_ob.data);
+ MeshComponent surface_mesh_component;
+ surface_mesh_component.replace(&surface_mesh, GeometryOwnershipType::ReadOnly);
+
+ VArray_Span<float2> surface_uv_map;
+ if (curves_id.surface_uv_map != nullptr) {
+ surface_uv_map = surface_mesh_component
+ .attribute_try_get_for_read(
+ curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2)
+ .typed<float2>();
+ }
+
MutableSpan<float3> positions_cu = curves.positions_for_write();
- MutableSpan<int> surface_triangle_indices = curves.surface_triangle_indices_for_write();
- MutableSpan<float2> surface_triangle_coords = curves.surface_triangle_coords_for_write();
+ MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write();
const Span<MLoopTri> surface_looptris = {BKE_mesh_runtime_looptri_ensure(&surface_mesh),
BKE_mesh_runtime_looptri_len(&surface_mesh)};
@@ -585,36 +599,51 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
pos_cu += pos_diff_cu;
}
- surface_triangle_indices[curve_i] = looptri_index;
-
- const MLoopTri &looptri = surface_looptris[looptri_index];
- const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co;
- const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co;
- const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[2]].v].co;
- float3 bary_coords;
- interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
- surface_triangle_coords[curve_i] = bke::curves::encode_surface_bary_coord(bary_coords);
+ if (!surface_uv_map.is_empty()) {
+ const MLoopTri &looptri = surface_looptris[looptri_index];
+ const int corner0 = looptri.tri[0];
+ const int corner1 = looptri.tri[1];
+ const int corner2 = looptri.tri[2];
+ const float2 &uv0 = surface_uv_map[corner0];
+ const float2 &uv1 = surface_uv_map[corner1];
+ const float2 &uv2 = surface_uv_map[corner2];
+ const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[corner0].v].co;
+ const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[corner1].v].co;
+ const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[corner2].v].co;
+ float3 bary_coords;
+ interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
+ const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2);
+ surface_uv_coords[curve_i] = uv;
+ }
}
});
break;
}
case AttachMode::Deform: {
+ if (surface_uv_map.is_empty()) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Curves do not have attachment information that can be used for deformation");
+ break;
+ }
+ using geometry::ReverseUVSampler;
+ ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris};
+
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) {
const IndexRange points = curves.points_for_curve(curve_i);
const int first_point_i = points.first();
const float3 old_first_point_pos_cu = positions_cu[first_point_i];
- const int looptri_index = surface_triangle_indices[curve_i];
- if (!surface_looptris.index_range().contains(looptri_index)) {
- found_invalid_looptri_index = true;
+ const float2 uv = surface_uv_coords[curve_i];
+ ReverseUVSampler::Result lookup_result = reverse_uv_sampler.sample(uv);
+ if (lookup_result.type != ReverseUVSampler::ResultType::Ok) {
+ found_invalid_uv = true;
continue;
}
- const MLoopTri &looptri = surface_looptris[looptri_index];
-
- const float3 bary_coords = bke::curves::decode_surface_bary_coord(
- surface_triangle_coords[curve_i]);
+ const MLoopTri &looptri = *lookup_result.looptri;
+ const float3 &bary_coords = lookup_result.bary_weights;
const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co;
const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co;
@@ -638,7 +667,7 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- if (found_invalid_looptri_index) {
+ if (found_invalid_uv) {
BKE_report(op->reports, RPT_INFO, "Could not snap some curves to the surface");
}
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 59370b53995..9da2c4819a3 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -776,9 +776,12 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.curves.sculpt_comb
ops.curves.sculpt_cut
ops.curves.sculpt_delete
+ ops.curves.sculpt_density
ops.curves.sculpt_grow_shrink
ops.curves.sculpt_pinch
ops.curves.sculpt_puff
+ ops.curves.sculpt_slide
+ ops.curves.sculpt_smooth
ops.curves.sculpt_snake_hook
ops.generic.cursor
ops.generic.select
@@ -930,6 +933,7 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/mask.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/mix.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/nudge.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/paint_select.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/pinch.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/scrape.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/smear.png SRC)
@@ -967,6 +971,19 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_hard.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_stroke.png SRC)
+ # curve sculpt
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_add.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_comb.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_cut.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_delete.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_density.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_grow_shrink.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_pinch.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_puff.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_slide.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_smooth.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_snake_hook.png SRC)
+
endif()
data_to_c_simple(../../../../release/datafiles/startup.blend SRC)
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index c9677da1af5..c7e782b7b89 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -44,9 +44,9 @@ namespace blender::ed::geometry {
static bool geometry_attributes_poll(bContext *C)
{
- Object *ob = ED_object_context(C);
- Main *bmain = CTX_data_main(C);
- ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
+ const Object *ob = ED_object_context(C);
+ const Main *bmain = CTX_data_main(C);
+ const ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
return (ob && BKE_id_is_editable(bmain, &ob->id) && data && BKE_id_is_editable(bmain, data)) &&
BKE_id_attributes_supported(data);
}
@@ -106,7 +106,7 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void next_color_attribute(struct ID *id, CustomDataLayer *layer, bool is_render)
+static void next_color_attribute(ID *id, CustomDataLayer *layer, bool is_render)
{
int index = BKE_id_attribute_to_index(id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -129,7 +129,7 @@ static void next_color_attribute(struct ID *id, CustomDataLayer *layer, bool is_
}
}
-static void next_color_attributes(struct ID *id, CustomDataLayer *layer)
+static void next_color_attributes(ID *id, CustomDataLayer *layer)
{
next_color_attribute(id, layer, false); /* active */
next_color_attribute(id, layer, true); /* render */
@@ -182,7 +182,7 @@ static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
next_color_attributes(id, layer);
- if (!BKE_id_attribute_remove(id, layer, op->reports)) {
+ if (!BKE_id_attribute_remove(id, layer->name, op->reports)) {
return OPERATOR_CANCELLED;
}
@@ -261,8 +261,11 @@ static bool geometry_attribute_convert_poll(bContext *C)
if (GS(data->name) != ID_ME) {
return false;
}
- CustomDataLayer *layer = BKE_id_attributes_active_get(data);
- if (layer == nullptr) {
+ if (CTX_data_edit_object(C) != nullptr) {
+ CTX_wm_operator_poll_msg_set(C, "Operation is not allowed in edit mode");
+ return false;
+ }
+ if (BKE_id_attributes_active_get(data) == nullptr) {
return false;
}
return true;
@@ -465,7 +468,7 @@ static int geometry_color_attribute_remove_exec(bContext *C, wmOperator *op)
next_color_attributes(id, layer);
- if (!BKE_id_attribute_remove(id, layer, op->reports)) {
+ if (!BKE_id_attribute_remove(id, layer->name, op->reports)) {
return OPERATOR_CANCELLED;
}
@@ -495,6 +498,7 @@ static bool geometry_color_attributes_remove_poll(bContext *C)
return false;
}
+
void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot)
{
/* identifiers */
@@ -510,6 +514,64 @@ void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static int geometry_color_attribute_duplicate_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
+
+ if (layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CustomDataLayer *new_layer = BKE_id_attribute_duplicate(id, layer->name, op->reports);
+ if (new_layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_id_attributes_active_color_set(id, new_layer);
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool geometry_color_attributes_duplicate_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+ if (CTX_data_edit_object(C) != nullptr) {
+ CTX_wm_operator_poll_msg_set(C, "Operation is not allowed in edit mode");
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *data = ob ? static_cast<ID *>(ob->data) : nullptr;
+
+ if (BKE_id_attributes_active_color_get(data) != nullptr) {
+ return true;
+ }
+
+ return false;
+}
+
+void GEOMETRY_OT_color_attribute_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Duplicate Color Attribute";
+ ot->description = "Duplicate color attribute";
+ ot->idname = "GEOMETRY_OT_color_attribute_duplicate";
+
+ /* api callbacks */
+ ot->exec = geometry_color_attribute_duplicate_exec;
+ ot->poll = geometry_color_attributes_duplicate_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh
index bbcb682d6bf..a1000a5d01f 100644
--- a/source/blender/editors/geometry/geometry_intern.hh
+++ b/source/blender/editors/geometry/geometry_intern.hh
@@ -17,6 +17,7 @@ void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_add(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_remove(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_render_set(struct wmOperatorType *ot);
+void GEOMETRY_OT_color_attribute_duplicate(struct wmOperatorType *ot);
void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot);
} // namespace blender::ed::geometry
diff --git a/source/blender/editors/geometry/geometry_ops.cc b/source/blender/editors/geometry/geometry_ops.cc
index 23f6e6f29f4..acac757ecf1 100644
--- a/source/blender/editors/geometry/geometry_ops.cc
+++ b/source/blender/editors/geometry/geometry_ops.cc
@@ -22,5 +22,6 @@ void ED_operatortypes_geometry(void)
WM_operatortype_append(GEOMETRY_OT_color_attribute_add);
WM_operatortype_append(GEOMETRY_OT_color_attribute_remove);
WM_operatortype_append(GEOMETRY_OT_color_attribute_render_set);
+ WM_operatortype_append(GEOMETRY_OT_color_attribute_duplicate);
WM_operatortype_append(GEOMETRY_OT_attribute_convert);
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
index 0e7a8873965..cde702294d0 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -58,6 +58,11 @@ typedef struct ArrowGizmo3D {
GizmoCommonData data;
} ArrowGizmo3D;
+typedef struct ArrowGizmoInteraction {
+ GizmoInteraction inter;
+ float init_arrow_length;
+} ArrowGizmoInteraction;
+
/* -------------------------------------------------------------------- */
static void gizmo_arrow_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4])
@@ -68,7 +73,10 @@ static void gizmo_arrow_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4]
madd_v3_v3fl(r_matrix[3], arrow->gizmo.matrix_basis[2], arrow->data.offset);
}
-static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const float color[4])
+static void arrow_draw_geom(const ArrowGizmo3D *arrow,
+ const bool select,
+ const float color[4],
+ const float arrow_length)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
bool unbind_shader = true;
@@ -111,8 +119,6 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
#ifdef USE_GIZMO_CUSTOM_ARROWS
wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_arrow, select, color);
#else
- const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length");
-
const float vec[2][3] = {
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, arrow_length},
@@ -176,6 +182,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
static void arrow_draw_intern(ArrowGizmo3D *arrow, const bool select, const bool highlight)
{
wmGizmo *gz = &arrow->gizmo;
+ const float arrow_length = RNA_float_get(gz->ptr, "length");
float color[4];
float matrix_final[4][4];
@@ -186,19 +193,20 @@ static void arrow_draw_intern(ArrowGizmo3D *arrow, const bool select, const bool
GPU_matrix_push();
GPU_matrix_mul(matrix_final);
GPU_blend(GPU_BLEND_ALPHA);
- arrow_draw_geom(arrow, select, color);
+ arrow_draw_geom(arrow, select, color, arrow_length);
GPU_blend(GPU_BLEND_NONE);
GPU_matrix_pop();
if (gz->interaction_data) {
- GizmoInteraction *inter = gz->interaction_data;
+ ArrowGizmoInteraction *arrow_inter = gz->interaction_data;
GPU_matrix_push();
- GPU_matrix_mul(inter->init_matrix_final);
+ GPU_matrix_mul(arrow_inter->inter.init_matrix_final);
GPU_blend(GPU_BLEND_ALPHA);
- arrow_draw_geom(arrow, select, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f});
+ arrow_draw_geom(
+ arrow, select, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}, arrow_inter->init_arrow_length);
GPU_blend(GPU_BLEND_NONE);
GPU_matrix_pop();
@@ -380,7 +388,7 @@ static void gizmo_arrow_setup(wmGizmo *gz)
static int gizmo_arrow_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event)
{
ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
- GizmoInteraction *inter = MEM_callocN(sizeof(GizmoInteraction), __func__);
+ GizmoInteraction *inter = MEM_callocN(sizeof(ArrowGizmoInteraction), __func__);
wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
/* Some gizmos don't use properties. */
@@ -396,6 +404,8 @@ static int gizmo_arrow_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *e
gizmo_arrow_matrix_basis_get(gz, inter->init_matrix_basis);
WM_gizmo_calc_matrix_final(gz, inter->init_matrix_final);
+ ((ArrowGizmoInteraction *)inter)->init_arrow_length = RNA_float_get(gz->ptr, "length");
+
gz->interaction_data = inter;
return OPERATOR_RUNNING_MODAL;
@@ -520,7 +530,8 @@ static void GIZMO_GT_arrow_3d(wmGizmoType *gzt)
"");
RNA_def_enum_flag(gzt->srna, "transform", rna_enum_transform_items, 0, "Transform", "");
- RNA_def_float(gzt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX);
+ RNA_def_float(
+ gzt->srna, "length", 1.0f, -FLT_MAX, FLT_MAX, "Arrow Line Length", "", -FLT_MAX, FLT_MAX);
RNA_def_float_vector(
gzt->srna, "aspect", 2, NULL, 0, FLT_MAX, "Aspect", "Cone/box style only", 0.0f, FLT_MAX);
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index a0e30c7518a..11309402220 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -57,8 +57,6 @@ typedef struct ButtonGizmo2D {
GPUBatch *shape_batch[2];
} ButtonGizmo2D;
-#define CIRCLE_RESOLUTION 32
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -68,11 +66,17 @@ typedef struct ButtonGizmo2D {
static void button2d_geom_draw_backdrop(const wmGizmo *gz,
const float color[4],
const float fill_alpha,
- const bool select)
+ const bool select,
+ const float screen_scale)
{
float viewport[4];
GPU_viewport_size_get_f(viewport);
+ const float max_pixel_error = 0.25f;
+ int nsegments = (int)(ceilf(M_PI / acosf(1.0f - max_pixel_error / screen_scale)));
+ nsegments = max_ff(nsegments, 8);
+ nsegments = min_ff(nsegments, 1000);
+
GPUVertFormat *format = immVertexFormat();
/* NOTE(Metal): Prefer 3D coordinate for 2D rendering when using 3D shader. */
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
@@ -81,14 +85,14 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
if (color[3] == 1.0 && fill_alpha == 1.0 && select == false) {
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(color);
- imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
- imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
}
else {
@@ -97,7 +101,7 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
const float fill_color[4] = {UNPACK3(color), fill_alpha * color[3]};
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(fill_color);
- imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
}
@@ -107,7 +111,7 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
- imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
}
}
@@ -184,9 +188,11 @@ static void button2d_draw_intern(const bContext *C,
GPU_matrix_mul(matrix_align);
}
+ const float screen_scale = mat4_to_scale(matrix_final);
+
if (select) {
BLI_assert(is_3d);
- button2d_geom_draw_backdrop(gz, color, 1.0, select);
+ button2d_geom_draw_backdrop(gz, color, 1.0, select, screen_scale);
}
else {
@@ -194,7 +200,7 @@ static void button2d_draw_intern(const bContext *C,
if (draw_options & ED_GIZMO_BUTTON_SHOW_BACKDROP) {
const float fill_alpha = RNA_float_get(gz->ptr, "backdrop_fill_alpha");
- button2d_geom_draw_backdrop(gz, color, fill_alpha, select);
+ button2d_geom_draw_backdrop(gz, color, fill_alpha, select, screen_scale);
}
if (button->shape_batch[0] != NULL) {
@@ -315,10 +321,11 @@ static int gizmo_button2d_cursor_get(wmGizmo *gz)
return WM_CURSOR_DEFAULT;
}
+#define CIRCLE_RESOLUTION_3D 32
static bool gizmo_button2d_bounds(bContext *C, wmGizmo *gz, rcti *r_bounding_box)
{
ScrArea *area = CTX_wm_area(C);
- float rad = CIRCLE_RESOLUTION * U.dpi_fac / 2.0f;
+ float rad = CIRCLE_RESOLUTION_3D * U.dpi_fac / 2.0f;
const float *co = NULL;
float matrix_final[4][4];
float co_proj[3];
@@ -342,6 +349,7 @@ static bool gizmo_button2d_bounds(bContext *C, wmGizmo *gz, rcti *r_bounding_box
}
}
else {
+ rad = mat4_to_scale(matrix_final);
co = matrix_final[3];
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
index 1d9fc35eda8..9b7b157dc7e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
@@ -77,6 +77,21 @@ typedef struct DialInteraction {
#define DIAL_CLIP_BIAS 0.02
/* -------------------------------------------------------------------- */
+struct Dial3dParams {
+ int draw_options;
+ float angle_ofs;
+ float angle_delta;
+ float angle_increment;
+ float arc_partial_angle;
+ float arc_inner_factor;
+ float *clip_plane;
+};
+static void dial_3d_draw_util(const float matrix_basis[4][4],
+ const float matrix_final[4][4],
+ const float line_width,
+ const float color[4],
+ const bool select,
+ struct Dial3dParams *params);
static void dial_geom_draw(const float color[4],
const float line_width,
@@ -411,23 +426,26 @@ static void dial_draw_intern(
if (WM_gizmo_target_property_is_valid(gz_prop)) {
angle_delta = WM_gizmo_target_property_float_get(gz, gz_prop);
}
+ if (gz->state & WM_GIZMO_STATE_MODAL) {
+ angle_increment = RNA_float_get(gz->ptr, "incremental_angle");
+ }
}
}
- ED_gizmotypes_dial_3d_draw_util(gz->matrix_basis,
- matrix_final,
- gz->line_width,
- color,
- select,
- &(struct Dial3dParams){
- .draw_options = draw_options,
- .angle_ofs = angle_ofs,
- .angle_delta = angle_delta,
- .angle_increment = angle_increment,
- .arc_partial_angle = arc_partial_angle,
- .arc_inner_factor = arc_inner_factor,
- .clip_plane = clip_plane,
- });
+ dial_3d_draw_util(gz->matrix_basis,
+ matrix_final,
+ gz->line_width,
+ color,
+ select,
+ &(struct Dial3dParams){
+ .draw_options = draw_options,
+ .angle_ofs = angle_ofs,
+ .angle_delta = angle_delta,
+ .angle_increment = angle_increment,
+ .arc_partial_angle = arc_partial_angle,
+ .arc_inner_factor = arc_inner_factor,
+ .clip_plane = clip_plane,
+ });
}
static void gizmo_dial_draw_select(const bContext *C, wmGizmo *gz, int select_id)
@@ -479,6 +497,10 @@ static int gizmo_dial_modal(bContext *C,
eWM_GizmoFlagTweak tweak_flag)
{
DialInteraction *inter = gz->interaction_data;
+ if (!inter) {
+ return OPERATOR_CANCELLED;
+ }
+
if ((event->type != MOUSEMOVE) && (inter->prev.tweak_flag == tweak_flag)) {
return OPERATOR_RUNNING_MODAL;
}
@@ -519,30 +541,33 @@ static int gizmo_dial_modal(bContext *C,
static void gizmo_dial_exit(bContext *C, wmGizmo *gz, const bool cancel)
{
DialInteraction *inter = gz->interaction_data;
- bool use_reset_value = false;
- float reset_value = 0.0f;
- if (cancel) {
- /* Set the property for the operator and call its modal function. */
- wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
- if (WM_gizmo_target_property_is_valid(gz_prop)) {
- use_reset_value = true;
- reset_value = inter->init.prop_angle;
- }
- }
- else {
- if (inter->has_drag == false) {
- PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value");
- if (RNA_property_is_set(gz->ptr, prop)) {
+ if (inter) {
+ bool use_reset_value = false;
+ float reset_value = 0.0f;
+
+ if (cancel) {
+ /* Set the property for the operator and call its modal function. */
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
use_reset_value = true;
- reset_value = RNA_property_float_get(gz->ptr, prop);
+ reset_value = inter->init.prop_angle;
+ }
+ }
+ else {
+ if (inter->has_drag == false) {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value");
+ if (RNA_property_is_set(gz->ptr, prop)) {
+ use_reset_value = true;
+ reset_value = RNA_property_float_get(gz->ptr, prop);
+ }
}
}
- }
- if (use_reset_value) {
- wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
- if (WM_gizmo_target_property_is_valid(gz_prop)) {
- WM_gizmo_target_property_float_set(C, gz, gz_prop, reset_value);
+ if (use_reset_value) {
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_float_set(C, gz, gz_prop, reset_value);
+ }
}
}
@@ -564,6 +589,11 @@ static void gizmo_dial_setup(wmGizmo *gz)
static int gizmo_dial_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event)
{
+ if (gz->custom_modal) {
+ /* #DialInteraction is only used for the inner modal. */
+ return OPERATOR_RUNNING_MODAL;
+ }
+
DialInteraction *inter = MEM_callocN(sizeof(DialInteraction), __func__);
inter->init.mval[0] = event->mval[0];
@@ -583,12 +613,12 @@ static int gizmo_dial_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *ev
/** \name Dial Gizmo API
* \{ */
-void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
- const float matrix_final[4][4],
- const float line_width,
- const float color[4],
- const bool select,
- struct Dial3dParams *params)
+static void dial_3d_draw_util(const float matrix_basis[4][4],
+ const float matrix_final[4][4],
+ const float line_width,
+ const float color[4],
+ const bool select,
+ struct Dial3dParams *params)
{
GPU_matrix_push();
GPU_matrix_mul(matrix_final);
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index 46fede8f6be..1ce67185c1e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -280,7 +280,7 @@ static int gizmo_move_modal(bContext *C,
CTX_wm_view3d(C),
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_EDIT,
.use_occlusion_test = true,
},
diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
index 1659afb1254..d468906f127 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
@@ -96,7 +96,7 @@ void ED_gizmotypes_snap_3d_data_get(const struct bContext *C,
float r_loc[3],
float r_nor[3],
int r_elem_index[3],
- int *r_snap_elem)
+ eSnapMode *r_snap_elem)
{
if (C) {
/* Snap values are updated too late at the cursor. Be sure to update ahead of time. */
@@ -283,7 +283,7 @@ static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2])
ED_view3d_cursor_snap_data_update(snap_gizmo->snap_state, C, x, y);
V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get();
- if (snap_data->snap_elem) {
+ if (snap_data->snap_elem != SCE_SNAP_MODE_NONE) {
return 0;
}
return -1;
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 011a5a66695..24de50db397 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -80,9 +80,9 @@ typedef enum eDrawStrokeFlags {
GP_DRAWDATA_ONLYI2D = (1 << 3),
/** special hack for drawing strokes in Image Editor (weird coordinates) */
GP_DRAWDATA_IEDITHACK = (1 << 4),
- /** don't draw xray in 3D view (which is default) */
+ /** Don't draw XRAY in 3D view (which is default). */
GP_DRAWDATA_NO_XRAY = (1 << 5),
- /** no onionskins should be drawn (for animation playback) */
+ /** No onion-skins should be drawn (for animation playback). */
GP_DRAWDATA_NO_ONIONS = (1 << 6),
/** draw strokes as "volumetric" circular billboards */
GP_DRAWDATA_VOLUMETRIC = (1 << 7),
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 4f9468cc9c4..0601d009bf7 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -1104,7 +1104,7 @@ static void gpencil_stroke_to_bezier(bContext *C,
rad_fac,
minmax_weights);
- /* shift coord vects */
+ /* Shift coord vectors. */
copy_v3_v3(p3d_prev, p3d_cur);
copy_v3_v3(p3d_cur, p3d_next);
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 56c94e4494d..d656241c463 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -726,16 +726,16 @@ struct GP_EditableStrokes_Iter {
(void)0
/**
- * Iterate over all editable editcurves in the current context,
- * stopping on each usable layer + stroke + curve pair (i.e. gpl, gps and gpc)
+ * Iterate over all editable edit-curves in the current context,
+ * stopping on each usable layer + stroke + curve pair (i.e. `gpl`, `gps` and `gpc`)
* to perform some operations on the curve.
*
* \param gpl: The identifier to use for the layer of the stroke being processed.
- * Choose a suitable value to avoid name clashes.
+ * Choose a suitable value to avoid name clashes.
* \param gps: The identifier to use for current stroke being processed.
- * Choose a suitable value to avoid name clashes.
+ * Choose a suitable value to avoid name clashes.
* \param gpc: The identifier to use for current editcurve being processed.
- * Choose a suitable value to avoid name clashes.
+ * Choose a suitable value to avoid name clashes.
*/
#define GP_EDITABLE_CURVES_BEGIN(gpstroke_iter, C, gpl, gps, gpc) \
{ \
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 01ac02a9a1d..6d0848de36d 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -829,7 +829,7 @@ static bool gpencil_brush_randomize_apply(tGP_BrushEditData *gso,
mul_v2_fl(svec, fac);
}
- /* convert to dataspace */
+ /* Convert to data-space. */
if (gps->flag & GP_STROKE_3DSPACE) {
/* 3D: Project to 3D space */
bool flip;
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index a37dc99229c..e903d11a1e0 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -1701,7 +1701,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
const bool select = (sel_op != SEL_OP_SUB);
bool changed = false;
- /* for bounding rect around circle (for quicky intersection testing) */
+ /* For bounding `rect` around circle (for quickly intersection testing). */
rcti rect = {0};
rect.xmin = mx - radius;
rect.ymin = my - radius;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 23c385c1213..fc5b3838900 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -525,7 +525,7 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps
return (area->spacetype == SPACE_IMAGE);
}
if (gps->flag & GP_STROKE_2DSPACE) {
- /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */
+ /* 2D strokes (data-space) - for any 2D view (i.e. everything other than 3D view). */
return (area->spacetype != SPACE_VIEW3D);
}
/* view aligned - anything goes */
@@ -1149,7 +1149,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
depsgraph,
v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
},
&ray_start[0],
&ray_normal[0],
@@ -1747,7 +1747,7 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
float darkcolor[3];
float radius = 3.0f;
- int mval_i[2] = {x, y};
+ const int mval_i[2] = {x, y};
/* Check if cursor is in drawing region and has valid data-block. */
if ((!gpencil_check_cursor_region(C, mval_i)) || (gpd == NULL)) {
return;
@@ -2962,7 +2962,7 @@ void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc,
bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
bGPDstroke *gps,
- const float mouse[2],
+ const float mval[2],
const int radius,
const float diff_mat[4][4])
{
@@ -2980,7 +2980,7 @@ bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
rcti rect_stroke = {boundbox_min[0], boundbox_max[0], boundbox_min[1], boundbox_max[1]};
/* For mouse, add a small offset to avoid false negative in corners. */
- rcti rect_mouse = {mouse[0] - offset, mouse[0] + offset, mouse[1] - offset, mouse[1] + offset};
+ rcti rect_mouse = {mval[0] - offset, mval[0] + offset, mval[1] - offset, mval[1] + offset};
/* Check collision between both rectangles. */
return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL);
@@ -2988,7 +2988,7 @@ bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
const GP_SpaceConversion *gsc,
- const int mouse[2],
+ const int mval[2],
const float diff_mat[4][4])
{
bool hit = false;
@@ -3014,9 +3014,8 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
BLI_lasso_boundbox(&rect, mcoords, len);
/* Test if point inside stroke. */
- hit = ((!ELEM(V2D_IS_CLIPPED, mouse[0], mouse[1])) &&
- BLI_rcti_isect_pt(&rect, mouse[0], mouse[1]) &&
- BLI_lasso_is_point_inside(mcoords, len, mouse[0], mouse[1], INT_MAX));
+ hit = ((!ELEM(V2D_IS_CLIPPED, mval[0], mval[1])) && BLI_rcti_isect_pt(&rect, mval[0], mval[1]) &&
+ BLI_lasso_is_point_inside(mcoords, len, mval[0], mval[1], INT_MAX));
/* Free memory. */
MEM_SAFE_FREE(mcoords);
diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c
index c0888968a2d..865c4e360b5 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_ops.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c
@@ -587,7 +587,7 @@ static int gpencil_vertexpaint_set_exec(bContext *C, wmOperator *op)
srgb_to_linearrgb_v4(color, color);
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if ((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) {
- copy_v3_v3(pt->vert_color, color);
+ copy_v4_v4(pt->vert_color, color);
}
}
}
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 2c67b02611b..c5a45f8b73e 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -60,7 +60,7 @@ bool ED_space_clip_get_position(struct SpaceClip *sc,
*/
bool ED_space_clip_color_sample(struct SpaceClip *sc,
struct ARegion *region,
- int mval[2],
+ const int mval[2],
float r_col[3]);
void ED_clip_update_frame(const struct Main *mainp, int cfra);
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index c3a66e4a7dd..e3b091430e8 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -103,6 +103,9 @@ extern const char datatoc_multiply_png[];
extern int datatoc_nudge_png_size;
extern const char datatoc_nudge_png[];
+extern int datatoc_paint_select_png_size;
+extern const char datatoc_paint_select_png[];
+
extern int datatoc_pinch_png_size;
extern const char datatoc_pinch_png[];
@@ -284,6 +287,41 @@ extern const char datatoc_gp_brush_erase_hard_png[];
extern int datatoc_gp_brush_erase_stroke_png_size;
extern const char datatoc_gp_brush_erase_stroke_png[];
+/* curves sculpt brushes files */
+
+extern int datatoc_curves_sculpt_add_png_size;
+extern const char datatoc_curves_sculpt_add_png[];
+
+extern int datatoc_curves_sculpt_comb_png_size;
+extern const char datatoc_curves_sculpt_comb_png[];
+
+extern int datatoc_curves_sculpt_cut_png_size;
+extern const char datatoc_curves_sculpt_cut_png[];
+
+extern int datatoc_curves_sculpt_delete_png_size;
+extern const char datatoc_curves_sculpt_delete_png[];
+
+extern int datatoc_curves_sculpt_density_png_size;
+extern const char datatoc_curves_sculpt_density_png[];
+
+extern int datatoc_curves_sculpt_grow_shrink_png_size;
+extern const char datatoc_curves_sculpt_grow_shrink_png[];
+
+extern int datatoc_curves_sculpt_pinch_png_size;
+extern const char datatoc_curves_sculpt_pinch_png[];
+
+extern int datatoc_curves_sculpt_puff_png_size;
+extern const char datatoc_curves_sculpt_puff_png[];
+
+extern int datatoc_curves_sculpt_slide_png_size;
+extern const char datatoc_curves_sculpt_slide_png[];
+
+extern int datatoc_curves_sculpt_smooth_png_size;
+extern const char datatoc_curves_sculpt_smooth_png[];
+
+extern int datatoc_curves_sculpt_snake_hook_png_size;
+extern const char datatoc_curves_sculpt_snake_hook_png[];
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 067e5ba4d7f..31c1f93f5bc 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -14,6 +14,8 @@
extern "C" {
#endif
+#include "DNA_scene_types.h"
+
/* initialize gizmos */
void ED_gizmotypes_arrow_3d(void);
void ED_gizmotypes_button_2d(void);
@@ -223,24 +225,6 @@ enum {
/* -------------------------------------------------------------------- */
/* Specific gizmos utils */
-/* dial3d_gizmo.c */
-
-struct Dial3dParams {
- int draw_options;
- float angle_ofs;
- float angle_delta;
- float angle_increment;
- float arc_partial_angle;
- float arc_inner_factor;
- float *clip_plane;
-};
-void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
- const float matrix_final[4][4],
- float line_width,
- const float color[4],
- bool select,
- struct Dial3dParams *params);
-
/* snap3d_gizmo.c */
struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *scene,
@@ -258,7 +242,7 @@ void ED_gizmotypes_snap_3d_data_get(const struct bContext *C,
float r_loc[3],
float r_nor[3],
int r_elem_index[3],
- int *r_snap_elem);
+ eSnapMode *r_snap_elem);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 01f60a81288..0943636a452 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -579,7 +579,7 @@ void ED_gpencil_init_random_settings(struct Brush *brush,
*/
bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc,
struct bGPDstroke *gps,
- const float mouse[2],
+ const float mval[2],
int radius,
const float diff_mat[4][4]);
/**
@@ -587,13 +587,13 @@ bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc,
*
* \param gps: Stroke to check.
* \param gsc: Space conversion data.
- * \param mouse: Mouse position.
+ * \param mval: Region relative cursor position.
* \param diff_mat: View matrix.
* \return True if the point is inside.
*/
bool ED_gpencil_stroke_point_is_inside(const struct bGPDstroke *gps,
const struct GP_SpaceConversion *gsc,
- const int mouse[2],
+ const int mval[2],
const float diff_mat[4][4]);
/**
* Get the bigger 2D bound box points.
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 774115fa188..b16844c01ea 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -24,6 +24,7 @@ struct Scene;
struct SpaceImage;
struct View2D;
struct bContext;
+struct Paint;
struct wmOperator;
struct wmWindowManager;
@@ -63,8 +64,11 @@ bool ED_space_image_get_position(struct SpaceImage *sima,
/**
* Returns color in linear space, matching #ED_space_node_color_sample().
*/
-bool ED_space_image_color_sample(
- struct SpaceImage *sima, struct ARegion *region, int mval[2], float r_col[3], bool *r_is_data);
+bool ED_space_image_color_sample(struct SpaceImage *sima,
+ struct ARegion *region,
+ const int mval[2],
+ float r_col[3],
+ bool *r_is_data);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock, int tile);
/**
* Get the #SpaceImage flag that is valid for the given ibuf.
@@ -187,6 +191,9 @@ ListBase ED_image_filesel_detect_sequences(struct Main *bmain,
struct wmOperator *op,
bool detect_udim);
+bool ED_image_tools_paint_poll(struct bContext *C);
+void ED_paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 8c0147612fb..a53042b70d6 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -658,15 +658,20 @@ bool ED_autokeyframe_pchan(struct bContext *C,
struct Object *ob,
struct bPoseChannel *pchan,
struct KeyingSet *ks);
+
/**
- * Use for auto-key-framing from the UI.
+ * Use for auto-key-framing
+ * \param only_if_property_keyed: if true, auto-key-framing only creates keyframes on already keyed
+ * properties. This is by design when using buttons. For other callers such as gizmos or VSE
+ * preview transform, creating new animation/keyframes also on non-keyed properties is desired.
*/
bool ED_autokeyframe_property(struct bContext *C,
struct Scene *scene,
PointerRNA *ptr,
PropertyRNA *prop,
int rnaindex,
- float cfra);
+ float cfra,
+ bool only_if_property_keyed);
/* Names for builtin keying sets so we don't confuse these with labels/text,
* defined in python script: `keyingsets_builtins.py`. */
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 54d67c50d5c..550040d2bc6 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -51,7 +51,7 @@ void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, int new_id);
int ED_sculpt_face_sets_active_update_and_get(struct bContext *C,
struct Object *ob,
- const float mval[2]);
+ const float mval_fl[2]);
/* Undo for changes happening on a base mesh for multires sculpting.
* if there is no multi-res sculpt active regular undo is used. */
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index 2919001c5ce..20353c21f93 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -6,6 +6,8 @@
#pragma once
+#include "DNA_scene_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -25,14 +27,6 @@ struct View3D;
/* ED_transform_snap_object_*** API */
-typedef enum eSnapSelect {
- SNAP_ALL = 0,
- SNAP_NOT_SELECTED = 1,
- SNAP_NOT_ACTIVE = 2,
- SNAP_NOT_EDITED = 3,
- SNAP_SELECTABLE = 4,
-} eSnapSelect;
-
typedef enum eSnapEditType {
SNAP_GEOM_FINAL = 0,
SNAP_GEOM_CAGE = 1,
@@ -59,7 +53,7 @@ struct SnapObjectHitDepth {
/** parameters that define which objects will be used to snap. */
struct SnapObjectParams {
/* Special context sensitive handling for the active or selected object. */
- eSnapSelect snap_select;
+ eSnapTargetSelect snap_target_select;
/* Geometry for snapping in edit mode. */
eSnapEditType edit_mode_type;
/* snap to the closest element, use when using more than one snap type */
@@ -120,21 +114,21 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
bool sort,
struct ListBase *r_hit_list);
-short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
- struct Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- unsigned short snap_to,
- const struct SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3],
- int *r_index,
- struct Object **r_ob,
- float r_obmat[4][4],
- float r_face_nor[3]);
+eSnapMode ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
+ struct Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ eSnapMode snap_to,
+ const struct SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3],
+ int *r_index,
+ struct Object **r_ob,
+ float r_obmat[4][4],
+ float r_face_nor[3]);
/**
* Convenience function for performing snapping.
*
@@ -148,18 +142,18 @@ short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
* \param r_no: hit normal (optional).
* \return Snap success.
*/
-short ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
- struct Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- unsigned short snap_to,
- const struct SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3]);
+eSnapMode ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
+ struct Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ eSnapMode snap_to,
+ const struct SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3]);
/**
* see: #ED_transform_snap_object_project_ray_all
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 8695e03a57f..0298983ed26 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -8,6 +8,7 @@
#pragma once
#include "BLI_utildefines.h"
+#include "DNA_scene_types.h"
#ifdef __cplusplus
extern "C" {
@@ -299,7 +300,7 @@ typedef enum {
} eV3DPlaceOrient;
typedef struct V3DSnapCursorData {
- short snap_elem;
+ eSnapMode snap_elem;
float loc[3];
float nor[3];
float obmat[4][4];
@@ -322,7 +323,7 @@ typedef struct V3DSnapCursorState {
struct wmGizmoGroupType *gzgrp_type; /* Force cursor to be drawn only when gizmo is available. */
float *prevpoint;
float box_dimensions[3];
- short snap_elem_force; /* If zero, use scene settings. */
+ eSnapMode snap_elem_force; /* If SCE_SNAP_MODE_NONE, use scene settings. */
short plane_axis;
bool use_plane_axis_auto;
bool draw_point;
@@ -347,7 +348,7 @@ void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d,
const float normal[3],
const uchar color_line[4],
const uchar color_point[4],
- short snap_elem_type);
+ eSnapMode snap_elem_type);
/* view3d_iterators.c */
diff --git a/source/blender/editors/include/UI_grid_view.hh b/source/blender/editors/include/UI_grid_view.hh
new file mode 100644
index 00000000000..6f553f4fad1
--- /dev/null
+++ b/source/blender/editors/include/UI_grid_view.hh
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup editorui
+ *
+ * API for simple creation of grid UIs, supporting typically needed features.
+ * https://wiki.blender.org/wiki/Source/Interface/Views/Grid_Views
+ */
+
+#pragma once
+
+#include "BLI_function_ref.hh"
+#include "BLI_map.hh"
+#include "BLI_vector.hh"
+
+#include "UI_resources.h"
+
+struct bContext;
+struct PreviewImage;
+struct uiBlock;
+struct uiButGridTile;
+struct uiLayout;
+struct View2D;
+struct wmNotifier;
+
+namespace blender::ui {
+
+class AbstractGridView;
+
+/* ---------------------------------------------------------------------- */
+/** \name Grid-View Item Type
+ * \{ */
+
+class AbstractGridViewItem {
+ friend class AbstractGridView;
+ friend class GridViewLayoutBuilder;
+
+ const AbstractGridView *view_;
+
+ bool is_active_ = false;
+
+ protected:
+ /** Reference to a string that uniquely identifies this item in the view. */
+ StringRef identifier_{};
+ /** Every visible item gets a button of type #UI_BTYPE_GRID_TILE during the layout building. */
+ uiButGridTile *grid_tile_but_ = nullptr;
+
+ public:
+ virtual ~AbstractGridViewItem() = default;
+
+ virtual void build_grid_tile(uiLayout &layout) const = 0;
+
+ /**
+ * Compare this item's identifier to \a other to check if they represent the same data.
+ * Used to recognize an item from a previous redraw, to be able to keep its state (e.g. active,
+ * renaming, etc.).
+ */
+ bool matches(const AbstractGridViewItem &other) const;
+
+ const AbstractGridView &get_view() const;
+
+ /**
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
+ * can't be sure about the item state.
+ */
+ bool is_active() const;
+
+ protected:
+ AbstractGridViewItem(StringRef identifier);
+
+ /** Called when the item's state changes from inactive to active. */
+ virtual void on_activate();
+ /**
+ * If the result is not empty, it controls whether the item should be active or not,
+ * usually depending on the data that the view represents.
+ */
+ virtual std::optional<bool> should_be_active() const;
+
+ /**
+ * Copy persistent state (e.g. active, selection, etc.) from a matching item of
+ * the last redraw to this item. If sub-classes introduce more advanced state they should
+ * override this and make it update their state accordingly.
+ */
+ virtual void update_from_old(const AbstractGridViewItem &old);
+
+ /**
+ * Activates this item, deactivates other items, and calls the
+ * #AbstractGridViewItem::on_activate() function.
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the
+ * actual item state is unknown, possibly calling state-change update functions incorrectly.
+ */
+ void activate();
+ void deactivate();
+
+ private:
+ /** See #AbstractTreeView::change_state_delayed() */
+ void change_state_delayed();
+ static void grid_tile_click_fn(bContext *, void *but_arg1, void *);
+ void add_grid_tile_button(uiBlock &block);
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Grid-View Base Class
+ * \{ */
+
+struct GridViewStyle {
+ GridViewStyle(int width, int height);
+ int tile_width = 0;
+ int tile_height = 0;
+};
+
+class AbstractGridView {
+ friend class AbstractGridViewItem;
+ friend class GridViewBuilder;
+ friend class GridViewLayoutBuilder;
+
+ protected:
+ Vector<std::unique_ptr<AbstractGridViewItem>> items_;
+ /** <identifier, item> map to lookup items by identifier, used for efficient lookups in
+ * #update_from_old(). */
+ Map<StringRef, AbstractGridViewItem *> item_map_;
+ GridViewStyle style_;
+ bool is_reconstructed_ = false;
+
+ public:
+ AbstractGridView();
+ virtual ~AbstractGridView() = default;
+
+ using ItemIterFn = FunctionRef<void(AbstractGridViewItem &)>;
+ void foreach_item(ItemIterFn iter_fn) const;
+
+ /** Listen to a notifier, returning true if a redraw is needed. */
+ virtual bool listen(const wmNotifier &) const;
+
+ /**
+ * Convenience wrapper constructing the item by forwarding given arguments to the constructor of
+ * the type (\a ItemT).
+ *
+ * E.g. if your grid-item type has the following constructor:
+ * \code{.cpp}
+ * MyGridItem(std::string str, int i);
+ * \endcode
+ * You can add an item like this:
+ * \code
+ * add_item<MyGridItem>("blabla", 42);
+ * \endcode
+ */
+ template<class ItemT, typename... Args> inline ItemT &add_item(Args &&...args);
+ const GridViewStyle &get_style() const;
+ int get_item_count() const;
+
+ protected:
+ virtual void build_items() = 0;
+
+ /**
+ * Check if the view is fully (re-)constructed. That means, both #build_items() and
+ * #update_from_old() have finished.
+ */
+ bool is_reconstructed() const;
+
+ private:
+ /**
+ * Match the grid-view against an earlier version of itself (if any) and copy the old UI state
+ * (e.g. active, selected, renaming, etc.) to the new one. See
+ * #AbstractGridViewItem.update_from_old().
+ */
+ void update_from_old(uiBlock &new_block);
+ AbstractGridViewItem *find_matching_item(const AbstractGridViewItem &item_to_match,
+ const AbstractGridView &view_to_search_in) const;
+ /**
+ * Items may want to do additional work when state changes. But these state changes can only be
+ * reliably detected after the view has completed reconstruction (see #is_reconstructed()). So
+ * the actual state changes are done in a delayed manner through this function.
+ */
+ void change_state_delayed();
+
+ /**
+ * Add an already constructed item, moving ownership to the grid-view.
+ * All items must be added through this, it handles important invariants!
+ */
+ AbstractGridViewItem &add_item(std::unique_ptr<AbstractGridViewItem> item);
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Grid-View Builder
+ *
+ * TODO unify this with `TreeViewBuilder` and call view-specific functions via type erased view?
+ * \{ */
+
+class GridViewBuilder {
+ uiBlock &block_;
+
+ public:
+ GridViewBuilder(uiBlock &block);
+
+ /** Build \a grid_view into the previously provided block, clipped by \a view_bounds (view space,
+ * typically `View2D.cur`). */
+ void build_grid_view(AbstractGridView &grid_view, const View2D &v2d);
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Predefined Grid-View Item Types
+ *
+ * Common, Basic Grid-View Item Types.
+ * \{ */
+
+/**
+ * A grid item that shows preview image icons at a nicely readable size (multiple of the normal UI
+ * unit size).
+ */
+class PreviewGridItem : public AbstractGridViewItem {
+ public:
+ using IsActiveFn = std::function<bool()>;
+ using ActivateFn = std::function<void(PreviewGridItem &new_active)>;
+
+ protected:
+ /** See #set_on_activate_fn() */
+ ActivateFn activate_fn_;
+ /** See #set_is_active_fn() */
+ IsActiveFn is_active_fn_;
+
+ public:
+ std::string label{};
+ int preview_icon_id = ICON_NONE;
+
+ PreviewGridItem(StringRef identifier, StringRef label, int preview_icon_id);
+
+ void build_grid_tile(uiLayout &layout) const override;
+
+ /**
+ * Set a custom callback to execute when activating this view item. This way users don't have to
+ * sub-class #PreviewGridItem, just to implement custom activation behavior (a common thing to
+ * do).
+ */
+ void set_on_activate_fn(ActivateFn fn);
+ /**
+ * Set a custom callback to check if this item should be active.
+ */
+ void set_is_active_fn(IsActiveFn fn);
+
+ private:
+ std::optional<bool> should_be_active() const override;
+ void on_activate() override;
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+
+template<class ItemT, typename... Args> inline ItemT &AbstractGridView::add_item(Args &&...args)
+{
+ static_assert(std::is_base_of<AbstractGridViewItem, ItemT>::value,
+ "Type must derive from and implement the AbstractGridViewItem interface");
+
+ return dynamic_cast<ItemT &>(add_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
+}
+
+} // namespace blender::ui
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index ea1095b26ff..f1c0acf43f7 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -891,6 +891,7 @@ DEF_ICON_COLOR(BRUSH_LAYER)
DEF_ICON_COLOR(BRUSH_MASK)
DEF_ICON_COLOR(BRUSH_MIX)
DEF_ICON_COLOR(BRUSH_NUDGE)
+DEF_ICON_COLOR(BRUSH_PAINT_SELECT)
DEF_ICON_COLOR(BRUSH_PINCH)
DEF_ICON_COLOR(BRUSH_SCRAPE)
DEF_ICON_COLOR(BRUSH_SCULPT_DRAW)
@@ -903,7 +904,6 @@ DEF_ICON_COLOR(BRUSH_TEXFILL)
DEF_ICON_COLOR(BRUSH_TEXMASK)
DEF_ICON_COLOR(BRUSH_THUMB)
DEF_ICON_COLOR(BRUSH_ROTATE)
-DEF_ICON_COLOR(BRUSH_PAINT)
/* grease pencil sculpt */
DEF_ICON_COLOR(GPBRUSH_SMOOTH)
@@ -929,6 +929,19 @@ DEF_ICON_COLOR(GPBRUSH_ERASE_SOFT)
DEF_ICON_COLOR(GPBRUSH_ERASE_HARD)
DEF_ICON_COLOR(GPBRUSH_ERASE_STROKE)
+/* Curves sculpt. */
+DEF_ICON_COLOR(BRUSH_CURVES_ADD)
+DEF_ICON_COLOR(BRUSH_CURVES_COMB)
+DEF_ICON_COLOR(BRUSH_CURVES_CUT)
+DEF_ICON_COLOR(BRUSH_CURVES_DELETE)
+DEF_ICON_COLOR(BRUSH_CURVES_DENSITY)
+DEF_ICON_COLOR(BRUSH_CURVES_GROW_SHRINK)
+DEF_ICON_COLOR(BRUSH_CURVES_PINCH)
+DEF_ICON_COLOR(BRUSH_CURVES_PUFF)
+DEF_ICON_COLOR(BRUSH_CURVES_SLIDE)
+DEF_ICON_COLOR(BRUSH_CURVES_SMOOTH)
+DEF_ICON_COLOR(BRUSH_CURVES_SNAKE_HOOK)
+
/* Vector icons. */
DEF_ICON_VECTOR(KEYTYPE_KEYFRAME_VEC)
DEF_ICON_VECTOR(KEYTYPE_BREAKDOWN_VEC)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index a9a9c98cab8..b2ec2102ddd 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -64,6 +64,7 @@ struct wmKeyMapItem;
struct wmMsgBus;
struct wmOperator;
struct wmOperatorType;
+struct wmRegionListenerParams;
struct wmWindow;
typedef struct uiBlock uiBlock;
@@ -75,6 +76,10 @@ typedef struct uiPopupBlockHandle uiPopupBlockHandle;
typedef struct uiTreeViewHandle uiTreeViewHandle;
/* C handle for C++ #ui::AbstractTreeViewItem type. */
typedef struct uiTreeViewItemHandle uiTreeViewItemHandle;
+/* C handle for C++ #ui::AbstractGridView type. */
+typedef struct uiGridViewHandle uiGridViewHandle;
+/* C handle for C++ #ui::AbstractGridViewItem type. */
+typedef struct uiGridViewItemHandle uiGridViewItemHandle;
/* Defines */
@@ -390,6 +395,8 @@ typedef enum {
UI_BTYPE_DECORATOR = 58 << 9,
/* An item in a tree view. Parent items may be collapsible. */
UI_BTYPE_TREEROW = 59 << 9,
+ /* An item in a grid view. */
+ UI_BTYPE_GRID_TILE = 60 << 9,
} eButType;
#define BUTTYPE (63 << 9)
@@ -851,33 +858,6 @@ void UI_block_translate(uiBlock *block, int x, int y);
int UI_but_return_value_get(uiBut *but);
-void UI_but_drag_set_id(uiBut *but, struct ID *id);
-/**
- * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`).
- * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image.
- */
-void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale);
-/**
- * \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
- */
-void UI_but_drag_set_asset(uiBut *but,
- const struct AssetHandle *asset,
- const char *path,
- struct AssetMetaData *metadata,
- int import_type, /* eFileAssetImportType */
- int icon,
- struct ImBuf *imb,
- float scale);
-void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr);
-void UI_but_drag_set_path(uiBut *but, const char *path, bool use_free);
-void UI_but_drag_set_name(uiBut *but, const char *name);
-/**
- * Value from button itself.
- */
-void UI_but_drag_set_value(uiBut *but);
-void UI_but_drag_set_image(
- uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, bool use_free);
-
uiBut *UI_but_active_drop_name_button(const struct bContext *C);
/**
* Returns true if highlighted button allows drop of names.
@@ -1767,6 +1747,14 @@ struct PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
struct wmOperatorType *UI_but_extra_operator_icon_optype_get(struct uiButExtraOpIcon *extra_icon);
struct PointerRNA *UI_but_extra_operator_icon_opptr_get(struct uiButExtraOpIcon *extra_icon);
+/**
+ * A decent size for a button (typically #UI_BTYPE_PREVIEW_TILE) to display a nicely readable
+ * preview with label in.
+ */
+int UI_preview_tile_size_x(void);
+int UI_preview_tile_size_y(void);
+int UI_preview_tile_size_y_no_label(void);
+
/* Autocomplete
*
* Tab complete helper functions, for use in uiButCompleteFunc callbacks.
@@ -1783,6 +1771,38 @@ AutoComplete *UI_autocomplete_begin(const char *startname, size_t maxlen);
void UI_autocomplete_update_name(AutoComplete *autocpl, const char *name);
int UI_autocomplete_end(AutoComplete *autocpl, char *autoname);
+/* Button drag-data (interface_drag.cc).
+ *
+ * Functions to set drag data for buttons. This enables dragging support, whereby the drag data is
+ * "dragged", not the button itself. */
+
+void UI_but_drag_set_id(uiBut *but, struct ID *id);
+/**
+ * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`).
+ * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image.
+ */
+void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale);
+/**
+ * \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
+ */
+void UI_but_drag_set_asset(uiBut *but,
+ const struct AssetHandle *asset,
+ const char *path,
+ struct AssetMetaData *metadata,
+ int import_type, /* eFileAssetImportType */
+ int icon,
+ struct ImBuf *imb,
+ float scale);
+void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr);
+void UI_but_drag_set_path(uiBut *but, const char *path, bool use_free);
+void UI_but_drag_set_name(uiBut *but, const char *name);
+/**
+ * Value from button itself.
+ */
+void UI_but_drag_set_value(uiBut *but);
+void UI_but_drag_set_image(
+ uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, bool use_free);
+
/* Panels
*
* Functions for creating, freeing and drawing panels. The API here
@@ -1866,7 +1886,7 @@ struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContex
const struct wmEvent *event);
void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data);
-/* Polyinstantiated panels for representing a list of data. */
+/* Poly-instantiated panels for representing a list of data. */
/**
* Called in situations where panels need to be added dynamically rather than
* having only one panel corresponding to each #PanelType.
@@ -3180,7 +3200,12 @@ void UI_interface_tag_script_reload(void);
/* Support click-drag motion which presses the button and closes a popover (like a menu). */
#define USE_UI_POPOVER_ONCE
+void UI_block_views_listen(const uiBlock *block,
+ const struct wmRegionListenerParams *listener_params);
+
+bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle);
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
+bool UI_grid_view_item_matches(const uiGridViewItemHandle *a, const uiGridViewItemHandle *b);
bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
/**
* Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't
@@ -3218,6 +3243,15 @@ uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const struct ARegion *regi
const int xy[2]) ATTR_NONNULL(1, 2);
uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const struct ARegion *region);
+/**
+ * Listen to \a notifier, returning true if the region should redraw.
+ */
+bool UI_tree_view_listen_should_redraw(const uiTreeViewHandle *view, const wmNotifier *notifier);
+/**
+ * Listen to \a notifier, returning true if the region should redraw.
+ */
+bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view, const wmNotifier *notifier);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index db43ec54431..3dc56b01993 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -23,6 +23,7 @@ struct uiSearchItems;
namespace blender::ui {
+class AbstractGridView;
class AbstractTreeView;
/**
@@ -55,6 +56,10 @@ void attribute_search_add_items(
/**
* Override this for all available tree types.
*/
+blender::ui::AbstractGridView *UI_block_add_view(
+ uiBlock &block,
+ blender::StringRef idname,
+ std::unique_ptr<blender::ui::AbstractGridView> tree_view);
blender::ui::AbstractTreeView *UI_block_add_view(
uiBlock &block,
blender::StringRef idname,
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index 5504e426f34..1aeb13ca5cc 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -28,6 +28,7 @@ struct uiButTreeRow;
struct uiLayout;
struct wmDrag;
struct wmEvent;
+struct wmNotifier;
namespace blender::ui {
@@ -128,6 +129,9 @@ class AbstractTreeView : public TreeViewItemContainer {
void foreach_item(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const;
+ /** Listen to a notifier, returning true if a redraw is needed. */
+ virtual bool listen(const wmNotifier &) const;
+
/** Only one item can be renamed at a time. */
bool is_renaming() const;
@@ -185,7 +189,7 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
bool is_renaming_ = false;
protected:
- /** This label is used for identifying an item within its parent. */
+ /** This label is used as the default way to identifying an item within its parent. */
std::string label_{};
/** Every visible item gets a button of type #UI_BTYPE_TREEROW during the layout building. */
uiButTreeRow *tree_row_but_ = nullptr;
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 444bb08f3fb..2a1852bd6e7 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -25,12 +25,14 @@ set(INC
)
set(SRC
+ grid_view.cc
interface.cc
interface_align.c
interface_anim.c
interface_button_group.c
interface_context_menu.c
interface_context_path.cc
+ interface_drag.cc
interface_draw.c
interface_dropboxes.cc
interface_eyedropper.c
diff --git a/source/blender/editors/interface/grid_view.cc b/source/blender/editors/interface/grid_view.cc
new file mode 100644
index 00000000000..a82cb7798fe
--- /dev/null
+++ b/source/blender/editors/interface/grid_view.cc
@@ -0,0 +1,525 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include <limits>
+#include <stdexcept>
+
+#include "BLI_index_range.hh"
+
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "interface_intern.h"
+
+#include "UI_grid_view.hh"
+
+namespace blender::ui {
+
+/* ---------------------------------------------------------------------- */
+
+AbstractGridView::AbstractGridView() : style_(UI_preview_tile_size_x(), UI_preview_tile_size_y())
+{
+}
+
+AbstractGridViewItem &AbstractGridView::add_item(std::unique_ptr<AbstractGridViewItem> item)
+{
+ items_.append(std::move(item));
+
+ AbstractGridViewItem &added_item = *items_.last();
+ added_item.view_ = this;
+
+ item_map_.add(added_item.identifier_, &added_item);
+
+ return added_item;
+}
+
+void AbstractGridView::foreach_item(ItemIterFn iter_fn) const
+{
+ for (auto &item_ptr : items_) {
+ iter_fn(*item_ptr);
+ }
+}
+
+bool AbstractGridView::listen(const wmNotifier &) const
+{
+ /* Nothing by default. */
+ return false;
+}
+
+AbstractGridViewItem *AbstractGridView::find_matching_item(
+ const AbstractGridViewItem &item_to_match, const AbstractGridView &view_to_search_in) const
+{
+ AbstractGridViewItem *const *match = view_to_search_in.item_map_.lookup_ptr(
+ item_to_match.identifier_);
+ BLI_assert(!match || item_to_match.matches(**match));
+
+ return match ? *match : nullptr;
+}
+
+void AbstractGridView::change_state_delayed()
+{
+ BLI_assert_msg(
+ is_reconstructed(),
+ "These state changes are supposed to be delayed until reconstruction is completed");
+ foreach_item([](AbstractGridViewItem &item) { item.change_state_delayed(); });
+}
+
+void AbstractGridView::update_from_old(uiBlock &new_block)
+{
+ uiGridViewHandle *old_view_handle = ui_block_grid_view_find_matching_in_old_block(
+ &new_block, reinterpret_cast<uiGridViewHandle *>(this));
+ if (!old_view_handle) {
+ /* Initial construction, nothing to update. */
+ is_reconstructed_ = true;
+ return;
+ }
+
+ AbstractGridView &old_view = reinterpret_cast<AbstractGridView &>(*old_view_handle);
+
+ foreach_item([this, &old_view](AbstractGridViewItem &new_item) {
+ const AbstractGridViewItem *matching_old_item = find_matching_item(new_item, old_view);
+ if (!matching_old_item) {
+ return;
+ }
+
+ new_item.update_from_old(*matching_old_item);
+ });
+
+ /* Finished (re-)constructing the tree. */
+ is_reconstructed_ = true;
+}
+
+bool AbstractGridView::is_reconstructed() const
+{
+ return is_reconstructed_;
+}
+
+const GridViewStyle &AbstractGridView::get_style() const
+{
+ return style_;
+}
+
+int AbstractGridView::get_item_count() const
+{
+ return items_.size();
+}
+
+GridViewStyle::GridViewStyle(int width, int height) : tile_width(width), tile_height(height)
+{
+}
+
+/* ---------------------------------------------------------------------- */
+
+AbstractGridViewItem::AbstractGridViewItem(StringRef identifier) : identifier_(identifier)
+{
+}
+
+bool AbstractGridViewItem::matches(const AbstractGridViewItem &other) const
+{
+ return identifier_ == other.identifier_;
+}
+
+void AbstractGridViewItem::grid_tile_click_fn(struct bContext * /*C*/,
+ void *but_arg1,
+ void * /*arg2*/)
+{
+ uiButGridTile *grid_tile_but = (uiButGridTile *)but_arg1;
+ AbstractGridViewItem &grid_item = reinterpret_cast<AbstractGridViewItem &>(
+ *grid_tile_but->view_item);
+
+ grid_item.activate();
+}
+
+void AbstractGridViewItem::add_grid_tile_button(uiBlock &block)
+{
+ const GridViewStyle &style = get_view().get_style();
+ grid_tile_but_ = (uiButGridTile *)uiDefBut(&block,
+ UI_BTYPE_GRID_TILE,
+ 0,
+ "",
+ 0,
+ 0,
+ style.tile_width,
+ style.tile_height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+
+ grid_tile_but_->view_item = reinterpret_cast<uiGridViewItemHandle *>(this);
+ UI_but_func_set(&grid_tile_but_->but, grid_tile_click_fn, grid_tile_but_, nullptr);
+}
+
+bool AbstractGridViewItem::is_active() const
+{
+ BLI_assert_msg(get_view().is_reconstructed(),
+ "State can't be queried until reconstruction is completed");
+ return is_active_;
+}
+
+void AbstractGridViewItem::on_activate()
+{
+ /* Do nothing by default. */
+}
+
+std::optional<bool> AbstractGridViewItem::should_be_active() const
+{
+ return std::nullopt;
+}
+
+void AbstractGridViewItem::change_state_delayed()
+{
+ const std::optional<bool> should_be_active = this->should_be_active();
+ if (should_be_active.has_value() && *should_be_active) {
+ activate();
+ }
+}
+
+void AbstractGridViewItem::update_from_old(const AbstractGridViewItem &old)
+{
+ is_active_ = old.is_active_;
+}
+
+void AbstractGridViewItem::activate()
+{
+ BLI_assert_msg(get_view().is_reconstructed(),
+ "Item activation can't be done until reconstruction is completed");
+
+ if (is_active()) {
+ return;
+ }
+
+ /* Deactivate other items in the tree. */
+ get_view().foreach_item([](auto &item) { item.deactivate(); });
+
+ on_activate();
+
+ is_active_ = true;
+}
+
+void AbstractGridViewItem::deactivate()
+{
+ is_active_ = false;
+}
+
+const AbstractGridView &AbstractGridViewItem::get_view() const
+{
+ if (UNLIKELY(!view_)) {
+ throw std::runtime_error(
+ "Invalid state, item must be added through AbstractGridView::add_item()");
+ }
+ return *view_;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Helper for only adding layout items for grid items that are actually in view. 3 main functions:
+ * - #is_item_visible(): Query if an item of a given index is visible in the view (others should be
+ * skipped when building the layout).
+ * - #fill_layout_before_visible(): Add empty space to the layout before a visible row is drawn, so
+ * the layout height is the same as if all items were added (important to get the correct scroll
+ * height).
+ * - #fill_layout_after_visible(): Same thing, just adds empty space for after the last visible
+ * row.
+ *
+ * Does two assumptions:
+ * - Top-to-bottom flow (ymax = 0 and ymin < 0). If that's not good enough, View2D should
+ * probably provide queries for the scroll offset.
+ * - Only vertical scrolling. For horizontal scrolling, spacers would have to be added on the
+ * side(s) as well.
+ */
+class BuildOnlyVisibleButtonsHelper {
+ const View2D &v2d_;
+ const AbstractGridView &grid_view_;
+ const GridViewStyle &style_;
+ const int cols_per_row_ = 0;
+ /* Indices of items within the view. Calculated by constructor */
+ IndexRange visible_items_range_{};
+
+ public:
+ BuildOnlyVisibleButtonsHelper(const View2D &,
+ const AbstractGridView &grid_view,
+ int cols_per_row);
+
+ bool is_item_visible(int item_idx) const;
+ void fill_layout_before_visible(uiBlock &) const;
+ void fill_layout_after_visible(uiBlock &) const;
+
+ private:
+ IndexRange get_visible_range() const;
+ void add_spacer_button(uiBlock &, int row_count) const;
+};
+
+BuildOnlyVisibleButtonsHelper::BuildOnlyVisibleButtonsHelper(const View2D &v2d,
+ const AbstractGridView &grid_view,
+ const int cols_per_row)
+ : v2d_(v2d), grid_view_(grid_view), style_(grid_view.get_style()), cols_per_row_(cols_per_row)
+{
+ visible_items_range_ = get_visible_range();
+}
+
+IndexRange BuildOnlyVisibleButtonsHelper::get_visible_range() const
+{
+ int first_idx_in_view = 0;
+ int max_items_in_view = 0;
+
+ const float scroll_ofs_y = abs(v2d_.cur.ymax - v2d_.tot.ymax);
+ if (!IS_EQF(scroll_ofs_y, 0)) {
+ const int scrolled_away_rows = (int)scroll_ofs_y / style_.tile_height;
+
+ first_idx_in_view = scrolled_away_rows * cols_per_row_;
+ }
+
+ const float view_height = BLI_rctf_size_y(&v2d_.cur);
+ const int count_rows_in_view = std::max(round_fl_to_int(view_height / style_.tile_height), 1);
+ max_items_in_view = (count_rows_in_view + 1) * cols_per_row_;
+
+ BLI_assert(max_items_in_view > 0);
+ return IndexRange(first_idx_in_view, max_items_in_view);
+}
+
+bool BuildOnlyVisibleButtonsHelper::is_item_visible(const int item_idx) const
+{
+ return visible_items_range_.contains(item_idx);
+}
+
+void BuildOnlyVisibleButtonsHelper::fill_layout_before_visible(uiBlock &block) const
+{
+ const float scroll_ofs_y = abs(v2d_.cur.ymax - v2d_.tot.ymax);
+
+ if (IS_EQF(scroll_ofs_y, 0)) {
+ return;
+ }
+
+ const int scrolled_away_rows = (int)scroll_ofs_y / style_.tile_height;
+ add_spacer_button(block, scrolled_away_rows);
+}
+
+void BuildOnlyVisibleButtonsHelper::fill_layout_after_visible(uiBlock &block) const
+{
+ const int last_item_idx = grid_view_.get_item_count() - 1;
+ const int last_visible_idx = visible_items_range_.last();
+
+ if (last_item_idx > last_visible_idx) {
+ const int remaining_rows = (cols_per_row_ > 0) ?
+ (last_item_idx - last_visible_idx) / cols_per_row_ :
+ 0;
+ BuildOnlyVisibleButtonsHelper::add_spacer_button(block, remaining_rows);
+ }
+}
+
+void BuildOnlyVisibleButtonsHelper::add_spacer_button(uiBlock &block, const int row_count) const
+{
+ /* UI code only supports button dimensions of `signed short` size, the layout height we want to
+ * fill may be bigger than that. So add multiple labels of the maximum size if necessary. */
+ for (int remaining_rows = row_count; remaining_rows > 0;) {
+ const short row_count_this_iter = std::min(
+ std::numeric_limits<short>::max() / style_.tile_height, remaining_rows);
+
+ uiDefBut(&block,
+ UI_BTYPE_LABEL,
+ 0,
+ "",
+ 0,
+ 0,
+ UI_UNIT_X,
+ row_count_this_iter * style_.tile_height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+ remaining_rows -= row_count_this_iter;
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+class GridViewLayoutBuilder {
+ uiBlock &block_;
+
+ friend class GridViewBuilder;
+
+ public:
+ GridViewLayoutBuilder(uiBlock &block);
+
+ void build_from_view(const AbstractGridView &grid_view, const View2D &v2d) const;
+
+ private:
+ void build_grid_tile(uiLayout &grid_layout, AbstractGridViewItem &item) const;
+
+ uiLayout *current_layout() const;
+};
+
+GridViewLayoutBuilder::GridViewLayoutBuilder(uiBlock &block) : block_(block)
+{
+}
+
+void GridViewLayoutBuilder::build_grid_tile(uiLayout &grid_layout,
+ AbstractGridViewItem &item) const
+{
+ uiLayout *overlap = uiLayoutOverlap(&grid_layout);
+
+ item.add_grid_tile_button(block_);
+ item.build_grid_tile(*uiLayoutRow(overlap, false));
+}
+
+void GridViewLayoutBuilder::build_from_view(const AbstractGridView &grid_view,
+ const View2D &v2d) const
+{
+ uiLayout *prev_layout = current_layout();
+
+ uiLayout &layout = *uiLayoutColumn(current_layout(), false);
+ const GridViewStyle &style = grid_view.get_style();
+
+ const int cols_per_row = std::max(uiLayoutGetWidth(&layout) / style.tile_width, 1);
+
+ BuildOnlyVisibleButtonsHelper build_visible_helper(v2d, grid_view, cols_per_row);
+
+ build_visible_helper.fill_layout_before_visible(block_);
+
+ /* Use `-cols_per_row` because the grid layout uses a multiple of the passed absolute value for
+ * the number of columns then, rather than distributing the number of items evenly over rows and
+ * stretching the items to fit (see #uiLayoutItemGridFlow.columns_len). */
+ uiLayout *grid_layout = uiLayoutGridFlow(&layout, true, -cols_per_row, true, true, true);
+
+ int item_idx = 0;
+ grid_view.foreach_item([&](AbstractGridViewItem &item) {
+ /* Skip if item isn't visible. */
+ if (!build_visible_helper.is_item_visible(item_idx)) {
+ item_idx++;
+ return;
+ }
+
+ build_grid_tile(*grid_layout, item);
+ item_idx++;
+ });
+
+ /* If there are not enough items to fill the layout, add padding items so the layout doesn't
+ * stretch over the entire width. */
+ if (grid_view.get_item_count() < cols_per_row) {
+ for (int padding_item_idx = 0; padding_item_idx < (cols_per_row - grid_view.get_item_count());
+ padding_item_idx++) {
+ uiItemS(grid_layout);
+ }
+ }
+
+ UI_block_layout_set_current(&block_, prev_layout);
+
+ build_visible_helper.fill_layout_after_visible(block_);
+}
+
+uiLayout *GridViewLayoutBuilder::current_layout() const
+{
+ return block_.curlayout;
+}
+
+/* ---------------------------------------------------------------------- */
+
+GridViewBuilder::GridViewBuilder(uiBlock &block) : block_(block)
+{
+}
+
+void GridViewBuilder::build_grid_view(AbstractGridView &grid_view, const View2D &v2d)
+{
+ grid_view.build_items();
+ grid_view.update_from_old(block_);
+ grid_view.change_state_delayed();
+
+ GridViewLayoutBuilder builder(block_);
+ builder.build_from_view(grid_view, v2d);
+}
+
+/* ---------------------------------------------------------------------- */
+
+PreviewGridItem::PreviewGridItem(StringRef identifier, StringRef label, int preview_icon_id)
+ : AbstractGridViewItem(identifier), label(label), preview_icon_id(preview_icon_id)
+{
+}
+
+void PreviewGridItem::build_grid_tile(uiLayout &layout) const
+{
+ const GridViewStyle &style = get_view().get_style();
+ uiBlock *block = uiLayoutGetBlock(&layout);
+
+ uiBut *but = uiDefBut(block,
+ UI_BTYPE_PREVIEW_TILE,
+ 0,
+ label.c_str(),
+ 0,
+ 0,
+ style.tile_width,
+ style.tile_height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+ ui_def_but_icon(but,
+ preview_icon_id,
+ /* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
+ UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+}
+
+void PreviewGridItem::set_on_activate_fn(ActivateFn fn)
+{
+ activate_fn_ = fn;
+}
+
+void PreviewGridItem::set_is_active_fn(IsActiveFn fn)
+{
+ is_active_fn_ = fn;
+}
+
+void PreviewGridItem::on_activate()
+{
+ if (activate_fn_) {
+ activate_fn_(*this);
+ }
+}
+
+std::optional<bool> PreviewGridItem::should_be_active() const
+{
+ if (is_active_fn_) {
+ return is_active_fn_();
+ }
+ return std::nullopt;
+}
+
+} // namespace blender::ui
+
+using namespace blender::ui;
+
+/* ---------------------------------------------------------------------- */
+/* C-API */
+
+using namespace blender::ui;
+
+bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle)
+{
+ const AbstractGridViewItem &item = reinterpret_cast<const AbstractGridViewItem &>(*item_handle);
+ return item.is_active();
+}
+
+bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view_handle,
+ const wmNotifier *notifier)
+{
+ const AbstractGridView &view = *reinterpret_cast<const AbstractGridView *>(view_handle);
+ return view.listen(*notifier);
+}
+
+bool UI_grid_view_item_matches(const uiGridViewItemHandle *a_handle,
+ const uiGridViewItemHandle *b_handle)
+{
+ const AbstractGridViewItem &a = reinterpret_cast<const AbstractGridViewItem &>(*a_handle);
+ const AbstractGridViewItem &b = reinterpret_cast<const AbstractGridViewItem &>(*b_handle);
+ return a.matches(b);
+}
diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc
index c12d6957a95..3f623566807 100644
--- a/source/blender/editors/interface/interface.cc
+++ b/source/blender/editors/interface/interface.cc
@@ -778,6 +778,15 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
}
}
+ if ((but->type == UI_BTYPE_GRID_TILE) && (oldbut->type == UI_BTYPE_GRID_TILE)) {
+ uiButGridTile *but_gridtile = (uiButGridTile *)but;
+ uiButGridTile *oldbut_gridtile = (uiButGridTile *)oldbut;
+ if (!but_gridtile->view_item || !oldbut_gridtile->view_item ||
+ !UI_grid_view_item_matches(but_gridtile->view_item, oldbut_gridtile->view_item)) {
+ return false;
+ }
+ }
+
return true;
}
@@ -904,6 +913,12 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
SWAP(uiTreeViewItemHandle *, treerow_newbut->tree_item, treerow_oldbut->tree_item);
break;
}
+ case UI_BTYPE_GRID_TILE: {
+ uiButGridTile *gridtile_oldbut = (uiButGridTile *)oldbut;
+ uiButGridTile *gridtile_newbut = (uiButGridTile *)but;
+ SWAP(uiGridViewItemHandle *, gridtile_newbut->view_item, gridtile_oldbut->view_item);
+ break;
+ }
default:
break;
}
@@ -996,9 +1011,9 @@ static bool ui_but_update_from_old_block(const bContext *C,
else {
int flag_copy = UI_BUT_DRAG_MULTI;
- /* Stupid special case: The active button may be inside (as in, overlapped on top) a tree-row
+ /* Stupid special case: The active button may be inside (as in, overlapped on top) a view-item
* button which we also want to keep highlighted then. */
- if (but->type == UI_BTYPE_TREEROW) {
+ if (ui_but_is_view_item(but)) {
flag_copy |= UI_ACTIVE;
}
@@ -2239,6 +2254,15 @@ int ui_but_is_pushed_ex(uiBut *but, double *value)
}
break;
}
+ case UI_BTYPE_GRID_TILE: {
+ uiButGridTile *grid_tile_but = (uiButGridTile *)but;
+
+ is_push = -1;
+ if (grid_tile_but->view_item) {
+ is_push = UI_grid_view_item_is_active(grid_tile_but->view_item);
+ }
+ break;
+ }
default:
is_push = -1;
break;
@@ -3445,9 +3469,7 @@ static void ui_but_free(const bContext *C, uiBut *but)
IMB_freeImBuf((struct ImBuf *)but->poin);
}
- if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- }
+ ui_but_drag_free(but);
ui_but_extra_operator_icons_free(but);
BLI_assert(UI_butstore_is_registered(but->block, but) == false);
@@ -3997,6 +4019,10 @@ static void ui_but_alloc_info(const eButType type,
alloc_size = sizeof(uiButHotkeyEvent);
alloc_str = "uiButHotkeyEvent";
break;
+ case UI_BTYPE_GRID_TILE:
+ alloc_size = sizeof(uiButGridTile);
+ alloc_str = "uiButGridTile";
+ break;
default:
alloc_size = sizeof(uiBut);
alloc_str = "uiBut";
@@ -4971,6 +4997,33 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
return match;
}
+#define PREVIEW_TILE_PAD (0.15f * UI_UNIT_X)
+
+int UI_preview_tile_size_x(void)
+{
+ const float pad = PREVIEW_TILE_PAD;
+ return round_fl_to_int((96.0f / 20.0f) * UI_UNIT_X + 2.0f * pad);
+}
+
+int UI_preview_tile_size_y(void)
+{
+ const uiStyle *style = UI_style_get();
+ const float font_height = style->widget.points * UI_DPI_FAC;
+ const float pad = PREVIEW_TILE_PAD;
+
+ return round_fl_to_int(UI_preview_tile_size_y_no_label() + font_height +
+ /* Add some extra padding to make things less tight vertically. */
+ pad);
+}
+
+int UI_preview_tile_size_y_no_label(void)
+{
+ const float pad = PREVIEW_TILE_PAD;
+ return round_fl_to_int((96.0f / 20.0f) * UI_UNIT_Y + 2.0f * pad);
+}
+
+#undef PREVIEW_TILE_PAD
+
static void ui_but_update_and_icon_set(uiBut *but, int icon)
{
if (icon) {
@@ -5881,104 +5934,6 @@ int UI_but_return_value_get(uiBut *but)
return but->retval;
}
-void UI_but_drag_set_id(uiBut *but, ID *id)
-{
- but->dragtype = WM_DRAG_ID;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)id;
-}
-
-void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale)
-{
- but->imb = imb;
- but->imb_scale = scale;
-}
-
-void UI_but_drag_set_asset(uiBut *but,
- const AssetHandle *asset,
- const char *path,
- struct AssetMetaData *metadata,
- int import_type,
- int icon,
- struct ImBuf *imb,
- float scale)
-{
- wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type);
-
- /* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the
- * #wmDropBox.
- * TODO: Handle link/append in operator called at the end of the drop process, and NOT in its
- * copy callback.
- * */
- asset_drag->evil_C = static_cast<bContext *>(but->block->evil_C);
-
- but->dragtype = WM_DRAG_ASSET;
- ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- }
- but->dragpoin = asset_drag;
- but->dragflag |= UI_BUT_DRAGPOIN_FREE;
- UI_but_drag_attach_image(but, imb, scale);
-}
-
-void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr)
-{
- but->dragtype = WM_DRAG_RNA;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)ptr;
-}
-
-void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free)
-{
- but->dragtype = WM_DRAG_PATH;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)path;
- if (use_free) {
- but->dragflag |= UI_BUT_DRAGPOIN_FREE;
- }
-}
-
-void UI_but_drag_set_name(uiBut *but, const char *name)
-{
- but->dragtype = WM_DRAG_NAME;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)name;
-}
-
-void UI_but_drag_set_value(uiBut *but)
-{
- but->dragtype = WM_DRAG_VALUE;
-}
-
-void UI_but_drag_set_image(
- uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free)
-{
- but->dragtype = WM_DRAG_PATH;
- ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)path;
- if (use_free) {
- but->dragflag |= UI_BUT_DRAGPOIN_FREE;
- }
- UI_but_drag_attach_image(but, imb, scale);
-}
-
PointerRNA *UI_but_operator_ptr_get(uiBut *but)
{
if (but->optype && !but->opptr) {
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index e838ce37d8e..0e69b4bb358 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -293,7 +293,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
{
- ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, but->rnaindex, cfra);
+ ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, but->rnaindex, cfra, true);
}
void ui_but_anim_copy_driver(bContext *C)
diff --git a/source/blender/editors/interface/interface_drag.cc b/source/blender/editors/interface/interface_drag.cc
new file mode 100644
index 00000000000..4c68870b2c7
--- /dev/null
+++ b/source/blender/editors/interface/interface_drag.cc
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+
+#include "interface_intern.h"
+
+void UI_but_drag_set_id(uiBut *but, ID *id)
+{
+ but->dragtype = WM_DRAG_ID;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)id;
+}
+
+void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale)
+{
+ but->imb = imb;
+ but->imb_scale = scale;
+}
+
+void UI_but_drag_set_asset(uiBut *but,
+ const AssetHandle *asset,
+ const char *path,
+ struct AssetMetaData *metadata,
+ int import_type,
+ int icon,
+ struct ImBuf *imb,
+ float scale)
+{
+ wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type);
+
+ /* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the
+ * #wmDropBox.
+ * TODO: Handle link/append in operator called at the end of the drop process, and NOT in its
+ * copy callback.
+ * */
+ asset_drag->evil_C = static_cast<bContext *>(but->block->evil_C);
+
+ but->dragtype = WM_DRAG_ASSET;
+ ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ }
+ but->dragpoin = asset_drag;
+ but->dragflag |= UI_BUT_DRAGPOIN_FREE;
+ UI_but_drag_attach_image(but, imb, scale);
+}
+
+void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr)
+{
+ but->dragtype = WM_DRAG_RNA;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)ptr;
+}
+
+void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free)
+{
+ but->dragtype = WM_DRAG_PATH;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)path;
+ if (use_free) {
+ but->dragflag |= UI_BUT_DRAGPOIN_FREE;
+ }
+}
+
+void UI_but_drag_set_name(uiBut *but, const char *name)
+{
+ but->dragtype = WM_DRAG_NAME;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)name;
+}
+
+void UI_but_drag_set_value(uiBut *but)
+{
+ but->dragtype = WM_DRAG_VALUE;
+}
+
+void UI_but_drag_set_image(
+ uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free)
+{
+ but->dragtype = WM_DRAG_PATH;
+ ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)path;
+ if (use_free) {
+ but->dragflag |= UI_BUT_DRAGPOIN_FREE;
+ }
+ UI_but_drag_attach_image(but, imb, scale);
+}
+
+void ui_but_drag_free(uiBut *but)
+{
+ if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ }
+}
+
+bool ui_but_drag_is_draggable(const uiBut *but)
+{
+ return but->dragpoin != nullptr;
+}
+
+void ui_but_drag_start(bContext *C, uiBut *but)
+{
+ wmDrag *drag = WM_event_start_drag(C,
+ but->icon,
+ but->dragtype,
+ but->dragpoin,
+ ui_but_value_get(but),
+ (but->dragflag & UI_BUT_DRAGPOIN_FREE) ? WM_DRAG_FREE_DATA :
+ WM_DRAG_NOP);
+ /* wmDrag has ownership over dragpoin now, stop messing with it. */
+ but->dragpoin = NULL;
+
+ if (but->imb) {
+ WM_event_drag_image(drag, but->imb, but->imb_scale);
+ }
+
+ /* Special feature for assets: We add another drag item that supports multiple assets. It
+ * gets the assets from context. */
+ if (ELEM(but->dragtype, WM_DRAG_ASSET, WM_DRAG_ID)) {
+ WM_event_start_drag(C, ICON_NONE, WM_DRAG_ASSET_LIST, NULL, 0, WM_DRAG_NOP);
+ }
+}
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 18bad7949ee..d201820fbb6 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -130,7 +130,7 @@ void UI_draw_roundbox_4fv_ex(const rctf *rect,
void UI_draw_roundbox_3ub_alpha(
const rctf *rect, bool filled, float rad, const uchar col[3], uchar alpha)
{
- float colv[4] = {
+ const float colv[4] = {
((float)col[0]) / 255,
((float)col[1]) / 255,
((float)col[2]) / 255,
@@ -142,7 +142,7 @@ void UI_draw_roundbox_3ub_alpha(
void UI_draw_roundbox_3fv_alpha(
const rctf *rect, bool filled, float rad, const float col[3], float alpha)
{
- float colv[4] = {col[0], col[1], col[2], alpha};
+ const float colv[4] = {col[0], col[1], col[2], alpha};
UI_draw_roundbox_4fv_ex(rect, (filled) ? colv : NULL, NULL, 1.0f, colv, U.pixelsize, rad);
}
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 895f8d0d840..c015a60de89 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -50,8 +50,6 @@
#include "RE_pipeline.h"
-#include "RE_pipeline.h"
-
#include "interface_eyedropper_intern.h"
typedef struct Eyedropper {
@@ -329,7 +327,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3])
ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceImage *sima = area->spacedata.first;
- int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
+ const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
if (ED_space_image_color_sample(sima, region, region_mval, r_col, NULL)) {
return;
@@ -340,7 +338,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3])
ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceNode *snode = area->spacedata.first;
- int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
+ const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
if (ED_space_node_color_sample(bmain, snode, region, region_mval, r_col)) {
return;
@@ -351,7 +349,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3])
ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceClip *sc = area->spacedata.first;
- int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
+ const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
if (ED_space_clip_color_sample(sc, region, region_mval, r_col)) {
return;
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index aec8f56678a..01b958576b6 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -156,7 +156,7 @@ static void datadropper_id_sample_pt(
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
- /* grr, always draw else we leave stale text */
+ /* Unfortunately it's necessary to always draw else we leave stale text. */
ED_region_tag_redraw(region);
if (area->spacetype == SPACE_VIEW3D) {
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index 56bc1a6d956..3c6f127582a 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -171,7 +171,7 @@ static void depthdropper_depth_sample_pt(bContext *C,
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
- /* grr, always draw else we leave stale text */
+ /* Unfortunately it's necessary to always draw otherwise we leave stale text. */
ED_region_tag_redraw(region);
view3d_operator_needs_opengl(C);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index a7dfff2edb4..7c00c4f1875 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -1480,9 +1480,9 @@ static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData *dat
}
}
- /* edit buttons proportionally to eachother
+ /* Edit buttons proportionally to each other.
* NOTE: if we mix buttons which are proportional and others which are not,
- * this may work a bit strangely */
+ * this may work a bit strangely. */
if ((but_active->rnaprop && (RNA_property_flag(but_active->rnaprop) & PROP_PROPORTIONAL)) ||
ELEM(but_active->unit_type, RNA_SUBTYPE_UNIT_VALUE(PROP_UNIT_LENGTH))) {
if (data->origvalue != 0.0) {
@@ -2135,25 +2135,7 @@ static bool ui_but_drag_init(bContext *C,
}
}
else {
- wmDrag *drag = WM_event_start_drag(
- C,
- but->icon,
- but->dragtype,
- but->dragpoin,
- ui_but_value_get(but),
- (but->dragflag & UI_BUT_DRAGPOIN_FREE) ? WM_DRAG_FREE_DATA : WM_DRAG_NOP);
- /* wmDrag has ownership over dragpoin now, stop messing with it. */
- but->dragpoin = NULL;
-
- if (but->imb) {
- WM_event_drag_image(drag, but->imb, but->imb_scale);
- }
-
- /* Special feature for assets: We add another drag item that supports multiple assets. It
- * gets the assets from context. */
- if (ELEM(but->dragtype, WM_DRAG_ASSET, WM_DRAG_ID)) {
- WM_event_start_drag(C, ICON_NONE, WM_DRAG_ASSET_LIST, NULL, 0, WM_DRAG_NOP);
- }
+ ui_but_drag_start(C, but);
}
return true;
}
@@ -2307,6 +2289,9 @@ static void ui_apply_but(
case UI_BTYPE_ROW:
ui_apply_but_ROW(C, block, but, data);
break;
+ case UI_BTYPE_GRID_TILE:
+ ui_apply_but_ROW(C, block, but, data);
+ break;
case UI_BTYPE_TREEROW:
ui_apply_but_TREEROW(C, block, but, data);
break;
@@ -2963,6 +2948,9 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR],
void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value)
{
+ /* Caller should check. */
+ BLI_assert((but->flag & UI_BUT_DISABLED) == 0);
+
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
ui_textedit_string_set(but, but->active, value);
@@ -3507,7 +3495,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT);
#ifdef WITH_INPUT_IME
- if (is_num_but == false && BLT_lang_is_ime_supported()) {
+ if (!is_num_but) {
ui_textedit_ime_begin(win, but);
}
#endif
@@ -3911,7 +3899,7 @@ static void ui_do_but_textedit(
if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)
#ifdef WITH_INPUT_IME
- && !is_ime_composing && (!WM_event_is_ime_switch(event) || !BLT_lang_is_ime_supported())
+ && !is_ime_composing && !WM_event_is_ime_switch(event)
#endif
) {
char ascii = event->ascii;
@@ -4825,12 +4813,53 @@ static int ui_do_but_TREEROW(bContext *C,
return WM_UI_HANDLER_CONTINUE;
}
+static int ui_do_but_GRIDTILE(bContext *C,
+ uiBut *but,
+ uiHandleButtonData *data,
+ const wmEvent *event)
+{
+ BLI_assert(but->type == UI_BTYPE_GRID_TILE);
+
+ if (data->state == BUTTON_STATE_HIGHLIGHT) {
+ if (event->type == LEFTMOUSE) {
+ switch (event->val) {
+ case KM_PRESS:
+ /* Extra icons have priority, don't mess with them. */
+ if (ui_but_extra_operator_icon_mouse_over_get(but, data->region, event)) {
+ return WM_UI_HANDLER_BREAK;
+ }
+ button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
+ return WM_UI_HANDLER_CONTINUE;
+
+ case KM_CLICK:
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ return WM_UI_HANDLER_BREAK;
+
+ case KM_DBL_CLICK:
+ data->cancel = true;
+ // uiButGridTile *grid_tile_but = (uiButGridTile *)but;
+ // UI_tree_view_item_begin_rename(grid_tile_but->tree_item);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
+ }
+ else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+ /* Let "default" button handling take care of the drag logic. */
+ return ui_do_but_EXIT(C, but, data, event);
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* First handle click on icon-drag type button. */
- if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && but->dragpoin) {
+ if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && ui_but_drag_is_draggable(but)) {
if (ui_but_contains_point_px_icon(but, data->region, event)) {
/* tell the button to wait and keep checking further events to
@@ -4853,7 +4882,8 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
if (ELEM(event->type, LEFTMOUSE, EVT_PADENTER, EVT_RETKEY) && event->val == KM_PRESS) {
int ret = WM_UI_HANDLER_BREAK;
/* XXX: (a bit ugly) Special case handling for file-browser drag button. */
- if (but->dragpoin && but->imb && ui_but_contains_point_px_icon(but, data->region, event)) {
+ if (ui_but_drag_is_draggable(but) && but->imb &&
+ ui_but_contains_point_px_icon(but, data->region, event)) {
ret = WM_UI_HANDLER_CONTINUE;
}
/* Same special case handling for UI lists. Return CONTINUE so that a tweak or CLICK event
@@ -4865,6 +4895,10 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
ret = WM_UI_HANDLER_CONTINUE;
}
}
+ const uiBut *view_but = ui_view_item_find_mouse_over(data->region, event->xy);
+ if (view_but) {
+ ret = WM_UI_HANDLER_CONTINUE;
+ }
button_activate_state(C, but, BUTTON_STATE_EXIT);
return ret;
}
@@ -6007,7 +6041,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* First handle click on icon-drag type button. */
- if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
+ if (event->type == LEFTMOUSE && ui_but_drag_is_draggable(but) && event->val == KM_PRESS) {
if (ui_but_contains_point_px_icon(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->xy[0];
@@ -6193,7 +6227,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* First handle click on icon-drag type button. */
- if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
+ if (event->type == LEFTMOUSE && ui_but_drag_is_draggable(but) && event->val == KM_PRESS) {
ui_palette_set_active(color_but);
if (ui_but_contains_point_px_icon(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
@@ -7408,8 +7442,7 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block,
const float zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&profile->view_rect);
if (snap) {
- float d[2] = {mx - data->dragstartx, data->dragstarty};
-
+ const float d[2] = {mx - data->dragstartx, data->dragstarty};
if (len_squared_v2(d) < (9.0f * U.dpi_fac)) {
snap = false;
}
@@ -8020,6 +8053,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_ROW:
retval = ui_do_but_TOG(C, but, data, event);
break;
+ case UI_BTYPE_GRID_TILE:
+ retval = ui_do_but_GRIDTILE(C, but, data, event);
+ break;
case UI_BTYPE_TREEROW:
retval = ui_do_but_TREEROW(C, but, data, event);
break;
@@ -9477,7 +9513,7 @@ static bool ui_list_is_hovering_draggable_but(bContext *C,
}
}
- return (hovered_but && hovered_but->dragpoin);
+ return (hovered_but && ui_but_drag_is_draggable(hovered_but));
}
static int ui_list_handle_click_drag(bContext *C,
@@ -9687,31 +9723,31 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *regi
return retval;
}
-static int ui_handle_tree_hover(const wmEvent *event, const ARegion *region)
+static int ui_handle_view_items_hover(const wmEvent *event, const ARegion *region)
{
- bool has_treerows = false;
+ bool has_view_item = false;
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
- /* Avoid unnecessary work: Tree-rows are assumed to be inside tree-views. */
+ /* Avoid unnecessary work: view item buttons are assumed to be inside views. */
if (BLI_listbase_is_empty(&block->views)) {
continue;
}
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- if (but->type == UI_BTYPE_TREEROW) {
+ if (ui_but_is_view_item(but)) {
but->flag &= ~UI_ACTIVE;
- has_treerows = true;
+ has_view_item = true;
}
}
}
- if (!has_treerows) {
+ if (!has_view_item) {
/* Avoid unnecessary lookup. */
return WM_UI_HANDLER_CONTINUE;
}
- /* Always highlight the hovered tree-row, even if the mouse hovers another button inside of it.
+ /* Always highlight the hovered view item, even if the mouse hovers another button inside of it.
*/
- uiBut *hovered_row_but = ui_tree_row_find_mouse_over(region, event->xy);
+ uiBut *hovered_row_but = ui_view_item_find_mouse_over(region, event->xy);
if (hovered_row_but) {
hovered_row_but->flag |= UI_ACTIVE;
}
@@ -9719,6 +9755,21 @@ static int ui_handle_tree_hover(const wmEvent *event, const ARegion *region)
return WM_UI_HANDLER_CONTINUE;
}
+static int ui_handle_view_item_event(bContext *C,
+ const wmEvent *event,
+ ARegion *region,
+ uiBut *view_but)
+{
+ BLI_assert(ui_but_is_view_item(view_but));
+ if (event->type == LEFTMOUSE) {
+ /* Will free active button if there already is one. */
+ ui_handle_button_activate(C, region, view_but, BUTTON_ACTIVATE_OVER);
+ return ui_do_button(C, view_but->block, view_but, event);
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, uiBut *but)
{
uiHandleButtonData *data = but->active;
@@ -11319,9 +11370,15 @@ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(use
ui_blocks_set_tooltips(region, true);
}
- /* Always do this, to reliably update tree-row highlighting, even if the mouse hovers a button
- * inside the row (it's an overlapping layout). */
- ui_handle_tree_hover(event, region);
+ /* Always do this, to reliably update view item highlighting, even if the mouse hovers a button
+ * nested in the item (it's an overlapping layout). */
+ ui_handle_view_items_hover(event, region);
+ if (retval == WM_UI_HANDLER_CONTINUE) {
+ uiBut *view_item = ui_view_item_find_mouse_over(region, event->xy);
+ if (view_item) {
+ retval = ui_handle_view_item_event(C, event, region, view_item);
+ }
+ }
/* delayed apply callbacks */
ui_apply_but_funcs_after(C);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 332b9b44b0a..c19e842aad8 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -546,6 +546,7 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_BRUSH_MASK, mask);
INIT_BRUSH_ICON(ICON_BRUSH_MIX, mix);
INIT_BRUSH_ICON(ICON_BRUSH_NUDGE, nudge);
+ INIT_BRUSH_ICON(ICON_BRUSH_PAINT_SELECT, paint_select);
INIT_BRUSH_ICON(ICON_BRUSH_PINCH, pinch);
INIT_BRUSH_ICON(ICON_BRUSH_SCRAPE, scrape);
INIT_BRUSH_ICON(ICON_BRUSH_SMEAR, smear);
@@ -584,6 +585,19 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_HARD, gp_brush_erase_hard);
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_STROKE, gp_brush_erase_stroke);
+ /* Curves sculpt. */
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_ADD, curves_sculpt_add);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_COMB, curves_sculpt_comb);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_CUT, curves_sculpt_cut);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_DELETE, curves_sculpt_delete);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_DENSITY, curves_sculpt_density);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_GROW_SHRINK, curves_sculpt_grow_shrink);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_PINCH, curves_sculpt_pinch);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_PUFF, curves_sculpt_puff);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SLIDE, curves_sculpt_slide);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SMOOTH, curves_sculpt_smooth);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SNAKE_HOOK, curves_sculpt_snake_hook);
+
# undef INIT_BRUSH_ICON
}
@@ -2034,6 +2048,9 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
else if (ob->mode & OB_MODE_TEXTURE_PAINT) {
paint_mode = PAINT_MODE_TEXTURE_3D;
}
+ else if (ob->mode & OB_MODE_SCULPT_CURVES) {
+ paint_mode = PAINT_MODE_SCULPT_CURVES;
+ }
}
else if (space_type == SPACE_IMAGE) {
if (area->spacetype == space_type) {
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index 00c1bcb5f6e..6ad5fe805ab 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -145,10 +145,10 @@ void icon_draw_rect_input(float x,
SNPRINTF(str, "F%d", 1 + (event_type - EVT_F1KEY));
icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8.0f : 10.0f);
}
- else if (event_type == EVT_LEFTSHIFTKEY) {
+ else if (event_type == EVT_LEFTSHIFTKEY) { /* Right Shift has already been converted to left. */
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0});
}
- else if (event_type == EVT_LEFTCTRLKEY) {
+ else if (event_type == EVT_LEFTCTRLKEY) { /* Right Shift has already been converted to left. */
if (platform == MACOS) {
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0});
}
@@ -156,7 +156,7 @@ void icon_draw_rect_input(float x,
icon_draw_rect_input_text(&rect, color, "Ctrl", 9.0f);
}
}
- else if (event_type == EVT_LEFTALTKEY) {
+ else if (event_type == EVT_LEFTALTKEY) { /* Right Alt has already been converted to left. */
if (platform == MACOS) {
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0});
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 1b245ba9e6f..791e51b81a6 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -351,6 +351,13 @@ typedef struct uiButTreeRow {
int indentation;
} uiButTreeRow;
+/** Derived struct for #UI_BTYPE_GRID_TILE. */
+typedef struct uiButGridTile {
+ uiBut but;
+
+ uiGridViewItemHandle *view_item;
+} uiButGridTile;
+
/** Derived struct for #UI_BTYPE_HSVCUBE. */
typedef struct uiButHSVCube {
uiBut but;
@@ -1321,6 +1328,12 @@ void ui_button_group_add_but(uiBlock *block, uiBut *but);
void ui_button_group_replace_but_ptr(uiBlock *block, const void *old_but_ptr, uiBut *new_but);
void ui_block_free_button_groups(uiBlock *block);
+/* interface_drag.cc */
+
+void ui_but_drag_free(uiBut *but);
+bool ui_but_drag_is_draggable(const uiBut *but);
+void ui_but_drag_start(struct bContext *C, uiBut *but);
+
/* interface_align.c */
bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -1359,6 +1372,7 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *but);
bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_editable_as_text(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_is_view_item(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
/**
* Can we mouse over the button or is it hidden/disabled/layout.
* \note ctrl is kind of a hack currently,
@@ -1390,6 +1404,8 @@ uiBut *ui_list_row_find_mouse_over(const struct ARegion *region, const int xy[2]
uiBut *ui_list_row_find_from_index(const struct ARegion *region,
int index,
uiBut *listbox) ATTR_WARN_UNUSED_RESULT;
+uiBut *ui_view_item_find_mouse_over(const struct ARegion *region, const int xy[2])
+ ATTR_NONNULL(1, 2);
uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2);
uiBut *ui_tree_row_find_active(const struct ARegion *region);
@@ -1527,8 +1543,10 @@ void ui_interface_tag_script_reload_queries(void);
/* interface_view.cc */
void ui_block_free_views(struct uiBlock *block);
-uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
- const uiTreeViewHandle *new_view);
+uiTreeViewHandle *ui_block_tree_view_find_matching_in_old_block(const uiBlock *new_block,
+ const uiTreeViewHandle *new_view);
+uiGridViewHandle *ui_block_grid_view_find_matching_in_old_block(
+ const uiBlock *new_block, const uiGridViewHandle *new_view_handle);
uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
const uiTreeViewItemHandle *new_item_handle);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index c066ced21cb..aafb56119ae 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1167,7 +1167,9 @@ static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
/* identifiers */
ot->name = "Copy to Selected";
ot->idname = "UI_OT_copy_to_selected_button";
- ot->description = "Copy property from this object to selected objects or bones";
+ ot->description =
+ "Copy the property's value from the active item to the same property of all selected items "
+ "if the same property exists";
/* callbacks */
ot->poll = copy_to_selected_button_poll;
@@ -1940,6 +1942,24 @@ static void UI_OT_drop_color(wmOperatorType *ot)
/** \name Drop Name Operator
* \{ */
+static bool drop_name_poll(bContext *C)
+{
+ if (!ED_operator_regionactive(C)) {
+ return false;
+ }
+
+ const uiBut *but = UI_but_active_drop_name_button(C);
+ if (!but) {
+ return false;
+ }
+
+ if (but->flag & UI_BUT_DISABLED) {
+ return false;
+ }
+
+ return true;
+}
+
static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
uiBut *but = UI_but_active_drop_name_button(C);
@@ -1959,7 +1979,7 @@ static void UI_OT_drop_name(wmOperatorType *ot)
ot->idname = "UI_OT_drop_name";
ot->description = "Drop name to button";
- ot->poll = ED_operator_regionactive;
+ ot->poll = drop_name_poll;
ot->invoke = drop_name_invoke;
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
diff --git a/source/blender/editors/interface/interface_query.cc b/source/blender/editors/interface/interface_query.cc
index ea1fe3923e4..71cf60985df 100644
--- a/source/blender/editors/interface/interface_query.cc
+++ b/source/blender/editors/interface/interface_query.cc
@@ -58,18 +58,23 @@ bool ui_but_is_toggle(const uiBut *but)
UI_BTYPE_TREEROW);
}
+bool ui_but_is_view_item(const uiBut *but)
+{
+ return ELEM(but->type, UI_BTYPE_TREEROW, UI_BTYPE_GRID_TILE);
+}
+
bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool for_tooltip)
{
/* NOTE: #UI_BTYPE_LABEL is included for highlights, this allows drags. */
if (but->type == UI_BTYPE_LABEL) {
if (for_tooltip) {
/* It's important labels are considered interactive for the purpose of showing tooltip. */
- if (but->dragpoin == nullptr && but->tip_func == nullptr) {
+ if (!ui_but_drag_is_draggable(but) && but->tip_func == nullptr) {
return false;
}
}
else {
- if (but->dragpoin == nullptr) {
+ if (!ui_but_drag_is_draggable(but)) {
return false;
}
}
@@ -462,6 +467,16 @@ static bool ui_but_is_treerow(const uiBut *but, const void *UNUSED(customdata))
return but->type == UI_BTYPE_TREEROW;
}
+static bool ui_but_is_view_item_fn(const uiBut *but, const void *UNUSED(customdata))
+{
+ return ui_but_is_view_item(but);
+}
+
+uiBut *ui_view_item_find_mouse_over(const ARegion *region, const int xy[2])
+{
+ return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_view_item_fn, nullptr);
+}
+
uiBut *ui_tree_row_find_mouse_over(const ARegion *region, const int xy[2])
{
return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_treerow, nullptr);
diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index 64de31dfe6a..81c0c29d09a 100644
--- a/source/blender/editors/interface/interface_region_search.cc
+++ b/source/blender/editors/interface/interface_region_search.cc
@@ -451,15 +451,16 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
/* reset vars */
data->items.totitem = 0;
data->items.more = 0;
- if (reset == false) {
+ if (!reset) {
data->items.offset_i = data->items.offset;
}
else {
data->items.offset_i = data->items.offset = 0;
data->active = -1;
- /* handle active */
- if (search_but->items_update_fn && search_but->item_active) {
+ /* On init, find and center active item. */
+ const bool is_first_search = !search_but->but.changed;
+ if (is_first_search && search_but->items_update_fn && search_but->item_active) {
data->items.active = search_but->item_active;
ui_searchbox_update_fn(C, search_but, but->editstr, &data->items);
data->items.active = nullptr;
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index c7ebecb178b..82d4405e1b5 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -800,7 +800,7 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
.style = UI_TIP_STYLE_HEADER,
.color_id = UI_TIP_LC_NORMAL,
});
- field->text = BLI_sprintfN("%s", but_label.strinfo);
+ field->text = BLI_strdup(but_label.strinfo);
}
/* Tip */
diff --git a/source/blender/editors/interface/interface_style.cc b/source/blender/editors/interface/interface_style.cc
index 291ede05730..904765f6dc4 100644
--- a/source/blender/editors/interface/interface_style.cc
+++ b/source/blender/editors/interface/interface_style.cc
@@ -382,19 +382,8 @@ void uiStyleInit(void)
}
CLAMP(U.dpi, 48, 144);
- LISTBASE_FOREACH (uiFont *, font, &U.uifonts) {
- BLF_unload_id(font->blf_id);
- }
-
- if (blf_mono_font != -1) {
- BLF_unload_id(blf_mono_font);
- blf_mono_font = -1;
- }
-
- if (blf_mono_font_render != -1) {
- BLF_unload_id(blf_mono_font_render);
- blf_mono_font_render = -1;
- }
+ /* Needed so that custom fonts are always first. */
+ BLF_unload_all();
uiFont *font_first = static_cast<uiFont *>(U.uifonts.first);
@@ -498,6 +487,9 @@ void uiStyleInit(void)
const bool unique = true;
blf_mono_font_render = BLF_load_mono_default(unique);
}
+
+ /* Load the fallback fonts last. */
+ BLF_load_font_stack();
}
void UI_fontstyle_set(const uiFontStyle *fs)
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index 68a699c652a..e0b6bbb34c4 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -945,13 +945,8 @@ static void ui_template_list_layout_draw(bContext *C,
const bool show_names = (flags & UI_TEMPLATE_LIST_NO_NAMES) == 0;
- /* TODO ED_fileselect_init_layout(). Share somehow? */
- float size_x = (96.0f / 20.0f) * UI_UNIT_X;
- float size_y = (96.0f / 20.0f) * UI_UNIT_Y;
-
- if (!show_names) {
- size_y -= UI_UNIT_Y;
- }
+ const int size_x = UI_preview_tile_size_x();
+ const int size_y = show_names ? UI_preview_tile_size_y() : UI_preview_tile_size_y_no_label();
const int cols_per_row = MAX2((uiLayoutGetWidth(box) - V2D_SCROLL_WIDTH) / size_x, 1);
uiLayout *grid = uiLayoutGridFlow(row, true, cols_per_row, true, true, true);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index a02e8a3ac49..05ae5299e58 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -1536,8 +1536,8 @@ static void template_ID_tabs(const bContext *C,
0.0f,
"");
UI_but_funcN_set(&tab->but, template_ID_set_property_exec_fn, MEM_dupallocN(template), id);
+ UI_but_drag_set_id(&tab->but, id);
tab->but.custom_data = (void *)id;
- tab->but.dragpoin = id;
tab->menu = mt;
UI_but_drawflag_enable(&tab->but, but_align);
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
index 85e1dbe73a5..699ac0c2b53 100644
--- a/source/blender/editors/interface/interface_view.cc
+++ b/source/blender/editors/interface/interface_view.cc
@@ -10,15 +10,22 @@
*/
#include <memory>
+#include <type_traits>
#include <variant>
#include "DNA_screen_types.h"
+#include "BKE_screen.h"
+
#include "BLI_listbase.h"
+#include "ED_screen.h"
+
#include "interface_intern.h"
#include "UI_interface.hh"
+
+#include "UI_grid_view.hh"
#include "UI_tree_view.hh"
using namespace blender;
@@ -30,29 +37,51 @@ using namespace blender::ui;
*/
struct ViewLink : public Link {
using TreeViewPtr = std::unique_ptr<AbstractTreeView>;
+ using GridViewPtr = std::unique_ptr<AbstractGridView>;
std::string idname;
/* NOTE: Can't use std::get() on this until minimum macOS deployment target is 10.14. */
- std::variant<TreeViewPtr> view;
+ std::variant<TreeViewPtr, GridViewPtr> view;
};
+template<class T> constexpr void check_if_valid_view_type()
+{
+ static_assert(std::is_same_v<T, AbstractTreeView> || std::is_same_v<T, AbstractGridView>,
+ "Unsupported view type");
+}
+
template<class T> T *get_view_from_link(ViewLink &link)
{
auto *t_uptr = std::get_if<std::unique_ptr<T>>(&link.view);
return t_uptr ? t_uptr->get() : nullptr;
}
-AbstractTreeView *UI_block_add_view(uiBlock &block,
- StringRef idname,
- std::unique_ptr<AbstractTreeView> tree_view)
+template<class T>
+static T *ui_block_add_view_impl(uiBlock &block, StringRef idname, std::unique_ptr<T> view)
{
+ check_if_valid_view_type<T>();
+
ViewLink *view_link = MEM_new<ViewLink>(__func__);
BLI_addtail(&block.views, view_link);
- view_link->view = std::move(tree_view);
+ view_link->view = std::move(view);
view_link->idname = idname;
- return get_view_from_link<AbstractTreeView>(*view_link);
+ return get_view_from_link<T>(*view_link);
+}
+
+AbstractGridView *UI_block_add_view(uiBlock &block,
+ StringRef idname,
+ std::unique_ptr<AbstractGridView> tree_view)
+{
+ return ui_block_add_view_impl<AbstractGridView>(block, idname, std::move(tree_view));
+}
+
+AbstractTreeView *UI_block_add_view(uiBlock &block,
+ StringRef idname,
+ std::unique_ptr<AbstractTreeView> tree_view)
+{
+ return ui_block_add_view_impl<AbstractTreeView>(block, idname, std::move(tree_view));
}
void ui_block_free_views(uiBlock *block)
@@ -62,6 +91,26 @@ void ui_block_free_views(uiBlock *block)
}
}
+void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
+{
+ ARegion *region = listener_params->region;
+
+ LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
+ if (AbstractGridView *grid_view = get_view_from_link<AbstractGridView>(*view_link)) {
+ if (UI_grid_view_listen_should_redraw(reinterpret_cast<uiGridViewHandle *>(grid_view),
+ listener_params->notifier)) {
+ ED_region_tag_redraw(region);
+ }
+ }
+ else if (AbstractTreeView *tree_view = get_view_from_link<AbstractTreeView>(*view_link)) {
+ if (UI_tree_view_listen_should_redraw(reinterpret_cast<uiTreeViewHandle *>(tree_view),
+ listener_params->notifier)) {
+ ED_region_tag_redraw(region);
+ }
+ }
+ }
+}
+
uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region, const int xy[2])
{
uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, xy);
@@ -82,11 +131,13 @@ uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const ARegion *region)
return tree_row_but->tree_item;
}
-static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractTreeView &view)
+template<class T> static StringRef ui_block_view_find_idname(const uiBlock &block, const T &view)
{
+ check_if_valid_view_type<T>();
+
/* First get the idname the of the view we're looking for. */
LISTBASE_FOREACH (ViewLink *, view_link, &block.views) {
- if (get_view_from_link<AbstractTreeView>(*view_link) == &view) {
+ if (get_view_from_link<T>(*view_link) == &view) {
return view_link->idname;
}
}
@@ -94,9 +145,11 @@ static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractT
return {};
}
-static AbstractTreeView *ui_block_view_find_matching_in_old_block(const uiBlock &new_block,
- const AbstractTreeView &new_view)
+template<class T>
+static T *ui_block_view_find_matching_in_old_block(const uiBlock &new_block, const T &new_view)
{
+ check_if_valid_view_type<T>();
+
uiBlock *old_block = new_block.oldblock;
if (!old_block) {
return nullptr;
@@ -109,15 +162,15 @@ static AbstractTreeView *ui_block_view_find_matching_in_old_block(const uiBlock
LISTBASE_FOREACH (ViewLink *, old_view_link, &old_block->views) {
if (old_view_link->idname == idname) {
- return get_view_from_link<AbstractTreeView>(*old_view_link);
+ return get_view_from_link<T>(*old_view_link);
}
}
return nullptr;
}
-uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
- const uiTreeViewHandle *new_view_handle)
+uiTreeViewHandle *ui_block_tree_view_find_matching_in_old_block(
+ const uiBlock *new_block, const uiTreeViewHandle *new_view_handle)
{
BLI_assert(new_block && new_view_handle);
const AbstractTreeView &new_view = reinterpret_cast<const AbstractTreeView &>(*new_view_handle);
@@ -126,6 +179,16 @@ uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_bl
return reinterpret_cast<uiTreeViewHandle *>(old_view);
}
+uiGridViewHandle *ui_block_grid_view_find_matching_in_old_block(
+ const uiBlock *new_block, const uiGridViewHandle *new_view_handle)
+{
+ BLI_assert(new_block && new_view_handle);
+ const AbstractGridView &new_view = reinterpret_cast<const AbstractGridView &>(*new_view_handle);
+
+ AbstractGridView *old_view = ui_block_view_find_matching_in_old_block(*new_block, new_view);
+ return reinterpret_cast<uiGridViewHandle *>(old_view);
+}
+
uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
const uiTreeViewItemHandle *new_item_handle)
{
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 3777ff31b26..e2df2d77817 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -105,6 +105,7 @@ typedef enum {
UI_WTYPE_PROGRESSBAR,
UI_WTYPE_NODESOCKET,
UI_WTYPE_TREEROW,
+ UI_WTYPE_GRID_TILE,
} uiWidgetTypeEnum;
/**
@@ -1419,7 +1420,7 @@ static void widget_draw_icon(
const bool has_theme = UI_icon_get_theme_color(icon, color);
/* to indicate draggable */
- if (but->dragpoin && (but->flag & UI_ACTIVE)) {
+ if (ui_but_drag_is_draggable(but) && (but->flag & UI_ACTIVE)) {
UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme);
}
else if ((but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW))) {
@@ -3706,6 +3707,16 @@ static void widget_treerow(uiBut *but,
widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation, zoom);
}
+static void widget_gridtile(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
+{
+ /* TODO Reuse tree-row drawing. */
+ widget_treerow_exec(wcol, rect, state, roundboxalign, 0, zoom);
+}
+
static void widget_nodesocket(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
@@ -4598,9 +4609,15 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
break;
case UI_WTYPE_TREEROW:
+ wt.wcol_theme = &btheme->tui.wcol_view_item;
wt.custom = widget_treerow;
break;
+ case UI_WTYPE_GRID_TILE:
+ wt.wcol_theme = &btheme->tui.wcol_view_item;
+ wt.draw = widget_gridtile;
+ break;
+
case UI_WTYPE_NODESOCKET:
wt.custom = widget_nodesocket;
break;
@@ -4937,6 +4954,11 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
fstyle = &style->widgetlabel;
break;
+ case UI_BTYPE_GRID_TILE:
+ wt = widget_type(UI_WTYPE_GRID_TILE);
+ fstyle = &style->widgetlabel;
+ break;
+
case UI_BTYPE_SCROLL:
wt = widget_type(UI_WTYPE_SCROLL);
break;
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc
index bf756fb5838..f86d1c4d8bc 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/tree_view.cc
@@ -68,6 +68,12 @@ void AbstractTreeView::foreach_item(ItemIterFn iter_fn, IterOptions options) con
foreach_item_recursive(iter_fn, options);
}
+bool AbstractTreeView::listen(const wmNotifier &) const
+{
+ /* Nothing by default. */
+ return false;
+}
+
bool AbstractTreeView::is_renaming() const
{
return rename_buffer_ != nullptr;
@@ -82,7 +88,7 @@ void AbstractTreeView::update_from_old(uiBlock &new_block)
return;
}
- uiTreeViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block(
+ uiTreeViewHandle *old_view_handle = ui_block_tree_view_find_matching_in_old_block(
&new_block, reinterpret_cast<uiTreeViewHandle *>(this));
if (old_view_handle == nullptr) {
is_reconstructed_ = true;
@@ -805,6 +811,13 @@ class TreeViewItemAPIWrapper {
using namespace blender::ui;
+bool UI_tree_view_listen_should_redraw(const uiTreeViewHandle *view_handle,
+ const wmNotifier *notifier)
+{
+ const AbstractTreeView &view = *reinterpret_cast<const AbstractTreeView *>(view_handle);
+ return view.listen(*notifier);
+}
+
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item_handle)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index ef093a01ff8..a716c00d5d9 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -13,6 +13,7 @@ set(INC
../../io/gpencil
../../io/usd
../../io/wavefront_obj
+ ../../io/stl
../../makesdna
../../makesrna
../../windowmanager
@@ -33,6 +34,7 @@ set(SRC
io_obj.c
io_ops.c
io_usd.c
+ io_stl_ops.c
io_alembic.h
io_cache.h
@@ -41,12 +43,12 @@ set(SRC
io_obj.h
io_ops.h
io_usd.h
+ io_stl_ops.h
)
set(LIB
bf_blenkernel
bf_blenlib
- bf_wavefront_obj
)
if(WITH_OPENCOLLADA)
@@ -56,6 +58,27 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_IO_WAVEFRONT_OBJ)
+ list(APPEND LIB
+ bf_wavefront_obj
+ )
+ add_definitions(-DWITH_IO_WAVEFRONT_OBJ)
+endif()
+
+if(WITH_IO_STL)
+ list(APPEND LIB
+ bf_stl
+ )
+ add_definitions(-DWITH_IO_STL)
+endif()
+
+if(WITH_IO_GPENCIL)
+ list(APPEND LIB
+ bf_gpencil
+ )
+ add_definitions(-DWITH_IO_GPENCIL)
+endif()
+
if(WITH_ALEMBIC)
list(APPEND LIB
bf_alembic
@@ -78,6 +101,4 @@ if(WITH_HARU)
add_definitions(-DWITH_HARU)
endif()
-list(APPEND LIB bf_gpencil)
-
blender_add_lib(bf_editor_io "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 87923d9fdf8..0e8e0f83597 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -282,7 +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;
+ ot->flag = OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index dc62212bf53..c491e7a5815 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -468,7 +468,7 @@ void WM_OT_collada_export(wmOperatorType *ot)
ot->poll = WM_operator_winactive;
ot->check = wm_collada_export_check;
- ot->flag |= OPTYPE_PRESET;
+ ot->flag = OPTYPE_PRESET;
ot->ui = wm_collada_export_draw;
@@ -786,7 +786,7 @@ void WM_OT_collada_import(wmOperatorType *ot)
ot->exec = wm_collada_import_exec;
ot->poll = WM_operator_winactive;
- // ot->flag |= OPTYPE_PRESET;
+ // ot->flag = OPTYPE_PRESET;
ot->ui = wm_collada_import_draw;
diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c
index 7ac05fcca3e..6e5ae9f3cba 100644
--- a/source/blender/editors/io/io_gpencil_export.c
+++ b/source/blender/editors/io/io_gpencil_export.c
@@ -5,36 +5,38 @@
* \ingroup editor/io
*/
-#include "BLI_path_util.h"
-#include "BLI_string.h"
+#ifdef WITH_IO_GPENCIL
-#include "DNA_gpencil_types.h"
-#include "DNA_space_types.h"
+# include "BLI_path_util.h"
+# include "BLI_string.h"
-#include "BKE_gpencil.h"
-#include "BKE_main.h"
-#include "BKE_report.h"
-#include "BKE_screen.h"
+# include "DNA_gpencil_types.h"
+# include "DNA_space_types.h"
-#include "BLT_translation.h"
+# include "BKE_gpencil.h"
+# include "BKE_main.h"
+# include "BKE_report.h"
+# include "BKE_screen.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
+# include "BLT_translation.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
+# include "RNA_access.h"
+# include "RNA_define.h"
-#include "WM_api.h"
-#include "WM_types.h"
+# include "UI_interface.h"
+# include "UI_resources.h"
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
+# include "WM_api.h"
+# include "WM_types.h"
-#include "io_gpencil.h"
+# include "DEG_depsgraph.h"
+# include "DEG_depsgraph_query.h"
-#include "gpencil_io.h"
+# include "io_gpencil.h"
-#if defined(WITH_PUGIXML) || defined(WITH_HARU)
+# include "gpencil_io.h"
+
+# if defined(WITH_PUGIXML) || defined(WITH_HARU)
/* Definition of enum elements to export. */
/* Common props for exporting. */
static void gpencil_export_common_props_definition(wmOperatorType *ot)
@@ -87,10 +89,10 @@ static void set_export_filepath(bContext *C, wmOperator *op, const char *extensi
RNA_string_set(op->ptr, "filepath", filepath);
}
}
-#endif
+# endif
/* <-------- SVG single frame export. --------> */
-#ifdef WITH_PUGIXML
+# ifdef WITH_PUGIXML
static bool wm_gpencil_export_svg_common_check(bContext *UNUSED(C), wmOperator *op)
{
char filepath[FILE_MAX];
@@ -241,10 +243,10 @@ void WM_OT_gpencil_export_svg(wmOperatorType *ot)
"Clip Camera",
"Clip drawings to camera size when export in camera view");
}
-#endif
+# endif
/* <-------- PDF single frame export. --------> */
-#ifdef WITH_HARU
+# ifdef WITH_HARU
static bool wm_gpencil_export_pdf_common_check(bContext *UNUSED(C), wmOperator *op)
{
@@ -406,4 +408,6 @@ void WM_OT_gpencil_export_pdf(wmOperatorType *ot)
"Frames",
"Which frames to include in the export");
}
-#endif
+# endif /* WITH_HARU */
+
+#endif /* WITH_IO_GPENCIL */
diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c
index 8bed32ad6c3..45f5441616f 100644
--- a/source/blender/editors/io/io_gpencil_import.c
+++ b/source/blender/editors/io/io_gpencil_import.c
@@ -5,34 +5,36 @@
* \ingroup editor/io
*/
-#include "BLI_path_util.h"
+#ifdef WITH_IO_GPENCIL
-#include "DNA_gpencil_types.h"
-#include "DNA_space_types.h"
+# include "BLI_path_util.h"
-#include "BKE_context.h"
-#include "BKE_gpencil.h"
-#include "BKE_report.h"
+# include "DNA_gpencil_types.h"
+# include "DNA_space_types.h"
-#include "BLT_translation.h"
+# include "BKE_context.h"
+# include "BKE_gpencil.h"
+# include "BKE_report.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
+# include "BLT_translation.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
+# include "RNA_access.h"
+# include "RNA_define.h"
-#include "WM_api.h"
-#include "WM_types.h"
+# include "UI_interface.h"
+# include "UI_resources.h"
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
+# include "WM_api.h"
+# include "WM_types.h"
-#include "ED_gpencil.h"
+# include "DEG_depsgraph.h"
+# include "DEG_depsgraph_query.h"
-#include "io_gpencil.h"
+# include "ED_gpencil.h"
-#include "gpencil_io.h"
+# include "io_gpencil.h"
+
+# include "gpencil_io.h"
/* <-------- SVG single frame import. --------> */
static bool wm_gpencil_import_svg_common_check(bContext *UNUSED(C), wmOperator *op)
@@ -174,3 +176,5 @@ void WM_OT_gpencil_import_svg(wmOperatorType *ot)
0.001f,
100.0f);
}
+
+#endif /* WITH_IO_GPENCIL */
diff --git a/source/blender/editors/io/io_gpencil_utils.c b/source/blender/editors/io/io_gpencil_utils.c
index fa5fcd79b96..9a88daef1a1 100644
--- a/source/blender/editors/io/io_gpencil_utils.c
+++ b/source/blender/editors/io/io_gpencil_utils.c
@@ -5,14 +5,16 @@
* \ingroup editor/io
*/
-#include "DNA_space_types.h"
+#ifdef WITH_IO_GPENCIL
-#include "BKE_context.h"
-#include "BKE_screen.h"
+# include "DNA_space_types.h"
-#include "WM_api.h"
+# include "BKE_context.h"
+# include "BKE_screen.h"
-#include "io_gpencil.h"
+# include "WM_api.h"
+
+# include "io_gpencil.h"
ARegion *get_invoke_region(bContext *C)
{
@@ -46,3 +48,5 @@ View3D *get_invoke_view3d(bContext *C)
return NULL;
}
+
+#endif /* WITH_IO_GPENCIL */
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index 5537b2575d8..4819ae09785 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -4,54 +4,39 @@
* \ingroup editor/io
*/
-#include "DNA_space_types.h"
+#ifdef WITH_IO_WAVEFRONT_OBJ
-#include "BKE_context.h"
-#include "BKE_main.h"
-#include "BKE_report.h"
+# include "DNA_space_types.h"
-#include "BLI_path_util.h"
-#include "BLI_string.h"
-#include "BLI_utildefines.h"
+# include "BKE_context.h"
+# include "BKE_main.h"
+# include "BKE_report.h"
-#include "BLT_translation.h"
+# include "BLI_path_util.h"
+# include "BLI_string.h"
+# include "BLI_utildefines.h"
-#include "ED_outliner.h"
+# include "BLT_translation.h"
-#include "MEM_guardedalloc.h"
+# include "ED_outliner.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
+# include "MEM_guardedalloc.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
+# include "RNA_access.h"
+# include "RNA_define.h"
-#include "WM_api.h"
-#include "WM_types.h"
+# include "UI_interface.h"
+# include "UI_resources.h"
-#include "DEG_depsgraph.h"
+# include "WM_api.h"
+# include "WM_types.h"
-#include "IO_path_util_types.h"
-#include "IO_wavefront_obj.h"
-#include "io_obj.h"
+# include "DEG_depsgraph.h"
-static const EnumPropertyItem io_obj_transform_axis_forward[] = {
- {OBJ_AXIS_X_FORWARD, "X_FORWARD", 0, "X", "Positive X axis"},
- {OBJ_AXIS_Y_FORWARD, "Y_FORWARD", 0, "Y", "Positive Y axis"},
- {OBJ_AXIS_Z_FORWARD, "Z_FORWARD", 0, "Z", "Positive Z axis"},
- {OBJ_AXIS_NEGATIVE_X_FORWARD, "NEGATIVE_X_FORWARD", 0, "-X", "Negative X axis"},
- {OBJ_AXIS_NEGATIVE_Y_FORWARD, "NEGATIVE_Y_FORWARD", 0, "-Y", "Negative Y axis"},
- {OBJ_AXIS_NEGATIVE_Z_FORWARD, "NEGATIVE_Z_FORWARD", 0, "-Z", "Negative Z axis"},
- {0, NULL, 0, NULL, NULL}};
-
-static const EnumPropertyItem io_obj_transform_axis_up[] = {
- {OBJ_AXIS_X_UP, "X_UP", 0, "X", "Positive X axis"},
- {OBJ_AXIS_Y_UP, "Y_UP", 0, "Y", "Positive Y axis"},
- {OBJ_AXIS_Z_UP, "Z_UP", 0, "Z", "Positive Z axis"},
- {OBJ_AXIS_NEGATIVE_X_UP, "NEGATIVE_X_UP", 0, "-X", "Negative X axis"},
- {OBJ_AXIS_NEGATIVE_Y_UP, "NEGATIVE_Y_UP", 0, "-Y", "Negative Y axis"},
- {OBJ_AXIS_NEGATIVE_Z_UP, "NEGATIVE_Z_UP", 0, "-Z", "Negative Z axis"},
- {0, NULL, 0, NULL, NULL}};
+# include "IO_orientation.h"
+# include "IO_path_util_types.h"
+# include "IO_wavefront_obj.h"
+# include "io_obj.h"
static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
{DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
@@ -115,6 +100,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects");
export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv");
export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals");
+ export_params.export_colors = RNA_boolean_get(op->ptr, "export_colors");
export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
export_params.path_mode = RNA_enum_get(op->ptr, "path_mode");
export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
@@ -175,6 +161,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
uiItemR(sub, imfptr, "export_uv", 0, IFACE_("UV Coordinates"), ICON_NONE);
uiItemR(sub, imfptr, "export_normals", 0, IFACE_("Normals"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_colors", 0, IFACE_("Colors"), ICON_NONE);
uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Materials"), ICON_NONE);
uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE);
uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE);
@@ -261,7 +248,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
ot->ui = wm_obj_export_draw;
ot->check = wm_obj_export_check;
- ot->flag |= OPTYPE_PRESET;
+ ot->flag = OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER,
@@ -296,13 +283,9 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
INT_MIN,
INT_MAX);
/* Object transform options. */
- RNA_def_enum(ot->srna,
- "forward_axis",
- io_obj_transform_axis_forward,
- OBJ_AXIS_NEGATIVE_Z_FORWARD,
- "Forward Axis",
- "");
- RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", "");
+ RNA_def_enum(
+ ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "Forward Axis", "");
+ RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", "");
RNA_def_float(ot->srna,
"scaling_factor",
1.0f,
@@ -334,6 +317,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"Export Normals",
"Export per-face normals if the face is flat-shaded, per-face-per-loop "
"normals if smooth-shaded");
+ RNA_def_boolean(ot->srna, "export_colors", false, "Export Colors", "Export per-vertex colors");
RNA_def_boolean(ot->srna,
"export_materials",
true,
@@ -480,13 +464,9 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
"Resize the objects to keep bounding box under this value. Value 0 disables clamping",
0.0f,
1000.0f);
- RNA_def_enum(ot->srna,
- "forward_axis",
- io_obj_transform_axis_forward,
- OBJ_AXIS_NEGATIVE_Z_FORWARD,
- "Forward Axis",
- "");
- RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", "");
+ RNA_def_enum(
+ ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "Forward Axis", "");
+ RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", "");
RNA_def_boolean(ot->srna,
"validate_meshes",
false,
@@ -497,3 +477,5 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
prop = RNA_def_string(ot->srna, "filter_glob", "*.obj;*.mtl", 0, "Extension Filter", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
+
+#endif /* WITH_IO_WAVEFRONT_OBJ */
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index 094f89d1540..0340d0598d5 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -24,6 +24,7 @@
#include "io_cache.h"
#include "io_gpencil.h"
#include "io_obj.h"
+#include "io_stl_ops.h"
void ED_operatortypes_io(void)
{
@@ -41,14 +42,14 @@ void ED_operatortypes_io(void)
WM_operatortype_append(WM_OT_usd_export);
#endif
+#ifdef WITH_IO_GPENCIL
WM_operatortype_append(WM_OT_gpencil_import_svg);
-
-#ifdef WITH_PUGIXML
+# ifdef WITH_PUGIXML
WM_operatortype_append(WM_OT_gpencil_export_svg);
-#endif
-
-#ifdef WITH_HARU
+# endif
+# ifdef WITH_HARU
WM_operatortype_append(WM_OT_gpencil_export_pdf);
+# endif
#endif
WM_operatortype_append(CACHEFILE_OT_open);
@@ -58,6 +59,12 @@ void ED_operatortypes_io(void)
WM_operatortype_append(CACHEFILE_OT_layer_remove);
WM_operatortype_append(CACHEFILE_OT_layer_move);
+#ifdef WITH_IO_WAVEFRONT_OBJ
WM_operatortype_append(WM_OT_obj_export);
WM_operatortype_append(WM_OT_obj_import);
+#endif
+
+#ifdef WITH_IO_STL
+ WM_operatortype_append(WM_OT_stl_import);
+#endif
}
diff --git a/source/blender/editors/io/io_stl_ops.c b/source/blender/editors/io/io_stl_ops.c
new file mode 100644
index 00000000000..7db32cd6f18
--- /dev/null
+++ b/source/blender/editors/io/io_stl_ops.c
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup editor/io
+ */
+
+#ifdef WITH_IO_STL
+
+# include "BKE_context.h"
+# include "BKE_report.h"
+
+# include "WM_api.h"
+# include "WM_types.h"
+
+# include "DNA_space_types.h"
+
+# include "ED_outliner.h"
+
+# include "RNA_access.h"
+# include "RNA_define.h"
+
+# include "IO_stl.h"
+# include "io_stl_ops.h"
+
+static int wm_stl_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ return WM_operator_filesel(C, op, event);
+}
+
+static int wm_stl_import_execute(bContext *C, wmOperator *op)
+{
+ struct STLImportParams params;
+ params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
+ params.up_axis = RNA_enum_get(op->ptr, "up_axis");
+ params.use_facet_normal = RNA_boolean_get(op->ptr, "use_facet_normal");
+ params.use_scene_unit = RNA_boolean_get(op->ptr, "use_scene_unit");
+ params.global_scale = RNA_float_get(op->ptr, "global_scale");
+ params.use_mesh_validate = RNA_boolean_get(op->ptr, "use_mesh_validate");
+
+ int files_len = RNA_collection_length(op->ptr, "files");
+
+ if (files_len) {
+ PointerRNA fileptr;
+ PropertyRNA *prop;
+ char dir_only[FILE_MAX], file_only[FILE_MAX];
+
+ RNA_string_get(op->ptr, "directory", dir_only);
+ prop = RNA_struct_find_property(op->ptr, "files");
+ for (int i = 0; i < files_len; i++) {
+ RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr);
+ RNA_string_get(&fileptr, "name", file_only);
+ BLI_join_dirfile(params.filepath, sizeof(params.filepath), dir_only, file_only);
+ STL_import(C, &params);
+ }
+ }
+ else if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ RNA_string_get(op->ptr, "filepath", params.filepath);
+ STL_import(C, &params);
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool wm_stl_import_check(bContext *UNUSED(C), wmOperator *op)
+{
+ const int num_axes = 3;
+ /* Both forward and up axes cannot be the same (or same except opposite sign). */
+ if (RNA_enum_get(op->ptr, "forward_axis") % num_axes ==
+ (RNA_enum_get(op->ptr, "up_axis") % num_axes)) {
+ RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % num_axes + 1);
+ return true;
+ }
+ return false;
+}
+
+void WM_OT_stl_import(struct wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Import STL";
+ ot->description = "Import an STL file as an object";
+ ot->idname = "WM_OT_stl_import";
+
+ ot->invoke = wm_stl_import_invoke;
+ ot->exec = wm_stl_import_execute;
+ ot->poll = WM_operator_winactive;
+ ot->check = wm_stl_import_check;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER,
+ FILE_BLENDER,
+ FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY |
+ WM_FILESEL_SHOW_PROPS,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_ALPHA);
+
+ RNA_def_float(ot->srna, "global_scale", 1.0f, 1e-6f, 1e6f, "Scale", "", 0.001f, 1000.0f);
+ RNA_def_boolean(ot->srna,
+ "use_scene_unit",
+ false,
+ "Scene Unit",
+ "Apply current scene's unit (as defined by unit scale) to imported data");
+ RNA_def_boolean(ot->srna,
+ "use_facet_normal",
+ false,
+ "Facet Normals",
+ "Use (import) facet normals (note that this will still give flat shading)");
+ RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", "");
+ RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", "");
+ RNA_def_boolean(ot->srna,
+ "use_mesh_validate",
+ false,
+ "Validate Mesh",
+ "Validate and correct imported mesh (slow)");
+
+ /* Only show .stl files by default. */
+ prop = RNA_def_string(ot->srna, "filter_glob", "*.stl", 0, "Extension Filter", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
+#endif /* WITH_IO_STL */
diff --git a/source/blender/editors/io/io_stl_ops.h b/source/blender/editors/io/io_stl_ops.h
new file mode 100644
index 00000000000..8f548f75985
--- /dev/null
+++ b/source/blender/editors/io/io_stl_ops.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup editor/io
+ */
+
+#pragma once
+
+struct wmOperatorType;
+
+void WM_OT_stl_export(struct wmOperatorType *ot);
+void WM_OT_stl_import(struct wmOperatorType *ot);
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index 609230eefea..a59cdf60243 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -57,6 +57,20 @@ const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_usd_mtl_name_collision_mode_items[] = {
+ {USD_MTL_NAME_COLLISION_MAKE_UNIQUE,
+ "MAKE_UNIQUE",
+ 0,
+ "Make Unique",
+ "Import each USD material as a unique Blender material"},
+ {USD_MTL_NAME_COLLISION_REFERENCE_EXISTING,
+ "REFERENCE_EXISTING",
+ 0,
+ "Reference Existing",
+ "If a material with the same name already exists, reference that instead of importing"},
+ {0, NULL, 0, NULL, NULL},
+};
+
/* Stored in the wmOperator's customdata field to indicate it should run as a background job.
* This is set when the operator is invoked, and not set when it is only executed. */
enum { AS_BACKGROUND_JOB = 1 };
@@ -216,7 +230,7 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
ot->ui = wm_usd_export_draw;
ot->check = wm_usd_export_check;
- ot->flag = OPTYPE_REGISTER; /* No UNDO possible. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_PRESET; /* No UNDO possible. */
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_USD,
@@ -371,6 +385,9 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
const float light_intensity_scale = RNA_float_get(op->ptr, "light_intensity_scale");
+ const eUSDMtlNameCollisionMode mtl_name_collision_mode = RNA_enum_get(op->ptr,
+ "mtl_name_collision_mode");
+
/* TODO(makowalski): Add support for sequences. */
const bool is_sequence = false;
int offset = 0;
@@ -409,7 +426,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
.use_instancing = use_instancing,
.import_usd_preview = import_usd_preview,
.set_material_blend = set_material_blend,
- .light_intensity_scale = light_intensity_scale};
+ .light_intensity_scale = light_intensity_scale,
+ .mtl_name_collision_mode = mtl_name_collision_mode};
const bool ok = USD_import(C, filename, &params, as_background_job);
@@ -452,6 +470,7 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
uiItemR(col, ptr, "relative_path", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "create_collection", 0, NULL, ICON_NONE);
uiItemR(box, ptr, "light_intensity_scale", 0, NULL, ICON_NONE);
+ uiItemR(box, ptr, "mtl_name_collision_mode", 0, NULL, ICON_NONE);
box = uiLayoutBox(layout);
col = uiLayoutColumnWithHeading(box, true, IFACE_("Experimental"));
@@ -575,6 +594,14 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
"Scale for the intensity of imported lights",
0.0001f,
1000.0f);
+
+ RNA_def_enum(
+ ot->srna,
+ "mtl_name_collision_mode",
+ rna_enum_usd_mtl_name_collision_mode_items,
+ USD_MTL_NAME_COLLISION_MAKE_UNIQUE,
+ "Material Name Collision",
+ "Behavior when the name of an imported material conflicts with an existing material");
}
#endif /* WITH_USD */
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index d10c420e28c..194170b1677 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -31,7 +31,9 @@
#include "mask_intern.h" /* own include */
-/******************** add vertex *********************/
+/* -------------------------------------------------------------------- */
+/** \name Add Vertex
+ * \{ */
static void setup_vertex_point(Mask *mask,
MaskSpline *spline,
@@ -160,7 +162,11 @@ static void setup_vertex_point(Mask *mask,
ED_mask_select_flush_all(mask);
}
-/* **** add extrude vertex **** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Extrude Vertex
+ * \{ */
static void finSelectedSplinePoint(MaskLayer *mask_layer,
MaskSpline **spline,
@@ -206,7 +212,11 @@ static void finSelectedSplinePoint(MaskLayer *mask_layer,
}
}
-/* **** add subdivide vertex **** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Subdivide Vertex
+ * \{ */
static void mask_spline_add_point_at_index(MaskSpline *spline, int point_index)
{
@@ -390,7 +400,7 @@ static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *mask_layer,
MaskSplinePoint *new_point = NULL, *ref_point = NULL;
if (!mask_layer) {
- /* if there's no mask layer currently operationg on, create new one */
+ /* If there's no mask layer currently operating on, create new one. */
mask_layer = BKE_mask_layer_new(mask, "");
mask->masklay_act = mask->masklay_tot - 1;
}
@@ -492,6 +502,12 @@ static int add_vertex_handle_cyclic(
return OPERATOR_PASS_THROUGH;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Vertex Operator
+ * \{ */
+
static int add_vertex_exec(bContext *C, wmOperator *op)
{
MaskViewLockState lock_state;
@@ -585,7 +601,11 @@ void MASK_OT_add_vertex(wmOperatorType *ot)
1.0f);
}
-/******************** add feather vertex *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Feather Vertex Operator
+ * \{ */
static int add_feather_vertex_exec(bContext *C, wmOperator *op)
{
@@ -677,7 +697,11 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot)
1.0f);
}
-/******************** common primitive functions *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Common Primitive Functions
+ * \{ */
static BezTriple *points_to_bezier(const float (*points)[2],
const int num_points,
@@ -812,7 +836,11 @@ static void define_primitive_add_properties(wmOperatorType *ot)
FLT_MAX);
}
-/******************** primitive add circle *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Primitive Add Circle Operator
+ * \{ */
static int primitive_circle_add_exec(bContext *C, wmOperator *op)
{
@@ -843,7 +871,11 @@ void MASK_OT_primitive_circle_add(wmOperatorType *ot)
define_primitive_add_properties(ot);
}
-/******************** primitive add suqare *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Primitive Add Suqare Operator
+ * \{ */
static int primitive_square_add_exec(bContext *C, wmOperator *op)
{
@@ -873,3 +905,5 @@ void MASK_OT_primitive_square_add(wmOperatorType *ot)
/* properties */
define_primitive_add_properties(ot);
}
+
+/** \} */
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index 3c0e7ee399c..f2e9c94c25b 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -146,7 +146,7 @@ void MASK_OT_layer_new(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_layer_new_exec;
- ot->poll = ED_maskedit_poll;
+ ot->poll = ED_maskedit_mask_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -181,7 +181,7 @@ void MASK_OT_layer_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_layer_remove_exec;
- ot->poll = ED_maskedit_poll;
+ ot->poll = ED_maskedit_mask_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index 89524a7b9e2..02e1524e23e 100644
--- a/source/blender/editors/mask/mask_query.c
+++ b/source/blender/editors/mask/mask_query.c
@@ -615,7 +615,7 @@ bool ED_mask_selected_minmax(const bContext *C,
/* Use evaluated mask to take animation into account.
* The animation of splies is not "flushed" back to original, so need to explicitly
- * sue evaluated datablock here. */
+ * use evaluated datablock here. */
Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask->id);
INIT_MINMAX2(min, max);
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 7c0b6fb0a93..e5fe108b6cd 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -364,12 +364,9 @@ static int select_exec(bContext *C, wmOperator *op)
return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
if (deselect_all) {
- /* For clip editor tracks, leave deselect all to clip editor. */
- if (!ED_clip_can_select(C)) {
- ED_mask_deselect_all(C);
- ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
- }
+ ED_mask_deselect_all(C);
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
return OPERATOR_PASS_THROUGH;
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 969d5b5912c..e7891450bd6 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -669,7 +669,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
short etype = event->type;
short eval = event->val;
- /* When activated from toolbar, need to convert leftmouse release to confirm */
+ /* When activated from toolbar, need to convert left-mouse release to confirm. */
if (ELEM(etype, LEFTMOUSE, opdata->launch_event) && (eval == KM_RELEASE) &&
RNA_boolean_get(op->ptr, "release_confirm")) {
etype = EVT_MODAL_MAP;
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index c16b82e34bd..5680865ae67 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1355,13 +1355,19 @@ static void knife_bvh_raycast_cb(void *userdata,
#endif
if (isect && dist < hit->dist) {
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+
+ /* Discard clipped points. */
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) &&
+ ED_view3d_clipping_test(kcd->vc.rv3d, hit->co, false)) {
+ return;
+ }
+
hit->dist = dist;
hit->index = index;
copy_v3_v3(hit->no, ltri[0]->f->no);
- madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
-
kcd->bvh.looptris = em->looptris;
copy_v2_v2(kcd->bvh.uv, uv);
kcd->bvh.base_index = b;
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index feecefdb7ea..1febc429edc 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3092,8 +3092,8 @@ static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
BMOperator bmop;
- Mesh *me = BKE_object_get_original_mesh(ob);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const Mesh *me = BKE_object_get_original_mesh(ob);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) {
continue;
@@ -3144,8 +3144,8 @@ static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
continue;
}
- Mesh *me = BKE_object_get_original_mesh(obedit);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const Mesh *me = BKE_object_get_original_mesh(obedit);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) {
continue;
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index c7c7e5cf2f8..04030583f5c 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -1641,21 +1641,22 @@ void EDBM_project_snap_verts(
float mval[2], co_proj[3];
if (ED_view3d_project_float_object(region, eve->co, mval, V3D_PROJ_TEST_NOP) ==
V3D_PROJ_RET_OK) {
- if (ED_transform_snap_object_project_view3d(snap_context,
- depsgraph,
- region,
- CTX_wm_view3d(C),
- SCE_SNAP_MODE_FACE,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_ACTIVE,
- .edit_mode_type = SNAP_GEOM_FINAL,
- .use_occlusion_test = true,
- },
- mval,
- NULL,
- NULL,
- co_proj,
- NULL)) {
+ if (ED_transform_snap_object_project_view3d(
+ snap_context,
+ depsgraph,
+ region,
+ CTX_wm_view3d(C),
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_target_select = SCE_SNAP_TARGET_NOT_ACTIVE,
+ .edit_mode_type = SNAP_GEOM_FINAL,
+ .use_occlusion_test = true,
+ },
+ mval,
+ NULL,
+ NULL,
+ co_proj,
+ NULL)) {
mul_v3_m4v3(eve->co, obedit->imat, co_proj);
}
}
diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index 5e09948e192..041a1383b28 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -2086,6 +2086,12 @@ static int object_curves_empty_hair_add_exec(bContext *C, wmOperator *op)
Curves *curves_id = static_cast<Curves *>(object->data);
curves_id->surface = surface_ob;
id_us_plus(&surface_ob->id);
+
+ Mesh *surface_mesh = static_cast<Mesh *>(surface_ob->data);
+ const char *uv_name = CustomData_get_active_layer_name(&surface_mesh->ldata, CD_MLOOPUV);
+ if (uv_name != nullptr) {
+ curves_id->surface_uv_map = BLI_strdup(uv_name);
+ }
}
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 1483c24ac70..effbde41c38 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -220,22 +220,22 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
Mesh *me = (Mesh *)ob->data;
MultiresModifierData tmp_mmd = *mmd;
- DerivedMesh *cddm = CDDM_from_mesh(me);
- DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ *lvl = mmd->lvl;
if (mmd->lvl == 0) {
- dm = CDDM_copy(cddm);
- }
- else {
- tmp_mmd.lvl = mmd->lvl;
- tmp_mmd.sculptlvl = mmd->lvl;
- dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0);
+ DerivedMesh *cddm = CDDM_from_mesh(me);
+ DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ return cddm;
}
- cddm->release(cddm);
+ DerivedMesh *cddm = CDDM_from_mesh(me);
+ DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ tmp_mmd.lvl = mmd->lvl;
+ tmp_mmd.sculptlvl = mmd->lvl;
+ dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0);
- *lvl = mmd->lvl;
+ cddm->release(cddm);
return dm;
}
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 114b2ce8102..006379123f8 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -21,6 +21,7 @@
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -1535,7 +1536,7 @@ static int bake(const BakeAPIRender *bkr,
ob_low_eval->obmat);
}
else {
- /* from multiresolution */
+ /* From multi-resolution. */
Mesh *me_nores = NULL;
ModifierData *md = NULL;
int mode;
@@ -1806,6 +1807,17 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
RE_SetReports(bkr->render, NULL);
}
+static void bake_job_complete(void *bkv)
+{
+ BakeAPIRender *bkr = (BakeAPIRender *)bkv;
+ BKE_callback_exec_id(bkr->main, &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_COMPLETE);
+}
+static void bake_job_canceled(void *bkv)
+{
+ BakeAPIRender *bkr = (BakeAPIRender *)bkv;
+ BKE_callback_exec_id(bkr->main, &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_CANCEL);
+}
+
static void bake_freejob(void *bkv)
{
BakeAPIRender *bkr = (BakeAPIRender *)bkv;
@@ -1941,6 +1953,7 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
/* init bake render */
bake_init_api_data(op, C, bkr);
+ BKE_callback_exec_id(CTX_data_main(C), &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_PRE);
re = bkr->render;
/* setup new render */
@@ -1958,7 +1971,8 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
/* TODO: only draw bake image, can we enforce this. */
WM_jobs_timer(
wm_job, 0.5, (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) ? NC_GEOM | ND_DATA : NC_IMAGE, 0);
- WM_jobs_callbacks(wm_job, bake_startjob, NULL, NULL, NULL);
+ WM_jobs_callbacks_ex(
+ wm_job, bake_startjob, NULL, NULL, NULL, bake_job_complete, bake_job_canceled);
G.is_break = false;
G.is_rendering = true;
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index d982d86fe77..bf3b71178e8 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -245,13 +245,11 @@ static void set_constraint_nth_target(bConstraint *con,
const char subtarget[],
int index)
{
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
int num_targets, i;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
+ if (BKE_constraint_targets_get(con, &targets)) {
num_targets = BLI_listbase_count(&targets);
if (index < 0) {
@@ -274,9 +272,7 @@ static void set_constraint_nth_target(bConstraint *con,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
@@ -289,7 +285,6 @@ static void set_constraint_nth_target(bConstraint *con,
static void test_constraint(
Main *bmain, Object *owner, bPoseChannel *pchan, bConstraint *con, int type)
{
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
bool check_targets = true;
@@ -465,14 +460,7 @@ static void test_constraint(
}
/* Check targets for constraints */
- if (check_targets && cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- /* constraints with empty target list that actually require targets */
- if (!targets.first && ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
- con->flag |= CONSTRAINT_DISABLE;
- }
-
+ if (check_targets && BKE_constraint_targets_get(con, &targets)) {
/* disable and clear constraints targets that are incorrect */
for (ct = targets.first; ct; ct = ct->next) {
/* general validity checks (for those constraints that need this) */
@@ -543,8 +531,12 @@ static void test_constraint(
}
/* free any temporary targets */
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
+ BKE_constraint_targets_flush(con, &targets, 0);
+ }
+ else if (check_targets) {
+ /* constraints with empty target list that actually require targets */
+ if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
+ con->flag |= CONSTRAINT_DISABLE;
}
}
}
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index fdf2cae026d..0055cdf9ea1 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -458,7 +458,7 @@ static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base
return false;
}
- bool mode_transfered = false;
+ bool mode_transferred = false;
ED_undo_group_begin(C);
@@ -480,11 +480,11 @@ static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_toolsystem_update_from_context_view3d(C);
- mode_transfered = true;
+ mode_transferred = true;
}
ED_undo_group_end(C);
- return mode_transfered;
+ return mode_transferred;
}
static int object_transfer_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -493,8 +493,8 @@ static int object_transfer_mode_invoke(bContext *C, wmOperator *op, const wmEven
const eObjectMode src_mode = (eObjectMode)ob_src->mode;
Base *base_dst = ED_view3d_give_base_under_cursor(C, event->mval);
- const bool mode_transfered = object_transfer_mode_to_base(C, op, base_dst);
- if (!mode_transfered) {
+ const bool mode_transferred = object_transfer_mode_to_base(C, op, base_dst);
+ if (!mode_transferred) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 6cfd322b2e2..f55ffdf0fcd 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2290,27 +2290,19 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
user_overrides_from_selected_objects = false;
}
else if (!make_override_library_object_overridable_check(bmain, obact)) {
- const int i = RNA_property_enum_get(op->ptr, op->type->prop);
- const uint collection_session_uuid = *((uint *)&i);
+ const int i = RNA_property_int_get(op->ptr, op->type->prop);
+ const uint collection_session_uuid = *((const uint *)&i);
if (collection_session_uuid == MAIN_ID_SESSION_UUID_UNSET) {
BKE_reportf(op->reports,
RPT_ERROR_INVALID_INPUT,
- "Active object '%s' is not overridable",
+ "Could not find an overridable root hierarchy for object '%s'",
obact->id.name + 2);
return OPERATOR_CANCELLED;
}
-
Collection *collection = BLI_listbase_bytes_find(&bmain->collections,
&collection_session_uuid,
sizeof(collection_session_uuid),
offsetof(ID, session_uuid));
- if (!ID_IS_OVERRIDABLE_LIBRARY(collection)) {
- BKE_reportf(op->reports,
- RPT_ERROR_INVALID_INPUT,
- "Could not find an overridable collection containing object '%s'",
- obact->id.name + 2);
- return OPERATOR_CANCELLED;
- }
id_root = &collection->id;
user_overrides_from_selected_objects = true;
}
@@ -2372,10 +2364,36 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
BLI_gset_free(user_overrides_objects_uids, NULL);
}
- /* Remove the instance empty from this scene, the items now have an overridden collection
- * instead. */
- if (success && is_override_instancing_object) {
- ED_object_base_free_and_unlink(bmain, scene, obact);
+ if (success) {
+ if (is_override_instancing_object) {
+ /* Remove the instance empty from this scene, the items now have an overridden collection
+ * instead. */
+ ED_object_base_free_and_unlink(bmain, scene, obact);
+ }
+ else {
+ /* Remove the found root ID from the view layer. */
+ switch (GS(id_root->name)) {
+ case ID_GR: {
+ Collection *collection_root = (Collection *)id_root;
+ LISTBASE_FOREACH_MUTABLE (
+ CollectionParent *, collection_parent, &collection_root->parents) {
+ if (ID_IS_LINKED(collection_parent->collection) ||
+ !BKE_view_layer_has_collection(view_layer, collection_parent->collection)) {
+ continue;
+ }
+ BKE_collection_child_remove(bmain, collection_parent->collection, collection_root);
+ }
+ break;
+ }
+ case ID_OB: {
+ /* TODO: Not sure how well we can handle this case, when we don't have the collections as
+ * reference containers... */
+ break;
+ }
+ default:
+ break;
+ }
+ }
}
DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
@@ -2385,10 +2403,11 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
}
/* Set the object to override. */
-static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obact = ED_object_active_context(C);
/* Sanity checks. */
@@ -2402,16 +2421,37 @@ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEve
return make_override_library_exec(C, op);
}
- if (ID_IS_LINKED(obact)) {
- /* Show menu with list of directly linked collections containing the active object. */
- WM_enum_search_invoke(C, op, event);
+ if (!ID_IS_LINKED(obact)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot make library override from a local object");
return OPERATOR_CANCELLED;
}
- /* Error.. cannot continue. */
- BKE_report(op->reports,
- RPT_ERROR,
- "Can only make library override for a referenced object or collection");
+ int potential_root_collections_num = 0;
+ uint collection_session_uuid = MAIN_ID_SESSION_UUID_UNSET;
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ /* Only check for directly linked collections. */
+ if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0 ||
+ !BKE_view_layer_has_collection(view_layer, collection)) {
+ continue;
+ }
+ if (BKE_collection_has_object_recursive(collection, obact)) {
+ if (potential_root_collections_num == 0) {
+ collection_session_uuid = collection->id.session_uuid;
+ }
+ potential_root_collections_num++;
+ }
+ }
+
+ if (potential_root_collections_num <= 1) {
+ RNA_property_int_set(op->ptr, op->type->prop, *((int *)&collection_session_uuid));
+ return make_override_library_exec(C, op);
+ }
+
+ BKE_reportf(op->reports,
+ RPT_ERROR,
+ "Too many potential root collections (%d) for the override hierarchy, "
+ "please use the Outliner instead",
+ potential_root_collections_num);
return OPERATOR_CANCELLED;
}
@@ -2426,37 +2466,6 @@ static bool make_override_library_poll(bContext *C)
!ID_IS_OVERRIDE_LIBRARY(obact))));
}
-static const EnumPropertyItem *make_override_collections_of_linked_object_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem item_tmp = {0}, *item = NULL;
- int totitem = 0;
-
- Object *object = ED_object_active_context(C);
- Main *bmain = CTX_data_main(C);
-
- if (!object || !ID_IS_LINKED(object)) {
- return DummyRNA_DEFAULT_items;
- }
-
- LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
- /* Only check for directly linked collections. */
- if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0) {
- continue;
- }
- if (BKE_collection_has_object_recursive(collection, object)) {
- item_tmp.identifier = item_tmp.name = collection->id.name + 2;
- item_tmp.value = *((int *)&collection->id.session_uuid);
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
void OBJECT_OT_make_override_library(wmOperatorType *ot)
{
/* identifiers */
@@ -2474,15 +2483,17 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot)
/* properties */
PropertyRNA *prop;
- prop = RNA_def_enum(ot->srna,
- "collection",
- DummyRNA_DEFAULT_items,
- MAIN_ID_SESSION_UUID_UNSET,
- "Override Collection",
- "Name of directly linked collection containing the selected object, to make "
- "an override from");
- RNA_def_enum_funcs(prop, make_override_collections_of_linked_object_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ prop = RNA_def_int(ot->srna,
+ "collection",
+ MAIN_ID_SESSION_UUID_UNSET,
+ INT_MIN,
+ INT_MAX,
+ "Override Collection",
+ "Session UUID of the directly linked collection containing the selected "
+ "object, to make an override from",
+ INT_MIN,
+ INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
ot->prop = prop;
prop = RNA_def_boolean(ot->srna,
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index ba2efa6e517..71b757b66ff 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -344,7 +344,7 @@ static void voxel_size_edit_draw(const bContext *C, ARegion *UNUSED(ar), void *a
BKE_unit_value_as_string(str,
VOXEL_SIZE_EDIT_MAX_STR_LEN,
(double)(cd->voxel_size * unit->scale_length),
- 4,
+ -3,
B_UNIT_LENGTH,
unit,
true);
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 492ece0b40e..9ad36cacc7d 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -4266,7 +4266,6 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
Mesh *me = ob->data;
BMEditMesh *em = me->edit_mesh;
- float weight_act;
int i;
if (em) {
@@ -4278,18 +4277,15 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
if (dvert_act == NULL) {
return;
}
- weight_act = BKE_defvert_find_weight(dvert_act, def_nr);
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) {
- MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
- if (dw) {
- dw->weight = weight_act;
+ MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- if (me->symmetry & ME_SYMMETRY_X) {
- ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
- }
+ BKE_defvert_copy_index(dvert_dst, def_nr, dvert_act, def_nr);
+
+ if (me->symmetry & ME_SYMMETRY_X) {
+ ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
}
}
}
@@ -4306,17 +4302,15 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
if (dvert_act == NULL) {
return;
}
- weight_act = BKE_defvert_find_weight(dvert_act, def_nr);
dv = me->dvert;
for (i = 0; i < me->totvert; i++, dv++) {
if ((me->mvert[i].flag & SELECT) && (dv != dvert_act)) {
- MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
- if (dw) {
- dw->weight = weight_act;
- if (me->symmetry & ME_SYMMETRY_X) {
- ED_mesh_defvert_mirror_update_ob(ob, -1, i);
- }
+
+ BKE_defvert_copy_index(dv, def_nr, dvert_act, def_nr);
+
+ if (me->symmetry & ME_SYMMETRY_X) {
+ ED_mesh_defvert_mirror_update_ob(ob, -1, i);
}
}
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index ad815f0d998..f58baa0e25c 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -145,6 +145,10 @@ void ED_region_do_listen(wmRegionListenerParams *params)
region->type->listener(params);
}
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ UI_block_views_listen(block, params);
+ }
+
LISTBASE_FOREACH (uiList *, list, &region->ui_lists) {
if (list->type && list->type->listener) {
list->type->listener(list, params);
@@ -3454,9 +3458,9 @@ ScrArea *ED_area_find_under_cursor(const bContext *C, int spacetype, const int x
if (!area) {
/* Check all windows except the active one. */
int scr_pos[2];
- wmWindow *r_win = WM_window_find_under_cursor(win, xy, scr_pos);
- if (r_win && r_win != win) {
- win = r_win;
+ wmWindow *win_other = WM_window_find_under_cursor(win, xy, scr_pos);
+ if (win_other && win_other != win) {
+ win = win_other;
screen = WM_window_get_active_screen(win);
area = BKE_screen_find_area_xy(screen, spacetype, scr_pos);
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 43c19670a41..08c8c863729 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -626,8 +626,8 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
screen_geom_vertices_scale(win, screen);
ED_screen_areas_iter (win, screen, area) {
- /* set spacetype and region callbacks, calls init() */
- /* sets subwindows for regions, adds handlers */
+ /* Set space-type and region callbacks, calls init() */
+ /* Sets sub-windows for regions, adds handlers. */
ED_area_init(wm, win, area);
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index a922e5aaaee..55721e6380d 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -665,8 +665,8 @@ bool ED_operator_mask(bContext *C)
if (area && area->spacedata.first) {
switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *screen = area->spacedata.first;
- return ED_space_clip_check_show_maskedit(screen);
+ SpaceClip *space_clip = area->spacedata.first;
+ return ED_space_clip_check_show_maskedit(space_clip);
}
case SPACE_SEQ: {
SpaceSeq *sseq = area->spacedata.first;
@@ -1477,7 +1477,7 @@ static int area_close_exec(bContext *C, wmOperator *op)
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
- /* This operator is scriptable, so the area passed could be invalid. */
+ /* This operator is script-able, so the area passed could be invalid. */
if (BLI_findindex(&screen->areabase, area) == -1) {
BKE_report(op->reports, RPT_ERROR, "Area not found in the active screen");
return OPERATOR_CANCELLED;
@@ -2490,6 +2490,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
case EVT_LEFTCTRLKEY:
+ case EVT_RIGHTCTRLKEY:
sd->do_snap = event->val == KM_PRESS;
update_factor = true;
break;
@@ -2722,7 +2723,7 @@ static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event
rmd->region->sizey = rmd->region->winy;
}
- /* now copy to regionmovedata */
+ /* Now copy to region-move-data. */
if (ELEM(rmd->edge, AE_LEFT_TO_TOPRIGHT, AE_RIGHT_TO_TOPLEFT)) {
rmd->origval = rmd->region->sizex;
}
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index dfd8f8b1bb9..b1b52d16c6d 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -10,6 +10,7 @@ set(INC
../../depsgraph
../../draw
../../functions
+ ../../geometry
../../gpu
../../imbuf
../../makesdna
@@ -57,7 +58,7 @@ set(SRC
paint_vertex_weight_ops.c
paint_vertex_weight_utils.c
sculpt.c
- sculpt_automasking.c
+ sculpt_automasking.cc
sculpt_boundary.c
sculpt_brush_types.c
sculpt_cloth.c
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index fea0e862707..7469c69e40b 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -19,11 +19,12 @@
#include "BKE_context.h"
#include "BKE_curves.hh"
#include "BKE_curves_utils.hh"
+#include "BKE_geometry_set.hh"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
#include "BKE_paint.h"
#include "BKE_report.h"
-#include "BKE_spline.hh"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
@@ -37,10 +38,12 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "GEO_add_curves_on_mesh.hh"
+
#include "WM_api.h"
/**
- * The code below uses a prefix naming convention to indicate the coordinate space:
+ * The code below uses a suffix naming convention to indicate the coordinate space:
* cu: Local space of the curves object that is being edited.
* su: Local space of the surface object.
* wo: World space.
@@ -69,26 +72,13 @@ class AddOperation : public CurvesSculptStrokeOperation {
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
};
-static void initialize_straight_curve_positions(const float3 &p1,
- const float3 &p2,
- MutableSpan<float3> r_positions)
-{
- const float step = 1.0f / (float)(r_positions.size() - 1);
- for (const int i : r_positions.index_range()) {
- r_positions[i] = math::interpolate(p1, p2, i * step);
- }
-}
-
/**
* Utility class that actually executes the update when the stroke is updated. That's useful
* because it avoids passing a very large number of parameters between functions.
*/
struct AddOperationExecutor {
AddOperation *self_ = nullptr;
- const Depsgraph *depsgraph_ = nullptr;
- const Scene *scene_ = nullptr;
- ARegion *region_ = nullptr;
- const View3D *v3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
@@ -97,60 +87,34 @@ struct AddOperationExecutor {
Object *surface_ob_ = nullptr;
Mesh *surface_ = nullptr;
Span<MLoopTri> surface_looptris_;
- Span<float3> corner_normals_su_;
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
const BrushCurvesSculptSettings *brush_settings_ = nullptr;
+ int add_amount_;
+ bool use_front_face_;
float brush_radius_re_;
float2 brush_pos_re_;
- bool use_front_face_;
- bool interpolate_length_;
- bool interpolate_shape_;
- bool interpolate_point_count_;
- bool use_interpolation_;
- float new_curve_length_;
- int add_amount_;
- int constant_points_per_curve_;
-
- /** Various matrices to convert between coordinate spaces. */
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
- float4x4 world_to_surface_mat_;
- float4x4 surface_to_world_mat_;
- float4x4 surface_to_curves_mat_;
- float4x4 surface_to_curves_normal_mat_;
+ CurvesSculptTransforms transforms_;
BVHTreeFromMesh surface_bvh_;
- int tot_old_curves_;
- int tot_old_points_;
-
struct AddedPoints {
Vector<float3> positions_cu;
Vector<float3> bary_coords;
Vector<int> looptri_indices;
};
- struct NeighborInfo {
- /* Curve index of the neighbor. */
- int index;
- /* The weights of all neighbors of a new curve add up to 1. */
- float weight;
- };
- static constexpr int max_neighbors = 5;
- using NeighborsVector = Vector<NeighborInfo, max_neighbors>;
+ AddOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
void execute(AddOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
{
self_ = &self;
- depsgraph_ = CTX_data_depsgraph_pointer(&C);
- scene_ = CTX_data_scene(&C);
object_ = CTX_data_active_object(&C);
- region_ = CTX_wm_region(&C);
- v3d_ = CTX_wm_view3d(&C);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
@@ -159,43 +123,21 @@ struct AddOperationExecutor {
return;
}
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
surface_ob_ = curves_id_->surface;
surface_ = static_cast<Mesh *>(surface_ob_->data);
- surface_to_world_mat_ = surface_ob_->obmat;
- world_to_surface_mat_ = surface_to_world_mat_.inverted();
- surface_to_curves_mat_ = world_to_curves_mat_ * surface_to_world_mat_;
- surface_to_curves_normal_mat_ = surface_to_curves_mat_.inverted().transposed();
- if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
- BKE_mesh_calc_normals_split(surface_);
- }
- corner_normals_su_ = {
- reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
- surface_->totloop};
-
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
brush_settings_ = brush_->curves_sculpt_settings;
- brush_radius_re_ = brush_radius_get(*scene_, *brush_, stroke_extension);
+ brush_radius_re_ = brush_radius_get(*ctx_.scene, *brush_, stroke_extension);
brush_pos_re_ = stroke_extension.mouse_position;
use_front_face_ = brush_->flag & BRUSH_FRONTFACE;
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
add_amount_ = std::max(0, brush_settings_->add_amount);
- constant_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;
- interpolate_point_count_ = brush_settings_->flag &
- BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
- use_interpolation_ = interpolate_length_ || interpolate_shape_ || interpolate_point_count_;
- new_curve_length_ = brush_settings_->curve_length;
-
- tot_old_curves_ = curves_->curves_num();
- tot_old_points_ = curves_->points_num();
if (add_amount_ == 0) {
return;
@@ -231,42 +173,56 @@ struct AddOperationExecutor {
return;
}
- Array<NeighborsVector> neighbors_per_curve;
- if (use_interpolation_) {
- this->ensure_curve_roots_kdtree();
- neighbors_per_curve = this->find_curve_neighbors(added_points);
+ /* Find UV map. */
+ VArray_Span<float2> surface_uv_map;
+ if (curves_id_->surface_uv_map != nullptr) {
+ MeshComponent surface_component;
+ surface_component.replace(surface_, GeometryOwnershipType::ReadOnly);
+ surface_uv_map = surface_component
+ .attribute_try_get_for_read(curves_id_->surface_uv_map,
+ ATTR_DOMAIN_CORNER)
+ .typed<float2>();
}
- /* Resize to add the new curves, building the offsets in the array owned by the curves. */
- const int tot_added_curves = added_points.bary_coords.size();
- curves_->resize(curves_->points_num(), curves_->curves_num() + tot_added_curves);
- if (interpolate_point_count_) {
- this->initialize_curve_offsets_with_interpolation(neighbors_per_curve);
- }
- else {
- this->initialize_curve_offsets_without_interpolation(constant_points_per_curve_);
+ /* Find normals. */
+ if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(surface_);
}
+ const Span<float3> corner_normals_su = {
+ reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
+ surface_->totloop};
- /* Resize to add the correct point count calculated as part of building the offsets. */
- curves_->resize(curves_->offsets().last(), curves_->curves_num());
-
- this->initialize_attributes(added_points, neighbors_per_curve);
+ geometry::AddCurvesOnMeshInputs add_inputs;
+ add_inputs.root_positions_cu = added_points.positions_cu;
+ add_inputs.bary_coords = added_points.bary_coords;
+ add_inputs.looptri_indices = added_points.looptri_indices;
+ add_inputs.interpolate_length = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
+ add_inputs.interpolate_shape = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
+ add_inputs.interpolate_point_count = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
+ add_inputs.fallback_curve_length = brush_settings_->curve_length;
+ add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve);
+ add_inputs.surface = surface_;
+ add_inputs.surface_bvh = &surface_bvh_;
+ add_inputs.surface_looptris = surface_looptris_;
+ add_inputs.surface_uv_map = surface_uv_map;
+ add_inputs.corner_normals_su = corner_normals_su;
+ add_inputs.curves_to_surface_mat = transforms_.curves_to_surface;
+ add_inputs.surface_to_curves_normal_mat = transforms_.surface_to_curves_normal;
+
+ if (add_inputs.interpolate_length || add_inputs.interpolate_shape ||
+ add_inputs.interpolate_point_count) {
+ this->ensure_curve_roots_kdtree();
+ add_inputs.old_roots_kdtree = self_->curve_roots_kdtree_;
+ }
- curves_->update_curve_types();
+ geometry::add_curves_on_mesh(*curves_, add_inputs);
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
- ED_region_tag_redraw(region_);
- }
-
- float3 get_bary_coords(const Mesh &mesh, const MLoopTri &looptri, const float3 position) const
- {
- const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co;
- const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co;
- const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co;
- float3 bary_coords;
- interp_weights_tri_v3(bary_coords, v0, v1, v2, position);
- return bary_coords;
+ ED_region_tag_redraw(ctx_.region);
}
/**
@@ -276,16 +232,16 @@ struct AddOperationExecutor {
{
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;
+ ctx_.depsgraph, ctx_.region, ctx_.v3d, brush_pos_re_, ray_start_wo, ray_end_wo, true);
+ const float3 ray_start_cu = transforms_.world_to_curves * ray_start_wo;
+ const float3 ray_end_cu = transforms_.world_to_curves * 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);
+ const float4x4 transform = transforms_.curves_to_surface * brush_transform;
+ this->sample_in_center(r_added_points, transform * ray_start_cu, transform * ray_end_cu);
}
}
@@ -312,10 +268,10 @@ struct AddOperationExecutor {
const int looptri_index = ray_hit.index;
const float3 brush_pos_su = ray_hit.co;
- const float3 bary_coords = this->get_bary_coords(
+ const float3 bary_coords = bke::mesh_surface_sample::compute_bary_coord_in_triangle(
*surface_, surface_looptris_[looptri_index], brush_pos_su);
- const float3 brush_pos_cu = surface_to_curves_mat_ * brush_pos_su;
+ const float3 brush_pos_cu = transforms_.surface_to_curves * brush_pos_su;
r_added_points.positions_cu.append(brush_pos_cu);
r_added_points.bary_coords.append(bary_coords);
@@ -339,57 +295,37 @@ struct AddOperationExecutor {
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);
+ const int max_iterations = 100;
int current_iteration = 0;
while (r_added_points.bary_coords.size() < old_amount + add_amount_) {
if (current_iteration++ >= max_iterations) {
break;
}
-
- const float r = brush_radius_re_ * std::sqrt(rng.get_float());
- const float angle = rng.get_float() * 2.0f * M_PI;
- const float2 pos_re = brush_pos_re_ + r * float2(std::cos(angle), std::sin(angle));
-
- 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 = 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;
- ray_hit.dist = FLT_MAX;
- ray_hit.index = -1;
- BLI_bvhtree_ray_cast(surface_bvh_.tree,
- ray_start_su,
- ray_direction_su,
- 0.0f,
- &ray_hit,
- surface_bvh_.raycast_callback,
- &surface_bvh_);
-
- if (ray_hit.index == -1) {
- continue;
- }
-
- if (use_front_face_) {
- const float3 normal_su = ray_hit.no;
- if (math::dot(ray_direction_su, normal_su) >= 0.0f) {
- continue;
- }
+ const int missing_amount = add_amount_ + old_amount - r_added_points.bary_coords.size();
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_projected(
+ rng,
+ *surface_,
+ surface_bvh_,
+ brush_pos_re_,
+ brush_radius_re_,
+ [&](const float2 &pos_re, float3 &r_start_su, float3 &r_end_su) {
+ float3 start_wo, end_wo;
+ ED_view3d_win_to_segment_clipped(
+ ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, start_wo, end_wo, true);
+ const float3 start_cu = brush_transform * (transforms_.world_to_curves * start_wo);
+ const float3 end_cu = brush_transform * (transforms_.world_to_curves * end_wo);
+ r_start_su = transforms_.curves_to_surface * start_cu;
+ r_end_su = transforms_.curves_to_surface * end_cu;
+ },
+ use_front_face_,
+ add_amount_,
+ missing_amount,
+ r_added_points.bary_coords,
+ r_added_points.looptri_indices,
+ r_added_points.positions_cu);
+ for (float3 &pos : r_added_points.positions_cu.as_mutable_span().take_back(new_points)) {
+ pos = transforms_.surface_to_curves * pos;
}
-
- const int looptri_index = ray_hit.index;
- const float3 pos_su = ray_hit.co;
-
- const float3 bary_coords = this->get_bary_coords(
- *surface_, surface_looptris_[looptri_index], pos_su);
-
- const float3 pos_cu = surface_to_curves_mat_ * pos_su;
-
- r_added_points.positions_cu.append(pos_cu);
- r_added_points.bary_coords.append(bary_coords);
- r_added_points.looptri_indices.append(looptri_index);
}
}
@@ -400,33 +336,40 @@ struct AddOperationExecutor {
{
/* Find ray that starts in the center of the brush. */
float3 brush_ray_start_wo, brush_ray_end_wo;
- ED_view3d_win_to_segment_clipped(
- 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;
+ ED_view3d_win_to_segment_clipped(ctx_.depsgraph,
+ ctx_.region,
+ ctx_.v3d,
+ brush_pos_re_,
+ brush_ray_start_wo,
+ brush_ray_end_wo,
+ true);
+ const float3 brush_ray_start_cu = transforms_.world_to_curves * brush_ray_start_wo;
+ const float3 brush_ray_end_cu = transforms_.world_to_curves * brush_ray_end_wo;
/* Find ray that starts on the boundary of the brush. That is used to compute the brush radius
* in 3D. */
float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo;
- ED_view3d_win_to_segment_clipped(depsgraph_,
- region_,
- v3d_,
+ ED_view3d_win_to_segment_clipped(ctx_.depsgraph,
+ ctx_.region,
+ ctx_.v3d,
brush_pos_re_ + float2(brush_radius_re_, 0),
brush_radius_ray_start_wo,
brush_radius_ray_end_wo,
true);
- 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 float3 brush_radius_ray_start_cu = transforms_.world_to_curves *
+ brush_radius_ray_start_wo;
+ const float3 brush_radius_ray_end_cu = transforms_.world_to_curves * 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) {
+ const float4x4 transform = transforms_.curves_to_surface * brush_transform;
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);
+ transform * brush_ray_start_cu,
+ transform * brush_ray_end_cu,
+ transform * brush_radius_ray_start_cu,
+ transform * brush_radius_ray_end_cu);
}
}
@@ -496,9 +439,6 @@ struct AddOperationExecutor {
const float brush_plane_area_su = M_PI * brush_radius_sq_su;
const float approximate_density_su = add_amount_ / brush_plane_area_su;
- /* Used for switching between two triangle sampling strategies. */
- const float area_threshold = brush_plane_area_su;
-
/* Usually one or two iterations should be enough. */
const int max_iterations = 5;
int current_iteration = 0;
@@ -508,78 +448,18 @@ struct AddOperationExecutor {
if (current_iteration++ >= max_iterations) {
break;
}
-
- for (const int looptri_index : looptri_indices) {
- const MLoopTri &looptri = surface_looptris_[looptri_index];
-
- const float3 v0_su = surface_->mvert[surface_->mloop[looptri.tri[0]].v].co;
- const float3 v1_su = surface_->mvert[surface_->mloop[looptri.tri[1]].v].co;
- const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co;
-
- const float looptri_area_su = area_tri_v3(v0_su, v1_su, v2_su);
-
- if (looptri_area_su < area_threshold) {
- /* The triangle is small compared to the brush radius. Sample by generating random
- * barycentric coordinates. */
- const int amount = rng.round_probabilistic(approximate_density_su * looptri_area_su);
- for ([[maybe_unused]] const int i : IndexRange(amount)) {
- const float3 bary_coord = rng.get_barycentric_coordinates();
- const float3 point_pos_su = attribute_math::mix3(bary_coord, v0_su, v1_su, v2_su);
- const float distance_to_brush_sq_su = math::distance_squared(point_pos_su,
- brush_pos_su);
- if (distance_to_brush_sq_su > brush_radius_sq_su) {
- continue;
- }
-
- r_added_points.bary_coords.append(bary_coord);
- r_added_points.looptri_indices.append(looptri_index);
- r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su);
- }
- }
- else {
- /* The triangle is large compared to the brush radius. Sample by generating random points
- * on the triangle plane within the brush radius. */
- float3 normal_su;
- normal_tri_v3(normal_su, v0_su, v1_su, v2_su);
-
- float3 brush_pos_proj_su = brush_pos_su;
- project_v3_plane(brush_pos_proj_su, normal_su, v0_su);
-
- const float proj_distance_sq_su = math::distance_squared(brush_pos_proj_su,
- brush_pos_su);
- const float brush_radius_factor_sq = 1.0f -
- std::min(1.0f,
- proj_distance_sq_su / brush_radius_sq_su);
- const float radius_proj_sq_su = brush_radius_sq_su * brush_radius_factor_sq;
- const float radius_proj_su = std::sqrt(radius_proj_sq_su);
- const float circle_area_su = M_PI * radius_proj_su;
-
- const int amount = rng.round_probabilistic(approximate_density_su * circle_area_su);
-
- const float3 axis_1_su = math::normalize(v1_su - v0_su) * radius_proj_su;
- const float3 axis_2_su = math::normalize(math::cross(
- axis_1_su, math::cross(axis_1_su, v2_su - v0_su))) *
- radius_proj_su;
-
- for ([[maybe_unused]] const int i : IndexRange(amount)) {
- const float r = std::sqrt(rng.get_float());
- const float angle = rng.get_float() * 2.0f * M_PI;
- const float x = r * std::cos(angle);
- const float y = r * std::sin(angle);
- const float3 point_pos_su = brush_pos_proj_su + axis_1_su * x + axis_2_su * y;
- if (!isect_point_tri_prism_v3(point_pos_su, v0_su, v1_su, v2_su)) {
- /* Sampled point is not in the triangle. */
- continue;
- }
-
- float3 bary_coord;
- interp_weights_tri_v3(bary_coord, v0_su, v1_su, v2_su, point_pos_su);
-
- r_added_points.bary_coords.append(bary_coord);
- r_added_points.looptri_indices.append(looptri_index);
- r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su);
- }
- }
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical(
+ rng,
+ *surface_,
+ looptri_indices,
+ brush_pos_su,
+ brush_radius_su,
+ approximate_density_su,
+ r_added_points.bary_coords,
+ r_added_points.looptri_indices,
+ r_added_points.positions_cu);
+ for (float3 &pos : r_added_points.positions_cu.as_mutable_span().take_back(new_points)) {
+ pos = transforms_.surface_to_curves * pos;
}
}
@@ -604,298 +484,11 @@ struct AddOperationExecutor {
BLI_kdtree_3d_balance(self_->curve_roots_kdtree_);
}
}
-
- void initialize_curve_offsets_with_interpolation(const Span<NeighborsVector> neighbors_per_curve)
- {
- MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
-
- attribute_math::DefaultMixer<int> mixer{new_offsets};
- threading::parallel_for(neighbors_per_curve.index_range(), 1024, [&](IndexRange curves_range) {
- for (const int i : curves_range) {
- if (neighbors_per_curve[i].is_empty()) {
- mixer.mix_in(i, constant_points_per_curve_, 1.0f);
- }
- else {
- for (const NeighborInfo &neighbor : neighbors_per_curve[i]) {
- const int neighbor_points_num = curves_->points_for_curve(neighbor.index).size();
- mixer.mix_in(i, neighbor_points_num, neighbor.weight);
- }
- }
- }
- });
- mixer.finalize();
-
- bke::curves::accumulate_counts_to_offsets(new_offsets, tot_old_points_);
- }
-
- void initialize_curve_offsets_without_interpolation(const int points_per_curve)
- {
- MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
- int offset = tot_old_points_;
- for (const int i : new_offsets.index_range()) {
- new_offsets[i] = offset;
- offset += points_per_curve;
- }
- }
-
- void initialize_attributes(const AddedPoints &added_points,
- const Span<NeighborsVector> neighbors_per_curve)
- {
- Array<float> new_lengths_cu(added_points.bary_coords.size());
- if (interpolate_length_) {
- this->interpolate_lengths(neighbors_per_curve, new_lengths_cu);
- }
- else {
- new_lengths_cu.fill(new_curve_length_);
- }
-
- Array<float3> new_normals_su = this->compute_normals_for_added_curves_su(added_points);
- this->initialize_surface_attachment(added_points);
-
- this->fill_new_selection();
-
- if (interpolate_shape_) {
- this->initialize_position_with_interpolation(
- added_points, neighbors_per_curve, new_normals_su, new_lengths_cu);
- }
- else {
- this->initialize_position_without_interpolation(
- added_points, new_lengths_cu, new_normals_su);
- }
- }
-
- /**
- * Select newly created points or curves in new curves if necessary.
- */
- void fill_new_selection()
- {
- switch (curves_id_->selection_domain) {
- case ATTR_DOMAIN_CURVE: {
- const VArray<float> selection = curves_->selection_curve_float();
- if (selection.is_single() && selection.get_internal_single() >= 1.0f) {
- return;
- }
- curves_->selection_curve_float_for_write().drop_front(tot_old_curves_).fill(1.0f);
- break;
- }
- case ATTR_DOMAIN_POINT: {
- const VArray<float> selection = curves_->selection_point_float();
- if (selection.is_single() && selection.get_internal_single() >= 1.0f) {
- return;
- }
- curves_->selection_point_float_for_write().drop_front(tot_old_points_).fill(1.0f);
- break;
- }
- default:
- BLI_assert_unreachable();
- }
- }
-
- Array<NeighborsVector> find_curve_neighbors(const AddedPoints &added_points)
- {
- const int tot_added_curves = added_points.bary_coords.size();
- Array<NeighborsVector> neighbors_per_curve(tot_added_curves);
- threading::parallel_for(IndexRange(tot_added_curves), 128, [&](const IndexRange range) {
- for (const int i : range) {
- const float3 root_cu = added_points.positions_cu[i];
- std::array<KDTreeNearest_3d, max_neighbors> nearest_n;
- const int found_neighbors = BLI_kdtree_3d_find_nearest_n(
- self_->curve_roots_kdtree_, root_cu, nearest_n.data(), max_neighbors);
- float tot_weight = 0.0f;
- for (const int neighbor_i : IndexRange(found_neighbors)) {
- KDTreeNearest_3d &nearest = nearest_n[neighbor_i];
- const float weight = 1.0f / std::max(nearest.dist, 0.00001f);
- tot_weight += weight;
- neighbors_per_curve[i].append({nearest.index, weight});
- }
- /* Normalize weights. */
- for (NeighborInfo &neighbor : neighbors_per_curve[i]) {
- neighbor.weight /= tot_weight;
- }
- }
- });
- return neighbors_per_curve;
- }
-
- void interpolate_lengths(const Span<NeighborsVector> neighbors_per_curve,
- MutableSpan<float> r_lengths)
- {
- const Span<float3> positions_cu = curves_->positions();
-
- threading::parallel_for(r_lengths.index_range(), 128, [&](const IndexRange range) {
- for (const int added_curve_i : range) {
- const Span<NeighborInfo> neighbors = neighbors_per_curve[added_curve_i];
- float length_sum = 0.0f;
- for (const NeighborInfo &neighbor : neighbors) {
- const IndexRange neighbor_points = curves_->points_for_curve(neighbor.index);
- float neighbor_length = 0.0f;
- for (const int segment_i : neighbor_points.drop_back(1)) {
- const float3 &p1 = positions_cu[segment_i];
- const float3 &p2 = positions_cu[segment_i + 1];
- neighbor_length += math::distance(p1, p2);
- }
- length_sum += neighbor.weight * neighbor_length;
- }
- const float length = neighbors.is_empty() ? new_curve_length_ : length_sum;
- r_lengths[added_curve_i] = length;
- }
- });
- }
-
- float3 compute_point_normal_su(const int looptri_index, const float3 &bary_coord)
- {
- const MLoopTri &looptri = surface_looptris_[looptri_index];
- const int l0 = looptri.tri[0];
- const int l1 = looptri.tri[1];
- const int l2 = looptri.tri[2];
-
- const float3 &l0_normal_su = corner_normals_su_[l0];
- const float3 &l1_normal_su = corner_normals_su_[l1];
- const float3 &l2_normal_su = corner_normals_su_[l2];
-
- const float3 normal_su = math::normalize(
- attribute_math::mix3(bary_coord, l0_normal_su, l1_normal_su, l2_normal_su));
- return normal_su;
- }
-
- Array<float3> compute_normals_for_added_curves_su(const AddedPoints &added_points)
- {
- Array<float3> normals_su(added_points.bary_coords.size());
- threading::parallel_for(normals_su.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const int looptri_index = added_points.looptri_indices[i];
- const float3 &bary_coord = added_points.bary_coords[i];
- normals_su[i] = this->compute_point_normal_su(looptri_index, bary_coord);
- }
- });
- return normals_su;
- }
-
- void initialize_surface_attachment(const AddedPoints &added_points)
- {
- MutableSpan<int> surface_triangle_indices = curves_->surface_triangle_indices_for_write();
- MutableSpan<float2> surface_triangle_coords = curves_->surface_triangle_coords_for_write();
- threading::parallel_for(
- added_points.bary_coords.index_range(), 1024, [&](const IndexRange range) {
- for (const int i : range) {
- const int curve_i = tot_old_curves_ + i;
- surface_triangle_indices[curve_i] = added_points.looptri_indices[i];
- surface_triangle_coords[curve_i] = float2(added_points.bary_coords[i]);
- }
- });
- }
-
- /**
- * Initialize new curves so that they are just a straight line in the normal direction.
- */
- void initialize_position_without_interpolation(const AddedPoints &added_points,
- const Span<float> lengths_cu,
- const MutableSpan<float3> normals_su)
- {
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
-
- threading::parallel_for(
- added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i);
- const float3 &root_cu = added_points.positions_cu[i];
- const float length = lengths_cu[i];
- const float3 &normal_su = normals_su[i];
- const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
- const float3 tip_cu = root_cu + length * normal_cu;
-
- initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
- }
- });
- }
-
- /**
- * Use neighboring curves to determine the shape.
- */
- void initialize_position_with_interpolation(const AddedPoints &added_points,
- const Span<NeighborsVector> neighbors_per_curve,
- const Span<float3> new_normals_su,
- const Span<float> new_lengths_cu)
- {
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
- const VArray_Span<int> surface_triangle_indices{curves_->surface_triangle_indices()};
- const Span<float2> surface_triangle_coords = curves_->surface_triangle_coords();
-
- threading::parallel_for(
- added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const Span<NeighborInfo> neighbors = neighbors_per_curve[i];
- const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i);
-
- const float length_cu = new_lengths_cu[i];
- const float3 &normal_su = new_normals_su[i];
- const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
-
- const float3 &root_cu = added_points.positions_cu[i];
-
- if (neighbors.is_empty()) {
- /* If there are no neighbors, just make a straight line. */
- const float3 tip_cu = root_cu + length_cu * normal_cu;
- initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
- continue;
- }
-
- positions_cu.slice(points).fill(root_cu);
-
- for (const NeighborInfo &neighbor : neighbors) {
- const int neighbor_curve_i = neighbor.index;
- const int neighbor_looptri_index = surface_triangle_indices[neighbor_curve_i];
-
- float3 neighbor_bary_coord{surface_triangle_coords[neighbor_curve_i]};
- neighbor_bary_coord.z = 1.0f - neighbor_bary_coord.x - neighbor_bary_coord.y;
-
- const float3 neighbor_normal_su = this->compute_point_normal_su(
- neighbor_looptri_index, neighbor_bary_coord);
- const float3 neighbor_normal_cu = math::normalize(surface_to_curves_normal_mat_ *
- neighbor_normal_su);
-
- /* The rotation matrix used to transform relative coordinates of the neighbor curve
- * to the new curve. */
- float normal_rotation_cu[3][3];
- rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu);
-
- const IndexRange neighbor_points = curves_->points_for_curve(neighbor_curve_i);
- const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]];
-
- /* Use a temporary #PolySpline, because that's the easiest way to resample an
- * existing curve right now. Resampling is necessary if the length of the new curve
- * does not match the length of the neighbors or the number of handle points is
- * different. */
- PolySpline neighbor_spline;
- neighbor_spline.resize(neighbor_points.size());
- neighbor_spline.positions().copy_from(positions_cu.slice(neighbor_points));
- neighbor_spline.mark_cache_invalid();
-
- const float neighbor_length_cu = neighbor_spline.length();
- const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu);
-
- const float resample_factor = (1.0f / (points.size() - 1.0f)) * length_factor;
- for (const int j : IndexRange(points.size())) {
- const Spline::LookupResult lookup = neighbor_spline.lookup_evaluated_factor(
- j * resample_factor);
- const float index_factor = lookup.evaluated_index + lookup.factor;
- float3 p;
- neighbor_spline.sample_with_index_factors<float3>(
- neighbor_spline.positions(), {&index_factor, 1}, {&p, 1});
- const float3 relative_coord = p - neighbor_root_cu;
- float3 rotated_relative_coord = relative_coord;
- mul_m3_v3(normal_rotation_cu, rotated_relative_coord);
- positions_cu[points[j]] += neighbor.weight * rotated_relative_coord;
- }
- }
- }
- });
- }
};
void AddOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
{
- AddOperationExecutor executor;
+ AddOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
index 92ce6ba3153..5955c349eae 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
@@ -4,15 +4,22 @@
#include "curves_sculpt_intern.hh"
+#include "BKE_attribute_math.hh"
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
+#include "DNA_meshdata_types.h"
+
#include "ED_view3d.h"
#include "UI_interface.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
#include "BLI_enumerable_thread_specific.hh"
+#include "BLI_length_parameterize.hh"
#include "BLI_task.hh"
/**
@@ -277,4 +284,58 @@ Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetr
return matrices;
}
+void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position)
+{
+ /* Find the accumulated length of each point in the original curve,
+ * treating it as a poly curve for performance reasons and simplicity. */
+ Array<float> orig_lengths(length_parameterize::lengths_num(positions.size(), false));
+ length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths);
+ const float orig_total_length = orig_lengths.last();
+
+ /* Find the factor by which the new curve is shorter or longer than the original. */
+ const float new_last_segment_length = math::distance(positions.last(1), new_last_position);
+ const float new_total_length = orig_lengths.last(1) + new_last_segment_length;
+ const float length_factor = safe_divide(new_total_length, orig_total_length);
+
+ /* Calculate the lengths to sample the original curve with by scaling the original lengths. */
+ Array<float> new_lengths(positions.size() - 1);
+ new_lengths.first() = 0.0f;
+ for (const int i : new_lengths.index_range().drop_front(1)) {
+ new_lengths[i] = orig_lengths[i - 1] * length_factor;
+ }
+
+ Array<int> indices(positions.size() - 1);
+ Array<float> factors(positions.size() - 1);
+ length_parameterize::create_samples_from_sorted_lengths(
+ orig_lengths, new_lengths, false, indices, factors);
+
+ Array<float3> new_positions(positions.size() - 1);
+ length_parameterize::linear_interpolation<float3>(positions, indices, factors, new_positions);
+ positions.drop_back(1).copy_from(new_positions);
+ positions.last() = new_last_position;
+}
+
+CurvesSculptCommonContext::CurvesSculptCommonContext(const bContext &C)
+{
+ this->depsgraph = CTX_data_depsgraph_pointer(&C);
+ this->scene = CTX_data_scene(&C);
+ this->region = CTX_wm_region(&C);
+ this->v3d = CTX_wm_view3d(&C);
+ this->rv3d = CTX_wm_region_view3d(&C);
+}
+
+CurvesSculptTransforms::CurvesSculptTransforms(const Object &curves_ob, const Object *surface_ob)
+{
+ this->curves_to_world = curves_ob.obmat;
+ this->world_to_curves = this->curves_to_world.inverted();
+
+ if (surface_ob != nullptr) {
+ this->surface_to_world = surface_ob->obmat;
+ this->world_to_surface = this->surface_to_world.inverted();
+ this->surface_to_curves = this->world_to_curves * this->surface_to_world;
+ this->curves_to_surface = this->world_to_surface * this->curves_to_world;
+ this->surface_to_curves_normal = this->surface_to_curves.inverted().transposed();
+ }
+}
+
} // 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 46332a66f60..541bf9d8253 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
@@ -78,11 +78,7 @@ class CombOperation : public CurvesSculptStrokeOperation {
*/
struct CombOperationExecutor {
CombOperation *self_ = nullptr;
- const Depsgraph *depsgraph_ = nullptr;
- const Scene *scene_ = nullptr;
- ARegion *region_ = nullptr;
- const View3D *v3d_ = nullptr;
- const RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
@@ -100,21 +96,15 @@ struct CombOperationExecutor {
Vector<int64_t> selected_curve_indices_;
IndexMask curve_selection_;
- const Object *surface_ob_ = nullptr;
- const Mesh *surface_ = nullptr;
- Span<MLoopTri> surface_looptris_;
-
float2 brush_pos_prev_re_;
float2 brush_pos_re_;
float2 brush_pos_diff_re_;
- float brush_pos_diff_length_re_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
- float4x4 surface_to_world_mat_;
- float4x4 world_to_surface_mat_;
+ CurvesSculptTransforms transforms_;
- BVHTreeFromMesh surface_bvh_;
+ CombOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
void execute(CombOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
{
@@ -122,21 +112,13 @@ struct CombOperationExecutor {
BLI_SCOPED_DEFER([&]() { self_->brush_pos_last_re_ = stroke_extension.mouse_position; });
- depsgraph_ = CTX_data_depsgraph_pointer(&C);
- scene_ = CTX_data_scene(&C);
object_ = CTX_data_active_object(&C);
- region_ = CTX_wm_region(&C);
- v3d_ = CTX_wm_view3d(&C);
- rv3d_ = CTX_wm_region_view3d(&C);
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
- brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
- brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
-
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
@@ -146,29 +128,14 @@ struct CombOperationExecutor {
return;
}
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
+
point_factors_ = get_point_selection(*curves_id_);
curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
brush_pos_prev_re_ = self_->brush_pos_last_re_;
brush_pos_re_ = stroke_extension.mouse_position;
brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_;
- brush_pos_diff_length_re_ = math::length(brush_pos_diff_re_);
-
- surface_ob_ = curves_id_->surface;
- if (surface_ob_ != nullptr) {
- surface_ = static_cast<const Mesh *>(surface_ob_->data);
- surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_),
- BKE_mesh_runtime_looptri_len(surface_)};
- surface_to_world_mat_ = surface_ob_->obmat;
- world_to_surface_mat_ = surface_to_world_mat_.inverted();
- BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
- }
-
- BLI_SCOPED_DEFER([&]() {
- if (surface_ob_ != nullptr) {
- free_bvhtree_from_mesh(&surface_bvh_);
- }
- });
if (stroke_extension.is_first) {
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
@@ -196,7 +163,7 @@ struct CombOperationExecutor {
curves_->tag_positions_changed();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
- ED_region_tag_redraw(region_);
+ ED_region_tag_redraw(ctx_.region);
}
/**
@@ -219,7 +186,7 @@ struct CombOperationExecutor {
MutableSpan<float3> positions_cu = curves_->positions_for_write();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
@@ -234,7 +201,7 @@ struct CombOperationExecutor {
/* Find the position of the point in screen space. */
float2 old_pos_re;
- ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values);
const float distance_to_brush_sq_re = dist_squared_to_line_segment_v2(
old_pos_re, brush_pos_prev_re_, brush_pos_re_);
@@ -254,10 +221,13 @@ struct CombOperationExecutor {
*/
const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
float3 new_position_wo;
- ED_view3d_win_to_3d(
- v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo);
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * old_pos_cu,
+ new_position_re,
+ new_position_wo);
const float3 new_position_cu = brush_transform *
- (world_to_curves_mat_ * new_position_wo);
+ (transforms_.world_to_curves * new_position_wo);
positions_cu[point_i] = new_position_cu;
curve_changed = true;
@@ -275,21 +245,21 @@ struct CombOperationExecutor {
void comb_spherical_with_symmetry(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
float3 brush_start_wo, brush_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_prev_re_,
brush_start_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
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_start_cu = transforms_.world_to_curves * brush_start_wo;
+ const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo;
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
@@ -352,8 +322,13 @@ struct CombOperationExecutor {
*/
void initialize_spherical_brush_reference_point()
{
- std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -407,7 +382,7 @@ struct CombOperationExecutor {
void CombOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
{
- CombOperationExecutor executor;
+ CombOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
index 5a192346f39..eab7dabcd22 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
@@ -60,11 +60,7 @@ class DeleteOperation : public CurvesSculptStrokeOperation {
struct DeleteOperationExecutor {
DeleteOperation *self_ = nullptr;
- const Depsgraph *depsgraph_ = nullptr;
- const Scene *scene_ = nullptr;
- ARegion *region_ = nullptr;
- const View3D *v3d_ = nullptr;
- const RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
@@ -80,19 +76,16 @@ struct DeleteOperationExecutor {
float2 brush_pos_re_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSculptTransforms transforms_;
- void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ DeleteOperationExecutor(const bContext &C) : ctx_(C)
{
+ }
+ void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ {
self_ = &self;
- depsgraph_ = CTX_data_depsgraph_pointer(&C);
- scene_ = CTX_data_scene(&C);
object_ = CTX_data_active_object(&C);
- region_ = CTX_wm_region(&C);
- v3d_ = CTX_wm_view3d(&C);
- rv3d_ = CTX_wm_region_view3d(&C);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
@@ -100,15 +93,14 @@ struct DeleteOperationExecutor {
selected_curve_indices_.clear();
curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
- brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
brush_pos_re_ = stroke_extension.mouse_position;
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
@@ -140,7 +132,7 @@ struct DeleteOperationExecutor {
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
- ED_region_tag_redraw(region_);
+ ED_region_tag_redraw(ctx_.region);
}
void delete_projected_with_symmetry(MutableSpan<bool> curves_to_delete)
@@ -157,7 +149,7 @@ struct DeleteOperationExecutor {
const float4x4 brush_transform_inv = brush_transform.inverted();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
Span<float3> positions_cu = curves_->positions();
@@ -170,7 +162,7 @@ struct DeleteOperationExecutor {
if (points.size() == 1) {
const float3 pos_cu = brush_transform_inv * positions_cu[points.first()];
float2 pos_re;
- ED_view3d_project_float_v2_m4(region_, pos_cu, pos_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
if (math::distance_squared(brush_pos_re_, pos_re) <= brush_radius_sq_re) {
curves_to_delete[curve_i] = true;
@@ -183,8 +175,8 @@ struct DeleteOperationExecutor {
const float3 pos2_cu = brush_transform_inv * positions_cu[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);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, pos2_re, projection.values);
const float dist_sq_re = dist_squared_to_line_segment_v2(
brush_pos_re_, pos1_re, pos2_re);
@@ -200,15 +192,15 @@ struct DeleteOperationExecutor {
void delete_spherical_with_symmetry(MutableSpan<bool> curves_to_delete)
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
float3 brush_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_wo);
- const float3 brush_cu = world_to_curves_mat_ * brush_wo;
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -255,8 +247,13 @@ struct DeleteOperationExecutor {
void initialize_spherical_brush_reference_point()
{
- std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -266,7 +263,7 @@ struct DeleteOperationExecutor {
void DeleteOperation::on_stroke_extended(const bContext &C,
const StrokeExtension &stroke_extension)
{
- DeleteOperationExecutor executor;
+ DeleteOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
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 d87828e7437..cf893f09fc6 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
@@ -151,50 +151,10 @@ class ExtrapolateCurvesEffect : public CurvesEffect {
const float3 direction = math::normalize(old_last_pos_cu - direction_reference_point);
const float3 new_last_pos_cu = old_last_pos_cu + direction * move_distance_cu;
- this->move_last_point_and_resample(positions_cu, curve_points, new_last_pos_cu);
+ move_last_point_and_resample(positions_cu.slice(curve_points), new_last_pos_cu);
}
});
}
-
- void move_last_point_and_resample(MutableSpan<float3> positions,
- const IndexRange curve_points,
- const float3 &new_last_point_position) const
- {
- Vector<float> old_lengths;
- old_lengths.append(0.0f);
- /* Used to (1) normalize the segment sizes over time and (2) support making zero-length
- * segments */
- const float extra_length = 0.001f;
- for (const int segment_i : IndexRange(curve_points.size() - 1)) {
- const float3 &p1 = positions[curve_points[segment_i]];
- const float3 &p2 = positions[curve_points[segment_i] + 1];
- const float length = math::distance(p1, p2);
- old_lengths.append(old_lengths.last() + length + extra_length);
- }
- Vector<float> point_factors;
- for (float &old_length : old_lengths) {
- point_factors.append(old_length / old_lengths.last());
- }
-
- PolySpline new_spline;
- new_spline.resize(curve_points.size());
- MutableSpan<float3> new_spline_positions = new_spline.positions();
- for (const int i : IndexRange(curve_points.size() - 1)) {
- new_spline_positions[i] = positions[curve_points[i]];
- }
- new_spline_positions.last() = new_last_point_position;
- new_spline.mark_cache_invalid();
-
- for (const int i : IndexRange(curve_points.size())) {
- const float factor = point_factors[i];
- const Spline::LookupResult lookup = new_spline.lookup_evaluated_factor(factor);
- const float index_factor = lookup.evaluated_index + lookup.factor;
- float3 p;
- new_spline.sample_with_index_factors<float3>(
- new_spline_positions, {&index_factor, 1}, {&p, 1});
- positions[curve_points[i]] = p;
- }
- }
};
/**
@@ -270,11 +230,7 @@ class CurvesEffectOperation : public CurvesSculptStrokeOperation {
*/
struct CurvesEffectOperationExecutor {
CurvesEffectOperation *self_ = nullptr;
- const Depsgraph *depsgraph_ = nullptr;
- const Scene *scene_ = nullptr;
- ARegion *region_ = nullptr;
- const View3D *v3d_ = nullptr;
- const RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
@@ -291,8 +247,7 @@ struct CurvesEffectOperationExecutor {
eBrushFalloffShape falloff_shape_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSculptTransforms transforms_;
float2 brush_pos_start_re_;
float2 brush_pos_end_re_;
@@ -302,6 +257,10 @@ struct CurvesEffectOperationExecutor {
Vector<float> move_distances_cu;
};
+ CurvesEffectOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
void execute(CurvesEffectOperation &self,
const bContext &C,
const StrokeExtension &stroke_extension)
@@ -309,12 +268,7 @@ struct CurvesEffectOperationExecutor {
BLI_SCOPED_DEFER([&]() { self.last_mouse_position_ = stroke_extension.mouse_position; });
self_ = &self;
- depsgraph_ = CTX_data_depsgraph_pointer(&C);
- scene_ = CTX_data_scene(&C);
object_ = CTX_data_active_object(&C);
- region_ = CTX_wm_region(&C);
- v3d_ = CTX_wm_view3d(&C);
- rv3d_ = CTX_wm_region_view3d(&C);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
@@ -325,18 +279,17 @@ struct CurvesEffectOperationExecutor {
curve_selection_factors_ = get_curves_selection(*curves_id_);
curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
- const CurvesSculpt &curves_sculpt = *scene_->toolsettings->curves_sculpt;
+ const CurvesSculpt &curves_sculpt = *ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt.paint);
- brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
- brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
- brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
falloff_shape_ = eBrushFalloffShape(brush_->falloff_shape);
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
brush_pos_start_re_ = self.last_mouse_position_;
brush_pos_end_re_ = stroke_extension.mouse_position;
@@ -344,10 +297,10 @@ struct CurvesEffectOperationExecutor {
if (stroke_extension.is_first) {
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
if (std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_,
- *region_,
- *v3d_,
- *rv3d_,
+ *ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
*object_,
stroke_extension.mouse_position,
brush_radius_base_re_)) {
@@ -376,7 +329,7 @@ struct CurvesEffectOperationExecutor {
curves_->tag_positions_changed();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
- ED_region_tag_redraw(region_);
+ ED_region_tag_redraw(ctx_.region);
}
void gather_influences_projected(
@@ -385,7 +338,7 @@ struct CurvesEffectOperationExecutor {
const Span<float3> positions_cu = curves_->positions();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -412,8 +365,8 @@ struct CurvesEffectOperationExecutor {
const float3 p2_cu = brush_transform_inv * positions_cu[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);
+ ED_view3d_project_float_v2_m4(ctx_.region, p1_cu, p1_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, p2_cu, p2_re, projection.values);
float2 closest_on_brush_re;
float2 closest_on_segment_re;
@@ -441,18 +394,18 @@ struct CurvesEffectOperationExecutor {
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,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * 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,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * 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 float3 brush_start_pos_cu = transforms_.world_to_curves * brush_start_pos_wo;
+ const float3 brush_end_pos_cu = transforms_.world_to_curves * brush_end_pos_wo;
const float move_distance_cu = weight *
math::distance(brush_start_pos_cu, brush_end_pos_cu);
@@ -473,18 +426,18 @@ struct CurvesEffectOperationExecutor {
const Span<float3> positions_cu = curves_->positions();
float3 brush_pos_start_wo, brush_pos_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_start_re_,
brush_pos_start_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_end_re_,
brush_pos_end_wo);
- const float3 brush_pos_start_cu = world_to_curves_mat_ * brush_pos_start_wo;
- const float3 brush_pos_end_cu = world_to_curves_mat_ * brush_pos_end_wo;
+ const float3 brush_pos_start_cu = transforms_.world_to_curves * brush_pos_start_wo;
+ const float3 brush_pos_end_cu = transforms_.world_to_curves * brush_pos_end_wo;
const float3 brush_pos_diff_cu = brush_pos_end_cu - brush_pos_start_cu;
const float brush_pos_diff_length_cu = math::length(brush_pos_diff_cu);
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
@@ -547,7 +500,7 @@ struct CurvesEffectOperationExecutor {
void CurvesEffectOperation::on_stroke_extended(const bContext &C,
const StrokeExtension &stroke_extension)
{
- CurvesEffectOperationExecutor executor;
+ CurvesEffectOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
index 3635ad84c36..ce84d94fbd5 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
@@ -95,4 +95,30 @@ VArray<float> get_point_selection(const Curves &curves_id);
*/
IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices);
+void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position);
+
+class CurvesSculptCommonContext {
+ public:
+ const Depsgraph *depsgraph = nullptr;
+ const Scene *scene = nullptr;
+ ARegion *region = nullptr;
+ const View3D *v3d = nullptr;
+ const RegionView3D *rv3d = nullptr;
+
+ CurvesSculptCommonContext(const bContext &C);
+};
+
+struct CurvesSculptTransforms {
+ float4x4 curves_to_world;
+ float4x4 curves_to_surface;
+ float4x4 world_to_curves;
+ float4x4 world_to_surface;
+ float4x4 surface_to_world;
+ float4x4 surface_to_curves;
+ float4x4 surface_to_curves_normal;
+
+ CurvesSculptTransforms() = default;
+ CurvesSculptTransforms(const Object &curves_ob, const Object *surface_ob);
+};
+
} // 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 aa2ec54c73f..5d6ffa67005 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
@@ -18,6 +18,7 @@
#include "WM_toolsystem.h"
#include "ED_curves_sculpt.h"
+#include "ED_image.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -49,7 +50,7 @@
bool CURVES_SCULPT_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
return ob && ob->mode & OB_MODE_SCULPT_CURVES;
}
@@ -109,9 +110,9 @@ static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bConte
{
const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op.ptr, "mode"));
- Scene &scene = *CTX_data_scene(&C);
- CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
- Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
+ const Scene &scene = *CTX_data_scene(&C);
+ const CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
+ const Brush &brush = *BKE_paint_brush_for_read(&curves_sculpt.paint);
switch (brush.curves_sculpt_tool) {
case CURVES_SCULPT_TOOL_COMB:
return new_comb_operation();
@@ -182,8 +183,8 @@ 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);
+ const Paint *paint = BKE_paint_get_active_from_context(C);
+ const Brush *brush = BKE_paint_brush_for_read(paint);
if (brush == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -252,7 +253,7 @@ static void SCULPT_CURVES_OT_brush_stroke(struct wmOperatorType *ot)
static bool curves_sculptmode_toggle_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
if (ob == nullptr) {
return false;
}
@@ -271,7 +272,7 @@ static void curves_sculptmode_enter(bContext *C)
ob->mode = OB_MODE_SCULPT_CURVES;
- paint_cursor_start(&curves_sculpt->paint, CURVES_SCULPT_mode_poll_view3d);
+ ED_paint_cursor_start(&curves_sculpt->paint, CURVES_SCULPT_mode_poll_view3d);
/* Update for mode change. */
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc
index 250987466d5..b40aebcaaf1 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc
@@ -51,12 +51,7 @@ class SelectionPaintOperation : public CurvesSculptStrokeOperation {
struct SelectionPaintOperationExecutor {
SelectionPaintOperation *self_ = nullptr;
- const bContext *C_ = nullptr;
- const Depsgraph *depsgraph_ = nullptr;
- const Scene *scene_ = nullptr;
- ARegion *region_ = nullptr;
- const View3D *v3d_ = nullptr;
- const RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
@@ -71,29 +66,30 @@ struct SelectionPaintOperationExecutor {
float2 brush_pos_re_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSculptTransforms transforms_;
+
+ SelectionPaintOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
void execute(SelectionPaintOperation &self,
const bContext &C,
const StrokeExtension &stroke_extension)
{
self_ = &self;
- depsgraph_ = CTX_data_depsgraph_pointer(&C);
- scene_ = CTX_data_scene(&C);
object_ = CTX_data_active_object(&C);
- region_ = CTX_wm_region(&C);
- v3d_ = CTX_wm_view3d(&C);
- rv3d_ = CTX_wm_region_view3d(&C);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
curves_id_->flag |= CV_SCULPT_SELECTION_ENABLED;
+ if (curves_->curves_num() == 0) {
+ return;
+ }
- brush_ = BKE_paint_brush_for_read(&scene_->toolsettings->curves_sculpt->paint);
- brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_ = BKE_paint_brush_for_read(&ctx_.scene->toolsettings->curves_sculpt->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
- brush_strength_ = BKE_brush_alpha_get(scene_, brush_);
+ brush_strength_ = BKE_brush_alpha_get(ctx_.scene, brush_);
brush_pos_re_ = stroke_extension.mouse_position;
@@ -108,8 +104,7 @@ struct SelectionPaintOperationExecutor {
}
}
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
@@ -145,7 +140,7 @@ struct SelectionPaintOperationExecutor {
* selection is handled as a generic attribute for now. */
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
- ED_region_tag_redraw(region_);
+ ED_region_tag_redraw(ctx_.region);
}
void paint_point_selection_projected_with_symmetry(MutableSpan<float> selection)
@@ -163,7 +158,7 @@ struct SelectionPaintOperationExecutor {
const float4x4 brush_transform_inv = brush_transform.inverted();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
Span<float3> positions_cu = curves_->positions();
@@ -176,7 +171,7 @@ struct SelectionPaintOperationExecutor {
/* Find the position of the point in screen space. */
float2 pos_re;
- ED_view3d_project_float_v2_m4(region_, pos_cu, pos_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
const float distance_to_brush_sq_re = math::distance_squared(pos_re, brush_pos_re_);
if (distance_to_brush_sq_re > brush_radius_sq_re) {
@@ -199,15 +194,15 @@ struct SelectionPaintOperationExecutor {
void paint_point_selection_spherical_with_symmetry(MutableSpan<float> selection)
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
float3 brush_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_wo);
- const float3 brush_cu = world_to_curves_mat_ * brush_wo;
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -264,7 +259,7 @@ struct SelectionPaintOperationExecutor {
const float4x4 brush_transform_inv = brush_transform.inverted();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
@@ -283,8 +278,8 @@ struct SelectionPaintOperationExecutor {
float2 pos1_re;
float2 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);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, pos2_re, projection.values);
const float distance_sq_re = dist_squared_to_line_segment_v2(
brush_pos_re_, pos1_re, pos2_re);
@@ -307,15 +302,15 @@ struct SelectionPaintOperationExecutor {
void paint_curve_selection_spherical_with_symmetry(MutableSpan<float> selection)
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
float3 brush_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_wo);
- const float3 brush_cu = world_to_curves_mat_ * brush_wo;
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -364,8 +359,13 @@ struct SelectionPaintOperationExecutor {
void initialize_spherical_brush_reference_point()
{
- std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -375,7 +375,7 @@ struct SelectionPaintOperationExecutor {
void SelectionPaintOperation::on_stroke_extended(const bContext &C,
const StrokeExtension &stroke_extension)
{
- SelectionPaintOperationExecutor executor;
+ SelectionPaintOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
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 f834d1e350f..b63e5a7756b 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
@@ -23,7 +23,6 @@
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
-#include "BKE_spline.hh"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
@@ -72,11 +71,7 @@ class SnakeHookOperation : public CurvesSculptStrokeOperation {
*/
struct SnakeHookOperatorExecutor {
SnakeHookOperation *self_ = nullptr;
- const Depsgraph *depsgraph_ = nullptr;
- const Scene *scene_ = nullptr;
- ARegion *region_ = nullptr;
- const View3D *v3d_ = nullptr;
- const RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
@@ -94,13 +89,16 @@ struct SnakeHookOperatorExecutor {
Vector<int64_t> selected_curve_indices_;
IndexMask curve_selection_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSculptTransforms transforms_;
float2 brush_pos_prev_re_;
float2 brush_pos_re_;
float2 brush_pos_diff_re_;
+ SnakeHookOperatorExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
void execute(SnakeHookOperation &self,
const bContext &C,
const StrokeExtension &stroke_extension)
@@ -108,32 +106,25 @@ struct SnakeHookOperatorExecutor {
BLI_SCOPED_DEFER([&]() { self.last_mouse_position_re_ = stroke_extension.mouse_position; });
self_ = &self;
- depsgraph_ = CTX_data_depsgraph_pointer(&C);
- scene_ = CTX_data_scene(&C);
- scene_ = CTX_data_scene(&C);
object_ = CTX_data_active_object(&C);
- region_ = CTX_wm_region(&C);
- v3d_ = CTX_wm_view3d(&C);
- rv3d_ = CTX_wm_region_view3d(&C);
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
- brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
- brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
-
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
if (curves_->curves_num() == 0) {
return;
}
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
+
curve_factors_ = get_curves_selection(*curves_id_);
curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
@@ -143,8 +134,13 @@ struct SnakeHookOperatorExecutor {
if (stroke_extension.is_first) {
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
- std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -165,7 +161,7 @@ struct SnakeHookOperatorExecutor {
curves_->tag_positions_changed();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
- ED_region_tag_redraw(region_);
+ ED_region_tag_redraw(ctx_.region);
}
void projected_snake_hook_with_symmetry()
@@ -184,7 +180,7 @@ struct SnakeHookOperatorExecutor {
MutableSpan<float3> positions_cu = curves_->positions_for_write();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
@@ -196,7 +192,7 @@ struct SnakeHookOperatorExecutor {
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);
+ ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values);
const float distance_to_brush_sq_re = math::distance_squared(old_pos_re,
brush_pos_prev_re_);
@@ -210,11 +206,15 @@ struct SnakeHookOperatorExecutor {
const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
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 = brush_transform * (world_to_curves_mat_ * new_position_wo);
-
- this->move_last_point_and_resample(positions_cu.slice(points), new_position_cu);
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * old_pos_cu,
+ new_position_re,
+ new_position_wo);
+ const float3 new_position_cu = brush_transform *
+ (transforms_.world_to_curves * new_position_wo);
+
+ move_last_point_and_resample(positions_cu.slice(points), new_position_cu);
}
});
}
@@ -222,21 +222,21 @@ struct SnakeHookOperatorExecutor {
void spherical_snake_hook_with_symmetry()
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
float3 brush_start_wo, brush_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_prev_re_,
brush_start_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
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_start_cu = transforms_.world_to_curves * brush_start_wo;
+ const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo;
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
@@ -276,48 +276,16 @@ struct SnakeHookOperatorExecutor {
const float3 new_pos_cu = old_pos_cu + weight * brush_diff_cu;
- this->move_last_point_and_resample(positions_cu.slice(points), new_pos_cu);
+ move_last_point_and_resample(positions_cu.slice(points), new_pos_cu);
}
});
}
-
- void move_last_point_and_resample(MutableSpan<float3> positions,
- const float3 &new_last_position) const
- {
- /* Find the accumulated length of each point in the original curve,
- * treating it as a poly curve for performance reasons and simplicity. */
- Array<float> orig_lengths(length_parameterize::lengths_num(positions.size(), false));
- length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths);
- const float orig_total_length = orig_lengths.last();
-
- /* Find the factor by which the new curve is shorter or longer than the original. */
- const float new_last_segment_length = math::distance(positions.last(1), new_last_position);
- const float new_total_length = orig_lengths.last(1) + new_last_segment_length;
- const float length_factor = new_total_length / orig_total_length;
-
- /* Calculate the lengths to sample the original curve with by scaling the original lengths. */
- Array<float> new_lengths(positions.size() - 1);
- new_lengths.first() = 0.0f;
- for (const int i : new_lengths.index_range().drop_front(1)) {
- new_lengths[i] = orig_lengths[i - 1] * length_factor;
- }
-
- Array<int> indices(positions.size() - 1);
- Array<float> factors(positions.size() - 1);
- length_parameterize::create_samples_from_sorted_lengths(
- orig_lengths, new_lengths, false, indices, factors);
-
- Array<float3> new_positions(positions.size() - 1);
- length_parameterize::linear_interpolation<float3>(positions, indices, factors, new_positions);
- positions.drop_back(1).copy_from(new_positions);
- positions.last() = new_last_position;
- }
};
void SnakeHookOperation::on_stroke_extended(const bContext &C,
const StrokeExtension &stroke_extension)
{
- SnakeHookOperatorExecutor executor;
+ SnakeHookOperatorExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 861da185975..c5ebcf870a3 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -38,6 +38,7 @@
#include "IMB_imbuf_types.h"
+#include "ED_image.h"
#include "ED_view3d.h"
#include "DEG_depsgraph.h"
@@ -1358,7 +1359,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon
ViewContext *vc = &pcontext->vc;
SculptCursorGeometryInfo gi;
- const float mouse[2] = {
+ const float mval_fl[2] = {
pcontext->x - pcontext->region->winrct.xmin,
pcontext->y - pcontext->region->winrct.ymin,
};
@@ -1368,7 +1369,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon
pcontext->prev_active_vertex_index = ss->active_vertex_index;
if (!ups->stroke_active) {
pcontext->is_cursor_over_mesh = SCULPT_cursor_geometry_info_update(
- C, &gi, mouse, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
+ C, &gi, mval_fl, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
copy_v3_v3(pcontext->location, gi.location);
copy_v3_v3(pcontext->normal, gi.normal);
}
@@ -1932,7 +1933,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* Public API */
-void paint_cursor_start(Paint *p, bool (*poll)(bContext *C))
+void ED_paint_cursor_start(Paint *p, bool (*poll)(bContext *C))
{
if (p && !p->paint_cursor) {
p->paint_cursor = WM_paint_cursor_activate(
diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc
index e726fd3f338..56cd4751881 100644
--- a/source/blender/editors/sculpt_paint/paint_image.cc
+++ b/source/blender/editors/sculpt_paint/paint_image.cc
@@ -287,7 +287,7 @@ static bool image_paint_poll_ex(bContext *C, bool check_tool)
return false;
}
-bool image_paint_poll(bContext *C)
+bool ED_image_tools_paint_poll(bContext *C)
{
return image_paint_poll_ex(C, true);
}
@@ -301,7 +301,7 @@ static bool image_paint_2d_clone_poll(bContext *C)
{
Brush *brush = image_paint_brush(C);
- if (!CTX_wm_region_view3d(C) && image_paint_poll(C)) {
+ if (!CTX_wm_region_view3d(C) && ED_image_tools_paint_poll(C)) {
if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE)) {
if (brush->clone.image) {
return true;
@@ -430,7 +430,7 @@ static void toggle_paint_cursor(Scene *scene, bool enable)
paint_cursor_delete_textures();
}
else if (enable) {
- paint_cursor_start(p, image_paint_poll);
+ ED_paint_cursor_start(p, ED_image_tools_paint_poll);
}
}
@@ -455,7 +455,7 @@ void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
if (enabled) {
BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT);
- paint_cursor_start(&imapaint->paint, image_paint_poll);
+ ED_paint_cursor_start(&imapaint->paint, ED_image_tools_paint_poll);
}
else {
paint_cursor_delete_textures();
@@ -925,7 +925,7 @@ static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op))
static bool brush_colors_flip_poll(bContext *C)
{
- if (image_paint_poll(C)) {
+ if (ED_image_tools_paint_poll(C)) {
Brush *br = image_paint_brush(C);
if (ELEM(br->imagepaint_tool, PAINT_TOOL_DRAW, PAINT_TOOL_FILL)) {
return true;
@@ -991,7 +991,7 @@ static bool texture_paint_poll(bContext *C)
bool image_texture_paint_poll(bContext *C)
{
- return (texture_paint_poll(C) || image_paint_poll(C));
+ return (texture_paint_poll(C) || ED_image_tools_paint_poll(C));
}
bool facemask_paint_poll(bContext *C)
diff --git a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
index 8ddf1614e41..a671c24c514 100644
--- a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
+++ b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
@@ -34,6 +34,8 @@
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "ED_image.h"
+
#include "paint_intern.h"
namespace blender::ed::sculpt_paint::image::ops::paint {
@@ -316,7 +318,7 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
pop->cursor = WM_paint_cursor_activate(
- SPACE_TYPE_ANY, RGN_TYPE_ANY, image_paint_poll, gradient_draw_line, pop);
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, ED_image_tools_paint_poll, gradient_draw_line, pop);
}
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
@@ -520,7 +522,7 @@ void PAINT_OT_image_paint(wmOperatorType *ot)
ot->invoke = paint_invoke;
ot->modal = paint_modal;
ot->exec = paint_exec;
- ot->poll = image_paint_poll;
+ ot->poll = ED_image_tools_paint_poll;
ot->cancel = paint_cancel;
/* flags */
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index d597705e82e..50480b8aef0 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -3132,7 +3132,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
}
}
- /* Is this UV visible from the view? - raytrace */
+ /* Is this UV visible from the view? - ray-trace */
/* project_paint_PickFace is less complex, use for testing */
// if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == tri_index) {
if ((ps->do_occlude == false) ||
@@ -3222,7 +3222,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
float seam_subsection[4][2];
float fac1, fac2;
- /* Pixelspace UVs. */
+ /* Pixel-space UV's. */
float lt_puv[3][2];
lt_puv[0][0] = lt_uv_pxoffset[0][0] * ibuf->x;
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 187f793eefe..3f4e660b229 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -98,7 +98,6 @@ void *paint_stroke_mode_data(struct PaintStroke *stroke);
float paint_stroke_distance_get(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
bool PAINT_brush_tool_poll(struct bContext *C);
-void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
/**
* Delete overlay cursor textures to preserve memory and invalidate all overlay flags.
*/
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index fb5e76b578f..89bbf2a3c92 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -1584,9 +1584,9 @@ static int sculpt_trim_gesture_box_invoke(bContext *C, wmOperator *op, const wmE
SculptSession *ss = ob->sculpt;
SculptCursorGeometryInfo sgi;
- float mouse[2] = {event->mval[0], event->mval[1]};
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
- ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
if (ss->gesture_initial_hit) {
copy_v3_v3(ss->gesture_initial_location, sgi.location);
copy_v3_v3(ss->gesture_initial_normal, sgi.normal);
@@ -1625,9 +1625,9 @@ static int sculpt_trim_gesture_lasso_invoke(bContext *C, wmOperator *op, const w
SculptSession *ss = ob->sculpt;
SculptCursorGeometryInfo sgi;
- float mouse[2] = {event->mval[0], event->mval[1]};
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
- ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
if (ss->gesture_initial_hit) {
copy_v3_v3(ss->gesture_initial_location, sgi.location);
copy_v3_v3(ss->gesture_initial_normal, sgi.normal);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 926a564184a..0f2b02ed3ab 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -82,11 +82,86 @@ static void BRUSH_OT_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool,
+ enum eContextObjectMode mode)
+{
+ switch (mode) {
+ case CTX_MODE_PAINT_GPENCIL: {
+ if (STREQ(tool->runtime->data_block, "DRAW")) {
+ return GP_BRUSH_PRESET_PENCIL;
+ }
+ else if (STREQ(tool->runtime->data_block, "FILL")) {
+ return GP_BRUSH_PRESET_FILL_AREA;
+ }
+ else if (STREQ(tool->runtime->data_block, "ERASE")) {
+ return GP_BRUSH_PRESET_ERASER_SOFT;
+ }
+ else if (STREQ(tool->runtime->data_block, "TINT")) {
+ return GP_BRUSH_PRESET_TINT;
+ }
+ break;
+ }
+ case CTX_MODE_SCULPT_GPENCIL: {
+ if (STREQ(tool->runtime->data_block, "SMOOTH")) {
+ return GP_BRUSH_PRESET_SMOOTH_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "STRENGTH")) {
+ return GP_BRUSH_PRESET_STRENGTH_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "THICKNESS")) {
+ return GP_BRUSH_PRESET_THICKNESS_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "GRAB")) {
+ return GP_BRUSH_PRESET_GRAB_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "PUSH")) {
+ return GP_BRUSH_PRESET_PUSH_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "TWIST")) {
+ return GP_BRUSH_PRESET_TWIST_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "PINCH")) {
+ return GP_BRUSH_PRESET_PINCH_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "RANDOMIZE")) {
+ return GP_BRUSH_PRESET_RANDOMIZE_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "CLONE")) {
+ return GP_BRUSH_PRESET_CLONE_STROKE;
+ }
+ break;
+ }
+ case CTX_MODE_WEIGHT_GPENCIL: {
+ return GP_BRUSH_PRESET_DRAW_WEIGHT;
+ }
+ case CTX_MODE_VERTEX_GPENCIL: {
+ if (STREQ(tool->runtime->data_block, "DRAW")) {
+ return GP_BRUSH_PRESET_VERTEX_DRAW;
+ }
+ else if (STREQ(tool->runtime->data_block, "BLUR")) {
+ return GP_BRUSH_PRESET_VERTEX_BLUR;
+ }
+ else if (STREQ(tool->runtime->data_block, "AVERAGE")) {
+ return GP_BRUSH_PRESET_VERTEX_AVERAGE;
+ }
+ else if (STREQ(tool->runtime->data_block, "SMEAR")) {
+ return GP_BRUSH_PRESET_VERTEX_SMEAR;
+ }
+ else if (STREQ(tool->runtime->data_block, "REPLACE")) {
+ return GP_BRUSH_PRESET_VERTEX_REPLACE;
+ }
+ break;
+ }
+ default:
+ return GP_BRUSH_PRESET_UNKNOWN;
+ break;
+ }
+ return GP_BRUSH_PRESET_UNKNOWN;
+}
+
static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op))
{
- // int type = RNA_enum_get(op->ptr, "type");
- ToolSettings *ts = CTX_data_tool_settings(C);
- Paint *paint = &ts->gp_paint->paint;
+ Paint *paint = BKE_paint_get_active_from_context(C);
Brush *br = BKE_paint_brush(paint);
Main *bmain = CTX_data_main(C);
@@ -94,15 +169,70 @@ static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op))
br = (Brush *)BKE_id_copy(bmain, &br->id);
}
else {
- br = BKE_brush_add(bmain, "Brush", OB_MODE_PAINT_GPENCIL);
+ /* Get the active tool to determine what type of brush is active. */
+ bScreen *screen = CTX_wm_screen(C);
+ if (screen == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- /* Init grease pencil specific data. */
- BKE_brush_init_gpencil_settings(br);
- }
+ bToolRef *tool = NULL;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ /* Check the current tool is a brush. */
+ bToolRef *tref = area->runtime.tool;
+ if (tref && tref->runtime && tref->runtime->data_block[0]) {
+ tool = tref;
+ break;
+ }
+ }
+ }
- id_us_min(&br->id); /* fake user only */
+ if (tool == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- BKE_paint_brush_set(paint, br);
+ /* Get Brush mode base on context mode. */
+ const enum eContextObjectMode mode = CTX_data_mode_enum(C);
+ eObjectMode obmode = OB_MODE_PAINT_GPENCIL;
+ switch (mode) {
+ case CTX_MODE_PAINT_GPENCIL:
+ obmode = OB_MODE_PAINT_GPENCIL;
+ break;
+ case CTX_MODE_SCULPT_GPENCIL:
+ obmode = OB_MODE_SCULPT_GPENCIL;
+ break;
+ case CTX_MODE_WEIGHT_GPENCIL:
+ obmode = OB_MODE_WEIGHT_GPENCIL;
+ break;
+ case CTX_MODE_VERTEX_GPENCIL:
+ obmode = OB_MODE_VERTEX_GPENCIL;
+ break;
+ default:
+ return OPERATOR_CANCELLED;
+ break;
+ }
+
+ /* Get brush preset using the actual tool. */
+ eGPBrush_Presets preset = gpencil_get_brush_preset_from_tool(tool, mode);
+
+ /* Capitalize Brush name first letter using the tool name. */
+ char name[64];
+ BLI_strncpy(name, tool->runtime->data_block, sizeof(name));
+ BLI_str_tolower_ascii(name, sizeof(name));
+ name[0] = BLI_toupper_ascii(name[0]);
+
+ /* Create the brush and assign default values. */
+ br = BKE_brush_add(bmain, name, obmode);
+ if (br) {
+ BKE_brush_init_gpencil_settings(br);
+ BKE_gpencil_brush_preset_set(bmain, br, preset);
+ }
+ }
+
+ if (br) {
+ id_us_min(&br->id); /* fake user only */
+ BKE_paint_brush_set(paint, br);
+ }
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 210cffcbcda..63e6dc7e965 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -506,7 +506,7 @@ static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert)
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
static void paint_brush_stroke_add_step(
- bContext *C, wmOperator *op, PaintStroke *stroke, const float mouse_in[2], float pressure)
+ bContext *C, wmOperator *op, PaintStroke *stroke, const float mval[2], float pressure)
{
Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
@@ -546,7 +546,7 @@ static void paint_brush_stroke_add_step(
/* copy last position -before- jittering, or space fill code
* will create too many dabs */
- copy_v2_v2(stroke->last_mouse_position, mouse_in);
+ copy_v2_v2(stroke->last_mouse_position, mval);
stroke->last_pressure = pressure;
if (paint_stroke_use_scene_spacing(brush, mode)) {
@@ -562,24 +562,24 @@ static void paint_brush_stroke_add_step(
factor *= pressure;
}
- BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
+ BKE_brush_jitter_pos(scene, brush, mval, mouse_out);
/* XXX: meh, this is round about because
* BKE_brush_jitter_pos isn't written in the best way to
* be reused here */
if (factor != 1.0f) {
- sub_v2_v2v2(delta, mouse_out, mouse_in);
+ sub_v2_v2v2(delta, mouse_out, mval);
mul_v2_fl(delta, factor);
- add_v2_v2v2(mouse_out, mouse_in, delta);
+ add_v2_v2v2(mouse_out, mval, delta);
}
}
else {
- copy_v2_v2(mouse_out, mouse_in);
+ copy_v2_v2(mouse_out, mval);
}
bool is_location_is_set;
ups->last_hit = paint_brush_update(
- C, brush, mode, stroke, mouse_in, mouse_out, pressure, location, &is_location_is_set);
+ C, brush, mode, stroke, mval, mouse_out, pressure, location, &is_location_is_set);
if (is_location_is_set) {
copy_v3_v3(ups->last_location, location);
}
@@ -605,7 +605,7 @@ static void paint_brush_stroke_add_step(
/* Mouse coordinates modified by the stroke type options. */
RNA_float_set_array(&itemptr, "mouse", mouse_out);
/* Original mouse coordinates. */
- RNA_float_set_array(&itemptr, "mouse_event", mouse_in);
+ RNA_float_set_array(&itemptr, "mouse_event", mval);
RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip);
RNA_float_set(&itemptr, "pressure", pressure);
RNA_float_set(&itemptr, "x_tilt", stroke->x_tilt);
@@ -912,8 +912,13 @@ PaintStroke *paint_stroke_new(bContext *C,
rv3d->rflag |= RV3D_PAINTING;
}
- zero_v3(ups->average_stroke_accum);
- ups->average_stroke_counter = 0;
+ /* Preserve location from last stroke while applying and resetting
+ * ups->average_stroke_counter to 1.
+ */
+ if (ups->average_stroke_counter) {
+ mul_v3_fl(ups->average_stroke_accum, 1.0f / (float)ups->average_stroke_counter);
+ ups->average_stroke_counter = 1;
+ }
/* initialize here to avoid initialization conflict with threaded strokes */
BKE_curvemapping_init(br->curve);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc
index fea501f20a9..67b60acc667 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -56,6 +56,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
@@ -139,8 +140,8 @@ struct NormalAnglePrecalc {
/* Returns number of elements. */
static int get_vcol_elements(Mesh *me, size_t *r_elem_size)
{
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
- eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
if (r_elem_size) {
*r_elem_size = layer->type == CD_PROP_COLOR ? sizeof(float) * 4ULL : 4ULL;
@@ -217,7 +218,7 @@ static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev,
MDeformVert *dvert_curr,
int index)
{
- MDeformVert *dv_curr = &dvert_curr[index];
+ const MDeformVert *dv_curr = &dvert_curr[index];
MDeformVert *dv_prev = &dvert_prev[index];
if (dv_prev->flag == 1) {
dv_prev->flag = 0;
@@ -233,7 +234,7 @@ static bool vertex_paint_use_fast_update_check(Object *ob)
const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
if (me_eval != nullptr) {
- Mesh *me = BKE_mesh_from_object(ob);
+ const Mesh *me = BKE_mesh_from_object(ob);
if (me && me->mloopcol) {
return (me->mloopcol == CustomData_get_layer(&me_eval->ldata, CD_PROP_BYTE_COLOR));
}
@@ -252,13 +253,14 @@ static void paint_last_stroke_update(Scene *scene, const float location[3])
bool vertex_paint_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
- if (!(ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly)) {
+ if (!(ob && ob->mode == OB_MODE_VERTEX_PAINT && ((const Mesh *)ob->data)->totpoly)) {
return false;
}
- CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)ob->data);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(
+ static_cast<const ID *>(ob->data));
return layer != nullptr;
}
@@ -291,15 +293,15 @@ bool vertex_paint_poll_ignore_tool(bContext *C)
bool weight_paint_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
- return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totpoly;
+ return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((const Mesh *)ob->data)->totpoly;
}
static bool weight_paint_poll_ex(bContext *C, bool check_tool)
{
- Object *ob = CTX_data_active_object(C);
- ScrArea *area;
+ const Object *ob = CTX_data_active_object(C);
+ const ScrArea *area;
if ((ob != nullptr) && (ob->mode & OB_MODE_WEIGHT_PAINT) &&
(BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != nullptr) &&
@@ -327,7 +329,7 @@ bool weight_paint_poll_ignore_tool(bContext *C)
template<typename Color, typename Traits, eAttrDomain domain>
static Color vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary)
{
- Brush *brush = BKE_paint_brush(&vp->paint);
+ const Brush *brush = BKE_paint_brush_for_read(&vp->paint);
float color[4];
const float *brush_color = secondary ? BKE_brush_secondary_color_get(scene, brush) :
BKE_brush_color_get(scene, brush);
@@ -360,7 +362,7 @@ static Color vpaint_blend(const VPaint *vp,
const Brush *brush = vp->paint.brush;
const IMB_BlendMode blend = (IMB_BlendMode)brush->blend;
- Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha);
+ const Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha);
/* If no accumulate, clip color adding with `color_orig` & `color_test`. */
if (!brush_use_accumulate(vp)) {
@@ -1321,7 +1323,7 @@ static void ed_vwpaintmode_enter_generic(
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->vpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start(paint, vertex_paint_poll);
+ ED_paint_cursor_start(paint, vertex_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
}
else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
@@ -1329,7 +1331,7 @@ static void ed_vwpaintmode_enter_generic(
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->wpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start(paint, weight_paint_poll);
+ ED_paint_cursor_start(paint, weight_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
/* weight paint specific */
@@ -1606,10 +1608,10 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache
/* Initialize the stroke cache invariants from operator properties */
static void vwpaint_update_cache_invariants(
- bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
+ bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mval[2])
{
StrokeCache *cache;
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
ViewContext *vc = paint_stroke_view_context((PaintStroke *)op->customdata);
Object *ob = CTX_data_active_object(C);
@@ -1627,8 +1629,8 @@ static void vwpaint_update_cache_invariants(
}
/* Initial mouse location */
- if (mouse) {
- copy_v2_v2(cache->initial_mouse, mouse);
+ if (mval) {
+ copy_v2_v2(cache->initial_mouse, mval);
}
else {
zero_v2(cache->initial_mouse);
@@ -1651,7 +1653,7 @@ static void vwpaint_update_cache_invariants(
}
copy_v2_v2(cache->mouse, cache->initial_mouse);
- Brush *brush = vp->paint.brush;
+ const Brush *brush = vp->paint.brush;
/* Truly temporary data that isn't stored in properties */
cache->vc = vc;
cache->brush = brush;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 2c6c4c82676..9ce80e4a433 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -148,7 +148,7 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
bool SCULPT_has_loop_colors(const Object *ob)
{
Mesh *me = BKE_object_get_original_mesh(ob);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
return layer && BKE_id_attribute_domain(&me->id, layer) == ATTR_DOMAIN_CORNER;
}
@@ -3535,15 +3535,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
Object *ob = data->ob;
-
- /* These brushes start from original coordinates. */
- const bool use_orco = ELEM(data->brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ELASTIC_DEFORM,
- SCULPT_TOOL_BOUNDARY,
- SCULPT_TOOL_POSE);
+ const bool use_orco = data->use_proxies_orco;
PBVHVertexIter vd;
PBVHProxyNode *proxies;
@@ -3598,17 +3590,49 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
return;
}
+ /* First line is tools that don't support proxies. */
+ const bool use_orco = ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_BOUNDARY,
+ SCULPT_TOOL_POSE);
+
BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
+ .use_proxies_orco = use_orco,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
+ MEM_SAFE_FREE(nodes);
+}
+
+void SCULPT_combine_transform_proxies(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes;
+ int totnode;
+
+ BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .use_proxies_orco = false,
};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
+
MEM_SAFE_FREE(nodes);
}
@@ -4150,7 +4174,7 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache
/* Initialize the stroke cache invariants from operator properties. */
static void sculpt_update_cache_invariants(
- bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
+ bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mval[2])
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
@@ -4180,8 +4204,8 @@ static void sculpt_update_cache_invariants(
sculpt_init_mirror_clipping(ob, ss);
/* Initial mouse location. */
- if (mouse) {
- copy_v2_v2(cache->initial_mouse, mouse);
+ if (mval) {
+ copy_v2_v2(cache->initial_mouse, mval);
}
else {
zero_v2(cache->initial_mouse);
@@ -4319,7 +4343,8 @@ static bool sculpt_needs_delta_from_anchored_origin(Brush *brush)
SCULPT_TOOL_POSE,
SCULPT_TOOL_BOUNDARY,
SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ELASTIC_DEFORM)) {
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_SMEAR)) {
return true;
}
if (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
@@ -4349,7 +4374,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
{
SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
- const float mouse[2] = {
+ const float mval[2] = {
cache->mouse_event[0],
cache->mouse_event[1],
};
@@ -4368,6 +4393,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_POSE,
SCULPT_TOOL_BOUNDARY,
+ SCULPT_TOOL_SMEAR,
SCULPT_TOOL_THUMB) &&
!sculpt_brush_use_topology_rake(ss, brush)) {
return;
@@ -4389,9 +4415,9 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
add_v3_v3(cache->true_location, cache->grab_delta);
}
- /* Compute 3d coordinate at same z from original location + mouse. */
+ /* Compute 3d coordinate at same z from original location + mval. */
mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location);
- ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mouse, grab_location);
+ ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mval, grab_location);
/* Compute delta to move verts by. */
if (!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
@@ -4759,7 +4785,7 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
}
float SCULPT_raycast_init(ViewContext *vc,
- const float mouse[2],
+ const float mval[2],
float ray_start[3],
float ray_end[3],
float ray_normal[3],
@@ -4773,7 +4799,7 @@ float SCULPT_raycast_init(ViewContext *vc,
/* TODO: what if the segment is totally clipped? (return == 0). */
ED_view3d_win_to_segment_clipped(
- vc->depsgraph, vc->region, vc->v3d, mouse, ray_start, ray_end, true);
+ vc->depsgraph, vc->region, vc->v3d, mval, ray_start, ray_end, true);
invert_m4_m4(obimat, ob->obmat);
mul_m4_v3(obimat, ray_start);
@@ -4797,7 +4823,7 @@ float SCULPT_raycast_init(ViewContext *vc,
bool SCULPT_cursor_geometry_info_update(bContext *C,
SculptCursorGeometryInfo *out,
- const float mouse[2],
+ const float mval[2],
bool use_sampled_normal)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -4826,7 +4852,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
}
/* PBVH raycast to get active vertex and face normal. */
- depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ depth = SCULPT_raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original);
SCULPT_stroke_modifiers_check(C, ob, brush);
SculptRaycastData srd = {
@@ -4924,7 +4950,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
return true;
}
-bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
+bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mval[2])
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob;
@@ -4946,7 +4972,7 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
SCULPT_stroke_modifiers_check(C, ob, brush);
- depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ depth = SCULPT_raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original);
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
@@ -5251,14 +5277,10 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
/* Returns whether the mouse/stylus is over the mesh (1)
* or over the background (0). */
-static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), float x, float y)
+static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), const float mval[2])
{
- float mouse[2], co[3];
-
- mouse[0] = x;
- mouse[1] = y;
-
- return SCULPT_stroke_get_location(C, co, mouse);
+ float co_dummy[3];
+ return SCULPT_stroke_get_location(C, co_dummy, mval);
}
bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)
@@ -5279,14 +5301,13 @@ bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)
return false;
}
-static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
+static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mval[2])
{
- /* Don't start the stroke until mouse goes over the mesh.
- * NOTE: mouse will only be null when re-executing the saved stroke.
- * We have exception for 'exec' strokes since they may not set 'mouse',
+ /* Don't start the stroke until `mval` goes over the mesh.
+ * NOTE: `mval` will only be null when re-executing the saved stroke.
+ * We have exception for 'exec' strokes since they may not set `mval`,
* only 'location', see: T52195. */
- if (((op->flag & OP_IS_INVOKE) == 0) || (mouse == NULL) ||
- over_mesh(C, op, mouse[0], mouse[1])) {
+ if (((op->flag & OP_IS_INVOKE) == 0) || (mval == NULL) || over_mesh(C, op, mval)) {
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -5304,10 +5325,10 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
- sculpt_update_cache_invariants(C, sd, ss, op, mouse);
+ sculpt_update_cache_invariants(C, sd, ss, op, mval);
SculptCursorGeometryInfo sgi;
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval, false);
/* Setup the correct undo system. Image painting and sculpting are mutual exclusive.
* Color attributes are part of the sculpting undo system. */
@@ -5499,7 +5520,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
/* For tablet rotation. */
ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
- if (ignore_background_click && !over_mesh(C, op, event->xy[0], event->xy[1])) {
+ if (ignore_background_click && !over_mesh(C, op, (const float[2]){UNPACK2(event->mval)})) {
paint_stroke_free(C, op, op->customdata);
return OPERATOR_PASS_THROUGH;
}
@@ -5759,7 +5780,8 @@ void SCULPT_connected_components_ensure(Object *ob)
{
SculptSession *ss = ob->sculpt;
- /* Topology IDs already initialized. They only need to be recalculated when the PBVH is rebuild.
+ /* Topology IDs already initialized. They only need to be recalculated when the PBVH is
+ * rebuild.
*/
if (ss->vertex_info.connected_component) {
return;
@@ -5823,7 +5845,8 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist)
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
- /* Fake neighbors were already initialized with the same distance, so no need to be recalculated.
+ /* Fake neighbors were already initialized with the same distance, so no need to be
+ * recalculated.
*/
if (ss->fake_neighbors.fake_neighbor_index &&
ss->fake_neighbors.current_max_distance == max_dist) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
index d7a2a18504c..bb101717c9b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.c
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
@@ -9,6 +9,7 @@
#include "BLI_blenlib.h"
#include "BLI_hash.h"
+#include "BLI_index_range.hh"
#include "BLI_math.h"
#include "BLI_task.h"
@@ -43,8 +44,10 @@
#include "bmesh.h"
-#include <math.h>
-#include <stdlib.h>
+#include <cmath>
+#include <cstdlib>
+
+using blender::IndexRange;
AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss)
{
@@ -54,7 +57,7 @@ AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss)
if (ss->filter_cache) {
return ss->filter_cache->automasking;
}
- return NULL;
+ return nullptr;
}
bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd,
@@ -167,18 +170,18 @@ static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
return false;
}
-typedef struct AutomaskFloodFillData {
+struct AutomaskFloodFillData {
float *automask_factor;
float radius;
bool use_radius;
float location[3];
char symm;
-} AutomaskFloodFillData;
+};
static bool automask_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata)
{
- AutomaskFloodFillData *data = userdata;
+ AutomaskFloodFillData *data = (AutomaskFloodFillData *)userdata;
data->automask_factor[to_v] = 1.0f;
data->automask_factor[from_v] = 1.0f;
@@ -194,11 +197,11 @@ static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *au
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
BLI_assert_msg(0, "Topology masking: pmap missing");
- return NULL;
+ return nullptr;
}
const int totvert = SCULPT_vertex_count_get(ss);
- for (int i = 0; i < totvert; i++) {
+ for (int i : IndexRange(totvert)) {
automask_factor[i] = 0.0f;
}
@@ -209,12 +212,13 @@ static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *au
const float radius = ss->cache ? ss->cache->radius : FLT_MAX;
SCULPT_floodfill_add_active(sd, ob, ss, &flood, radius);
- AutomaskFloodFillData fdata = {
- .automask_factor = automask_factor,
- .radius = radius,
- .use_radius = ss->cache && sculpt_automasking_is_constrained_by_radius(brush),
- .symm = SCULPT_mesh_symmetry_xyz_get(ob),
- };
+ AutomaskFloodFillData fdata = {nullptr};
+
+ fdata.automask_factor = automask_factor;
+ fdata.radius = radius;
+ fdata.use_radius = ss->cache && sculpt_automasking_is_constrained_by_radius(brush);
+ fdata.symm = SCULPT_mesh_symmetry_xyz_get(ob);
+
copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss));
SCULPT_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata);
SCULPT_floodfill_free(&flood);
@@ -228,17 +232,17 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a
Brush *brush = BKE_paint_brush(&sd->paint);
if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
- return NULL;
+ return nullptr;
}
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
BLI_assert_msg(0, "Face Sets automasking: pmap missing");
- return NULL;
+ return nullptr;
}
int tot_vert = SCULPT_vertex_count_get(ss);
int active_face_set = SCULPT_active_face_set_get(ss);
- for (int i = 0; i < tot_vert; i++) {
+ for (int i : IndexRange(tot_vert)) {
if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
automask_factor[i] *= 0.0f;
}
@@ -258,13 +262,13 @@ float *SCULPT_boundary_automasking_init(Object *ob,
if (!ss->pmap) {
BLI_assert_msg(0, "Boundary Edges masking: pmap missing");
- return NULL;
+ return nullptr;
}
const int totvert = SCULPT_vertex_count_get(ss);
- int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor");
+ int *edge_distance = (int *)MEM_callocN(sizeof(int) * totvert, "automask_factor");
- for (int i = 0; i < totvert; i++) {
+ for (int i : IndexRange(totvert)) {
edge_distance[i] = EDGE_DISTANCE_INF;
switch (mode) {
case AUTOMASK_INIT_BOUNDARY_EDGES:
@@ -280,8 +284,8 @@ float *SCULPT_boundary_automasking_init(Object *ob,
}
}
- for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) {
- for (int i = 0; i < totvert; i++) {
+ for (int propagation_it : IndexRange(propagation_steps)) {
+ for (int i : IndexRange(totvert)) {
if (edge_distance[i] != EDGE_DISTANCE_INF) {
continue;
}
@@ -295,7 +299,7 @@ float *SCULPT_boundary_automasking_init(Object *ob,
}
}
- for (int i = 0; i < totvert; i++) {
+ for (int i : IndexRange(totvert)) {
if (edge_distance[i] == EDGE_DISTANCE_INF) {
continue;
}
@@ -323,10 +327,11 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object
const int totvert = SCULPT_vertex_count_get(ss);
if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
- return NULL;
+ return nullptr;
}
- AutomaskingCache *automasking = MEM_callocN(sizeof(AutomaskingCache), "automasking cache");
+ AutomaskingCache *automasking = (AutomaskingCache *)MEM_callocN(sizeof(AutomaskingCache),
+ "automasking cache");
SCULPT_automasking_cache_settings_update(automasking, ss, sd, brush);
SCULPT_boundary_info_ensure(ob);
@@ -334,8 +339,8 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object
return automasking;
}
- automasking->factor = MEM_malloc_arrayN(totvert, sizeof(float), "automask_factor");
- for (int i = 0; i < totvert; i++) {
+ automasking->factor = (float *)MEM_malloc_arrayN(totvert, sizeof(float), "automask_factor");
+ for (int i : IndexRange(totvert)) {
automasking->factor[i] = 1.0f;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index dcf90f9e819..9d231f2ccd2 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -1553,11 +1553,9 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
const eSculptClothFilterType filter_type = RNA_enum_get(op->ptr, "type");
/* Update the active vertex */
- float mouse[2];
+ float mval_fl[2] = {UNPACK2(event->mval)};
SculptCursorGeometryInfo sgi;
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
SCULPT_vertex_random_access_ensure(ss);
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index fe69cf6b84f..00503087e39 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -158,7 +158,7 @@ static EnumPropertyItem prop_sculpt_sample_detail_mode_types[] = {
{0, NULL, 0, NULL, NULL},
};
-static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
+static void sample_detail_voxel(bContext *C, ViewContext *vc, const int mval[2])
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = vc->obact;
@@ -169,8 +169,8 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
SCULPT_vertex_random_access_ensure(ss);
/* Update the active vertex. */
- const float mouse[2] = {mx, my};
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ const float mval_fl[2] = {UNPACK2(mval)};
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
/* Average the edge length of the connected edges to the active vertex. */
@@ -201,7 +201,7 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
}
}
-static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region, int mx, int my)
+static void sample_detail_dyntopo(bContext *C, ViewContext *vc, const int mval[2])
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = vc->obact;
@@ -209,9 +209,9 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region,
SCULPT_stroke_modifiers_check(C, ob, brush);
- const float mouse[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
+ const float mval_fl[2] = {UNPACK2(mval)};
float ray_start[3], ray_end[3], ray_normal[3];
- float depth = SCULPT_raycast_init(vc, mouse, ray_start, ray_end, ray_normal, false);
+ float depth = SCULPT_raycast_init(vc, mval_fl, ray_start, ray_end, ray_normal, false);
SculptDetailRaycastData srd;
srd.hit = 0;
@@ -228,14 +228,12 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region,
}
}
-static int sample_detail(bContext *C, int mx, int my, int mode)
+static int sample_detail(bContext *C, const int event_xy[2], int mode)
{
/* Find 3D view to pick from. */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, (const int[2]){mx, my});
- ARegion *region = (area) ?
- BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}) :
- NULL;
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, event_xy);
+ ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, event_xy) : NULL;
if (region == NULL) {
return OPERATOR_CANCELLED;
}
@@ -260,6 +258,11 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
return OPERATOR_CANCELLED;
}
+ const int mval[2] = {
+ event_xy[0] - region->winrct.xmin,
+ event_xy[1] - region->winrct.ymin,
+ };
+
/* Pick sample detail. */
switch (mode) {
case SAMPLE_DETAIL_DYNTOPO:
@@ -268,7 +271,7 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
CTX_wm_region_set(C, prev_region);
return OPERATOR_CANCELLED;
}
- sample_detail_dyntopo(C, &vc, region, mx, my);
+ sample_detail_dyntopo(C, &vc, mval);
break;
case SAMPLE_DETAIL_VOXEL:
if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
@@ -276,7 +279,7 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
CTX_wm_region_set(C, prev_region);
return OPERATOR_CANCELLED;
}
- sample_detail_voxel(C, &vc, mx, my);
+ sample_detail_voxel(C, &vc, mval);
break;
}
@@ -292,7 +295,7 @@ static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
int ss_co[2];
RNA_int_get_array(op->ptr, "location", ss_co);
int mode = RNA_enum_get(op->ptr, "mode");
- return sample_detail(C, ss_co[0], ss_co[1], mode);
+ return sample_detail(C, ss_co, mode);
}
static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
@@ -308,12 +311,10 @@ static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wm
switch (event->type) {
case LEFTMOUSE:
if (event->val == KM_PRESS) {
- const int ss_co[2] = {event->xy[0], event->xy[1]};
-
int mode = RNA_enum_get(op->ptr, "mode");
- sample_detail(C, ss_co[0], ss_co[1], mode);
+ sample_detail(C, event->xy, mode);
- RNA_int_set_array(op->ptr, "location", ss_co);
+ RNA_int_set_array(op->ptr, "location", event->xy);
WM_cursor_modal_restore(CTX_wm_window(C));
ED_workspace_status_text(C, NULL);
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
@@ -657,11 +658,13 @@ static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmE
ED_region_tag_redraw(region);
- if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) {
- cd->sample_mode = true;
- }
- if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) {
- cd->sample_mode = false;
+ if (ELEM(event->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
+ if (event->val == KM_PRESS) {
+ cd->sample_mode = true;
+ }
+ else if (event->val == KM_RELEASE) {
+ cd->sample_mode = false;
+ }
}
/* Sample mode sets the detail size sampling the average edge length under the surface. */
diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index 644f14905ba..fbf988d63e8 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -1450,13 +1450,11 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v
* Updates the #SculptSession cursor data and gets the active vertex
* if the cursor is over the mesh.
*/
-static int sculpt_expand_target_vertex_update_and_get(bContext *C,
- Object *ob,
- const float mouse[2])
+static int sculpt_expand_target_vertex_update_and_get(bContext *C, Object *ob, const float mval[2])
{
SculptSession *ss = ob->sculpt;
SculptCursorGeometryInfo sgi;
- if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
+ if (SCULPT_cursor_geometry_info_update(C, &sgi, mval, false)) {
return SCULPT_active_vertex_get(ss);
}
return SCULPT_EXPAND_VERTEX_NONE;
@@ -1588,16 +1586,16 @@ static void sculpt_expand_find_active_connected_components_from_vert(Object *ob,
static void sculpt_expand_set_initial_components_for_mouse(bContext *C,
Object *ob,
ExpandCache *expand_cache,
- const float mouse[2])
+ const float mval[2])
{
SculptSession *ss = ob->sculpt;
- int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse);
+ int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval);
if (initial_vertex == SCULPT_EXPAND_VERTEX_NONE) {
/* Cursor not over the mesh, for creating valid initial falloffs, fallback to the last active
* vertex in the sculpt session. */
initial_vertex = SCULPT_active_vertex_get(ss);
}
- copy_v2_v2(ss->expand_cache->initial_mouse, mouse);
+ copy_v2_v2(ss->expand_cache->initial_mouse, mval);
expand_cache->initial_active_vertex = initial_vertex;
expand_cache->initial_active_face_set = SCULPT_active_face_set_get(ss);
@@ -1629,14 +1627,14 @@ static void sculpt_expand_move_propagation_origin(bContext *C,
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- const float mouse[2] = {event->mval[0], event->mval[1]};
+ const float mval_fl[2] = {UNPACK2(event->mval)};
float move_disp[2];
- sub_v2_v2v2(move_disp, mouse, expand_cache->initial_mouse_move);
+ sub_v2_v2v2(move_disp, mval_fl, expand_cache->initial_mouse_move);
- float new_mouse[2];
- add_v2_v2v2(new_mouse, move_disp, expand_cache->original_mouse_move);
+ float new_mval[2];
+ add_v2_v2v2(new_mval, move_disp, expand_cache->original_mouse_move);
- sculpt_expand_set_initial_components_for_mouse(C, ob, expand_cache, new_mouse);
+ sculpt_expand_set_initial_components_for_mouse(C, ob, expand_cache, new_mval);
sculpt_expand_falloff_factors_from_vertex_and_symm_create(
expand_cache,
sd,
@@ -1697,8 +1695,8 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
sculpt_expand_ensure_sculptsession_data(ob);
/* Update and get the active vertex (and face) from the cursor. */
- const float mouse[2] = {event->mval[0], event->mval[1]};
- const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse);
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval_fl);
/* Handle the modal keymap state changes. */
ExpandCache *expand_cache = ss->expand_cache;
@@ -1756,7 +1754,7 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
}
expand_cache->move = true;
expand_cache->move_original_falloff_type = expand_cache->falloff_type;
- copy_v2_v2(expand_cache->initial_mouse_move, mouse);
+ copy_v2_v2(expand_cache->initial_mouse_move, mval_fl);
copy_v2_v2(expand_cache->original_mouse_move, expand_cache->initial_mouse);
if (expand_cache->falloff_type == SCULPT_EXPAND_FALLOFF_GEODESIC &&
SCULPT_vertex_count_get(ss) > expand_cache->max_geodesic_move_preview) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index d03c5ecab4d..ce704e619ea 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -949,11 +949,9 @@ static int sculpt_face_sets_change_visibility_invoke(bContext *C,
/* Update the active vertex and Face Set using the cursor position to avoid relying on the paint
* cursor updates. */
SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
return sculpt_face_sets_change_visibility_exec(C, op);
}
@@ -1401,8 +1399,8 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven
/* Update the current active Face Set and Vertex as the operator can be used directly from the
* tool without brush cursor. */
SculptCursorGeometryInfo sgi;
- const float mouse[2] = {event->mval[0], event->mval[1]};
- if (!SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ if (!SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) {
/* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 165e87eb2cd..95c01d24c6d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -339,11 +339,9 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
if (use_automasking) {
/* Update the active face set manually as the paint cursor is not enabled when using the Mesh
* Filter Tool. */
- float mouse[2];
+ float mval_fl[2] = {UNPACK2(event->mval)};
SculptCursorGeometryInfo sgi;
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
}
/* Disable for multires and dyntopo for now */
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index a32b1c3015b..dbed5624adf 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -675,11 +675,9 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
if (use_automasking) {
/* Update the active face set manually as the paint cursor is not enabled when using the Mesh
* Filter Tool. */
- float mouse[2];
+ float mval_fl[2] = {UNPACK2(event->mval)};
SculptCursorGeometryInfo sgi;
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
}
SCULPT_vertex_random_access_ensure(ss);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 5fa115ed629..0693b445fe5 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -247,6 +247,10 @@ typedef struct SculptThreadedTaskData {
float (*mat)[4];
float (*vertCos)[3];
+ /* When true, the displacement stored in the proxies will be aplied to the original coordinates
+ * instead of to the current coordinates. */
+ bool use_proxies_orco;
+
/* X and Z vectors aligned to the stroke direction for operations where perpendicular vectors to
* the stroke direction are needed. */
float (*stroke_xz)[3];
@@ -290,6 +294,10 @@ typedef struct SculptThreadedTaskData {
bool mask_expand_create_face_set;
float transform_mats[8][4][4];
+ float elastic_transform_mat[4][4];
+ float elastic_transform_pivot[3];
+ float elastic_transform_pivot_init[3];
+ float elastic_transform_radius;
/* Boundary brush */
float boundary_deform_strength;
@@ -372,6 +380,14 @@ typedef enum SculptFilterOrientation {
SCULPT_FILTER_ORIENTATION_VIEW = 2,
} SculptFilterOrientation;
+/* Defines how transform tools are going to apply its displacement. */
+typedef enum SculptTransformDisplacementMode {
+ /* Displaces the elements from their original coordinates. */
+ SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL = 0,
+ /* Displaces the elements incrementally from their previous position. */
+ SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL = 1,
+} SculptTransformDisplacementMode;
+
#define SCULPT_CLAY_STABILIZER_LEN 10
typedef struct AutomaskingSettings {
@@ -440,6 +456,8 @@ typedef struct FilterCache {
int active_face_set;
+ SculptTransformDisplacementMode transform_displacement_mode;
+
/* Auto-masking. */
AutomaskingCache *automasking;
@@ -1137,12 +1155,15 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v);
*/
bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v);
+void SCULPT_combine_transform_proxies(Sculpt *sd, Object *ob);
+
/**
* Initialize a point-in-brush test with a given falloff shape.
*
* \param falloff_shape: #PAINT_FALLOFF_SHAPE_SPHERE or #PAINT_FALLOFF_SHAPE_TUBE.
* \return The brush falloff function.
*/
+
SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
SculptBrushTest *test,
char falloff_shape);
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 201e02b8235..4593c6a8b60 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -167,10 +167,8 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
if (RNA_boolean_get(op->ptr, "use_cursor")) {
SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ if (SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) {
/* The cursor is over the mesh, get the update iteration from the updated active vertex. */
mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)];
}
@@ -340,16 +338,14 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
op->customdata = MEM_mallocN(sizeof(float[2]), "initial mouse position");
- copy_v2_v2(op->customdata, mouse);
+ copy_v2_v2(op->customdata, mval_fl);
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index eef344c3d90..f16763be735 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -84,6 +84,7 @@
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "ED_image.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
@@ -349,7 +350,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
- paint_cursor_start(paint, SCULPT_mode_poll_view3d);
+ ED_paint_cursor_start(paint, SCULPT_mode_poll_view3d);
/* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
* As long as no data was added that is not supported. */
@@ -1060,10 +1061,8 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
/* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
* so it needs to be updated here. */
SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
SCULPT_undo_push_begin(ob, "Mask by color");
BKE_sculpt_color_layer_create_if_needed(ob);
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index ac05652b058..fa9f24377da 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -380,6 +380,15 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ float brush_delta[3];
+
+ if (brush->flag & BRUSH_ANCHORED) {
+ copy_v3_v3(brush_delta, ss->cache->grab_delta_symmetry);
+ }
+ else {
+ sub_v3_v3v3(brush_delta, ss->cache->location, ss->cache->last_location);
+ }
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@@ -404,7 +413,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
switch (brush->smear_deform_type) {
case BRUSH_SMEAR_DEFORM_DRAG:
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ copy_v3_v3(current_disp, brush_delta);
break;
case BRUSH_SMEAR_DEFORM_PINCH:
sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
@@ -529,12 +538,10 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
const int totvert = SCULPT_vertex_count_get(ss);
- if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
- if (!ss->cache->prev_colors) {
- ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors");
- for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]);
- }
+ if (!ss->cache->prev_colors) {
+ ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors");
+ for (int i = 0; i < totvert; i++) {
+ SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index b3616254b26..48033f3407e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -16,6 +16,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_kelvinlet.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_object.h"
@@ -33,6 +34,7 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
+#include "ED_view3d.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
@@ -54,6 +56,10 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob)
copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot);
copy_v3_v3(ss->init_pivot_scale, ss->pivot_scale);
+ copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos);
+ copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot);
+ copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale);
+
SCULPT_undo_push_begin(ob, "Transform");
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
@@ -61,10 +67,18 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob)
SCULPT_vertex_random_access_ensure(ss);
SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS);
+
+ if (sd->transform_mode == SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC) {
+ ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL;
+ }
+ else {
+ ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL;
+ }
}
static void sculpt_transform_matrices_init(SculptSession *ss,
const char symm,
+ const SculptTransformDisplacementMode t_mode,
float r_transform_mats[8][4][4])
{
@@ -73,9 +87,18 @@ static void sculpt_transform_matrices_init(SculptSession *ss,
transform_mat[4][4];
float start_pivot_pos[3], start_pivot_rot[4], start_pivot_scale[3];
- copy_v3_v3(start_pivot_pos, ss->init_pivot_pos);
- copy_v4_v4(start_pivot_rot, ss->init_pivot_rot);
- copy_v3_v3(start_pivot_scale, ss->init_pivot_scale);
+ switch (t_mode) {
+ case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL:
+ copy_v3_v3(start_pivot_pos, ss->init_pivot_pos);
+ copy_v4_v4(start_pivot_rot, ss->init_pivot_rot);
+ copy_v3_v3(start_pivot_scale, ss->init_pivot_scale);
+ break;
+ case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL:
+ copy_v3_v3(start_pivot_pos, ss->prev_pivot_pos);
+ copy_v4_v4(start_pivot_rot, ss->prev_pivot_rot);
+ copy_v3_v3(start_pivot_scale, ss->prev_pivot_scale);
+ break;
+ }
for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
ePaintSymmetryAreas v_symm = i;
@@ -134,16 +157,26 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float *start_co;
float transformed_co[3], orig_co[3], disp[3];
float fade = vd.mask ? *vd.mask : 0.0f;
copy_v3_v3(orig_co, orig_data.co);
char symm_area = SCULPT_get_vertex_symm_area(orig_co);
- copy_v3_v3(transformed_co, orig_co);
+ switch (ss->filter_cache->transform_displacement_mode) {
+ case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL:
+ start_co = orig_co;
+ break;
+ case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL:
+ start_co = vd.co;
+ break;
+ }
+
+ copy_v3_v3(transformed_co, start_co);
mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
- sub_v3_v3v3(disp, transformed_co, orig_co);
+ sub_v3_v3v3(disp, transformed_co, start_co);
mul_v3_fl(disp, 1.0f - fade);
- add_v3_v3v3(vd.co, orig_co, disp);
+ add_v3_v3v3(vd.co, start_co, disp);
if (vd.mvert) {
BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
@@ -165,7 +198,8 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob)
.nodes = ss->filter_cache->nodes,
};
- sculpt_transform_matrices_init(ss, symm, data.transform_mats);
+ sculpt_transform_matrices_init(
+ ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats);
/* Regular transform applies all symmetry passes at once as it is split by symmetry areas
* (each vertex can only be transformed once by the transform matrix of its area). */
@@ -175,6 +209,98 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob)
0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
}
+static void sculpt_elastic_transform_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[i])->co;
+
+ SculptOrigVertData orig_data;
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+
+ KelvinletParams params;
+ /* TODO(pablodp606): These parameters can be exposed if needed as transform strength and volume
+ * preservation like in the elastic deform brushes. Setting them to the same default as elastic
+ * deform triscale grab because they work well in most cases. */
+ const float force = 1.0f;
+ const float shear_modulus = 1.0f;
+ const float poisson_ratio = 0.4f;
+ BKE_kelvinlet_init_params(
+ &params, data->elastic_transform_radius, force, shear_modulus, poisson_ratio);
+
+ SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float transformed_co[3], orig_co[3], disp[3];
+ const float fade = vd.mask ? *vd.mask : 0.0f;
+ copy_v3_v3(orig_co, orig_data.co);
+
+ copy_v3_v3(transformed_co, vd.co);
+ mul_m4_v3(data->elastic_transform_mat, transformed_co);
+ sub_v3_v3v3(disp, transformed_co, vd.co);
+
+ float final_disp[3];
+ BKE_kelvinlet_grab_triscale(final_disp, &params, vd.co, data->elastic_transform_pivot, disp);
+ mul_v3_fl(final_disp, 20.0f * (1.0f - fade));
+
+ copy_v3_v3(proxy[vd.i], final_disp);
+
+ if (vd.mvert) {
+ BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_update(node);
+}
+
+static void sculpt_transform_radius_elastic(Sculpt *sd, Object *ob, const float transform_radius)
+{
+ SculptSession *ss = ob->sculpt;
+ BLI_assert(ss->filter_cache->transform_displacement_mode ==
+ SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL);
+
+ const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .elastic_transform_radius = transform_radius,
+ };
+
+ sculpt_transform_matrices_init(
+ ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats);
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode);
+
+ /* Elastic transform needs to apply all transform matrices to all vertices and then combine the
+ * displacement proxies as all vertices are modified by all symmetry passes. */
+ for (ePaintSymmetryFlags symmpass = 0; symmpass <= symm; symmpass++) {
+ if (SCULPT_is_symmetry_iteration_valid(symmpass, symm)) {
+ flip_v3_v3(data.elastic_transform_pivot, ss->pivot_pos, symmpass);
+ flip_v3_v3(data.elastic_transform_pivot_init, ss->init_pivot_pos, symmpass);
+
+ printf(
+ "%.2f %.2f %.2f\n", ss->init_pivot_pos[0], ss->init_pivot_pos[1], ss->init_pivot_pos[2]);
+
+ const int symm_area = SCULPT_get_vertex_symm_area(data.elastic_transform_pivot);
+ copy_m4_m4(data.elastic_transform_mat, data.transform_mats[symm_area]);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, sculpt_elastic_transform_task_cb, &settings);
+ }
+ }
+ SCULPT_combine_transform_proxies(sd, ob);
+}
+
void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -184,7 +310,36 @@ void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob)
SCULPT_vertex_random_access_ensure(ss);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
- sculpt_transform_all_vertices(sd, ob);
+ switch (sd->transform_mode) {
+ case SCULPT_TRANSFORM_MODE_ALL_VERTICES: {
+ sculpt_transform_all_vertices(sd, ob);
+ break;
+ }
+ case SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC: {
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ Scene *scene = CTX_data_scene(C);
+ float transform_radius;
+
+ if (BKE_brush_use_locked_size(scene, brush)) {
+ transform_radius = BKE_brush_unprojected_radius_get(scene, brush);
+ }
+ else {
+ ViewContext vc;
+
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+
+ transform_radius = paint_calc_object_space_radius(
+ &vc, ss->init_pivot_pos, BKE_brush_size_get(scene, brush));
+ }
+
+ sculpt_transform_radius_elastic(sd, ob, transform_radius);
+ break;
+ }
+ }
+
+ copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos);
+ copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot);
+ copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale);
if (ss->deform_modifiers_active || ss->shapekey_active) {
SCULPT_flush_stroke_deform(sd, ob, true);
@@ -267,10 +422,11 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
/* Pivot to ray-cast surface. */
else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
float stroke_location[3];
- float mouse[2];
- mouse[0] = RNA_float_get(op->ptr, "mouse_x");
- mouse[1] = RNA_float_get(op->ptr, "mouse_y");
- if (SCULPT_stroke_get_location(C, stroke_location, mouse)) {
+ const float mval[2] = {
+ RNA_float_get(op->ptr, "mouse_x"),
+ RNA_float_get(op->ptr, "mouse_y"),
+ };
+ if (SCULPT_stroke_get_location(C, stroke_location, mval)) {
copy_v3_v3(ss->pivot_pos, stroke_location);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index f6b24bede61..e82f14b1ca7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1465,7 +1465,7 @@ static bool sculpt_attribute_ref_equals(SculptAttrRef *a, SculptAttrRef *b)
static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr)
{
Mesh *me = BKE_object_get_original_mesh(ob);
- CustomDataLayer *layer;
+ const CustomDataLayer *layer;
if (ob && me && (layer = BKE_id_attributes_active_color_get((ID *)me))) {
attr->domain = BKE_id_attribute_domain((ID *)me, layer);
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 87e88d094d7..0b4eec4a835 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -272,7 +272,7 @@ bool ED_space_clip_get_position(struct SpaceClip *sc,
return true;
}
-bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], float r_col[3])
+bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, const int mval[2], float r_col[3])
{
ImBuf *ibuf;
float fx, fy, co[2];
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index e61c264ca06..f5bf850791a 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -777,7 +777,7 @@ void CLIP_OT_view_zoom_in(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag |= OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_LOCK_BYPASS;
/* properties */
prop = RNA_def_float_vector(ot->srna,
@@ -834,7 +834,7 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag |= OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_LOCK_BYPASS;
/* properties */
prop = RNA_def_float_vector(ot->srna,
@@ -883,7 +883,7 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag |= OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_LOCK_BYPASS;
/* properties */
RNA_def_float(ot->srna,
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index bbfbbd2cc58..28e304bfa74 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -394,8 +394,6 @@ static int select_exec(bContext *C, wmOperator *op)
else if (deselect_all) {
ed_tracking_deselect_all_tracks(tracksbase);
ed_tracking_deselect_all_plane_tracks(plane_tracks_base);
- /* Mask as well if we are in combined mask / track view. */
- ED_mask_deselect_all(C);
}
ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
index e5a4919f548..87595ecdb88 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -407,8 +407,15 @@ std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &dr
std::string basic_tip = is_multiple_assets ? TIP_("Move assets to catalog") :
TIP_("Move asset to catalog");
- return basic_tip + ": " + catalog_item_.get_name() + " (" + catalog_item_.catalog_path().str() +
- ")";
+ basic_tip += ": " + catalog_item_.get_name();
+
+ /* Display the full catalog path, but only if it's not exactly the same as the already shown name
+ * (i.e. not a root level catalog with no parent). */
+ if (catalog_item_.get_name() != catalog_item_.catalog_path().str()) {
+ basic_tip += " (" + catalog_item_.catalog_path().str() + ")";
+ }
+
+ return basic_tip;
}
bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag)
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 1ee6445f4ba..655a7983e2b 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -83,6 +83,7 @@ void FILE_OT_rename(struct wmOperatorType *ot);
void FILE_OT_smoothscroll(struct wmOperatorType *ot);
void FILE_OT_filepath_drop(struct wmOperatorType *ot);
void FILE_OT_start_filter(struct wmOperatorType *ot);
+void FILE_OT_edit_directory_path(struct wmOperatorType *ot);
void FILE_OT_view_selected(struct wmOperatorType *ot);
void file_directory_enter_handle(bContext *C, void *arg_unused, void *arg_but);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 578288ca289..62bdd583bc1 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -2914,9 +2914,9 @@ void FILE_OT_delete(struct wmOperatorType *ot)
static int file_start_filter_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *area = CTX_wm_area(C);
- SpaceFile *sfile = CTX_wm_space_file(C);
- FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ const ScrArea *area = CTX_wm_area(C);
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ const FileSelectParams *params = ED_fileselect_get_active_params(sfile);
ARegion *region_ctx = CTX_wm_region(C);
@@ -2950,6 +2950,46 @@ void FILE_OT_start_filter(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Edit Directory Path Operator
+ * \{ */
+
+static int file_edit_directory_path_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ const ScrArea *area = CTX_wm_area(C);
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ const FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+
+ ARegion *region_ctx = CTX_wm_region(C);
+
+ if (area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
+ CTX_wm_region_set(C, region);
+ if (UI_textbutton_activate_rna(C, region, params, "directory")) {
+ break;
+ }
+ }
+ }
+
+ CTX_wm_region_set(C, region_ctx);
+
+ return OPERATOR_FINISHED;
+}
+
+void FILE_OT_edit_directory_path(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Edit Directory Path";
+ ot->description = "Start editing directory field";
+ ot->idname = "FILE_OT_edit_directory_path";
+
+ /* api callbacks */
+ ot->exec = file_edit_directory_path_exec;
+ ot->poll = ED_operator_file_active;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Macro Operators
* \{ */
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index cfbbc1a1b45..183af0c14f5 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -2803,7 +2803,7 @@ int ED_path_extension_type(const char *path)
return FILE_TYPE_ARCHIVE;
}
if (BLI_path_extension_check_n(
- path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", NULL)) {
+ path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", ".stl", NULL)) {
return FILE_TYPE_OBJECT_IO;
}
if (BLI_path_extension_check_array(path, imb_ext_image)) {
@@ -3075,7 +3075,7 @@ static int filelist_readjob_list_dir(const char *root,
}
target = entry->redirection_path;
#ifdef WIN32
- /* On Windows don't show ".lnk" extension for valid shortcuts. */
+ /* On Windows don't show `.lnk` extension for valid shortcuts. */
BLI_path_extension_replace(entry->relpath, FILE_MAXDIR, "");
#endif
}
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index ce36e3e4e4f..e42e1e98660 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -983,6 +983,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
if (params->display == FILE_IMGDISPLAY) {
const float pad_fac = compact ? 0.15f : 0.3f;
+ /* Matches UI_preview_tile_size_x()/_y() by default. */
layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = pad_fac * UI_UNIT_X;
@@ -1009,6 +1010,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
else if (params->display == FILE_VERTICALDISPLAY) {
int rowcount;
+ /* Matches UI_preview_tile_size_x()/_y() by default. */
layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = 0.4f * UI_UNIT_X;
@@ -1030,6 +1032,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
layout->flag = FILE_LAYOUT_VER;
}
else if (params->display == FILE_HORIZONTALDISPLAY) {
+ /* Matches UI_preview_tile_size_x()/_y() by default. */
layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = 0.4f * UI_UNIT_X;
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 10cde239987..310c688383b 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -890,7 +890,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
continue;
}
- /* Exclude "all my files" as it makes no sense in blender fileselector */
+ /* Exclude "all my files" as it makes no sense in blender file-selector. */
/* Exclude "airdrop" if wlan not active as it would show "" ) */
if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) {
fsmenu_insert_entry(
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 0170361f244..a462476aae0 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -695,6 +695,7 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_smoothscroll);
WM_operatortype_append(FILE_OT_filepath_drop);
WM_operatortype_append(FILE_OT_start_filter);
+ WM_operatortype_append(FILE_OT_edit_directory_path);
WM_operatortype_append(FILE_OT_view_selected);
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index ee168730d22..fa49e996c2a 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -197,6 +197,20 @@ static ImageUser *image_user_from_context(const bContext *C)
return (sima) ? &sima->iuser : NULL;
}
+static ImageUser image_user_from_active_tile(Image *ima)
+{
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+
+ /* Use the file associated with the active tile. Otherwise use the first tile. */
+ if (ima && ima->source == IMA_SRC_TILED) {
+ const ImageTile *active = (ImageTile *)BLI_findlink(&ima->tiles, ima->active_tile_index);
+ iuser.tile = active ? active->tile_number : ((ImageTile *)ima->tiles.first)->tile_number;
+ }
+
+ return iuser;
+}
+
static bool image_from_context_has_data_poll(bContext *C)
{
Image *ima = image_from_context(C);
@@ -214,13 +228,14 @@ static bool image_from_context_has_data_poll(bContext *C)
}
/**
- * Use this when the image buffer is accessed without the image user.
+ * Use this when the image buffer is accessing the active tile without the image user.
*/
-static bool image_from_context_has_data_poll_no_image_user(bContext *C)
+static bool image_from_context_has_data_poll_active_tile(bContext *C)
{
Image *ima = image_from_context(C);
+ ImageUser iuser = image_user_from_active_tile(ima);
- return BKE_image_has_ibuf(ima, NULL);
+ return BKE_image_has_ibuf(ima, &iuser);
}
static bool image_not_packed_poll(bContext *C)
@@ -1446,7 +1461,7 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
image_open_init(C, op);
- /* show multiview save options only if scene has multiviews */
+ /* Show multi-view save options only if scene has multi-views. */
PropertyRNA *prop;
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
@@ -1587,12 +1602,7 @@ static int image_file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *
}
}
else if (ima->source == IMA_SRC_TILED) {
- ImageUser iuser;
- BKE_imageuser_default(&iuser);
-
- /* Use the file associated with the active tile. Otherwise use the first tile. */
- const ImageTile *active = (ImageTile *)BLI_findlink(&ima->tiles, ima->active_tile_index);
- iuser.tile = active ? active->tile_number : ((ImageTile *)ima->tiles.first)->tile_number;
+ ImageUser iuser = image_user_from_active_tile(ima);
BKE_image_user_file_path(&iuser, ima, filepath);
}
@@ -1810,7 +1820,6 @@ static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOp
RNA_boolean_get(op->ptr, "copy"));
opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") &&
RNA_boolean_get(op->ptr, "save_as_render"));
- opts->do_newpath = true;
}
static bool save_image_op(
@@ -1847,6 +1856,8 @@ static ImageSaveData *image_save_as_init(bContext *C, wmOperator *op)
return NULL;
}
+ isd->opts.do_newpath = true;
+
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
RNA_string_set(op->ptr, "filepath", isd->opts.filepath);
}
@@ -2687,7 +2698,8 @@ void IMAGE_OT_new(wmOperatorType *ot)
static int image_flip_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImageUser iuser = image_user_from_active_tile(ima);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -2784,7 +2796,7 @@ void IMAGE_OT_flip(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_flip_exec;
- ot->poll = image_from_context_has_data_poll_no_image_user;
+ ot->poll = image_from_context_has_data_poll_active_tile;
/* properties */
PropertyRNA *prop;
@@ -2807,7 +2819,8 @@ void IMAGE_OT_flip(wmOperatorType *ot)
static int image_invert_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImageUser iuser = image_user_from_active_tile(ima);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -2905,7 +2918,7 @@ void IMAGE_OT_invert(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_invert_exec;
- ot->poll = image_from_context_has_data_poll_no_image_user;
+ ot->poll = image_from_context_has_data_poll_active_tile;
/* properties */
prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert red channel");
@@ -2930,9 +2943,10 @@ void IMAGE_OT_invert(wmOperatorType *ot)
static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Image *ima = image_from_context(C);
+ ImageUser iuser = image_user_from_active_tile(ima);
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
if (!RNA_property_is_set(op->ptr, prop)) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
const int size[2] = {ibuf->x, ibuf->y};
RNA_property_int_set_array(op->ptr, prop, size);
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -2943,7 +2957,8 @@ static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
static int image_scale_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImageUser iuser = image_user_from_active_tile(ima);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -2993,7 +3008,7 @@ void IMAGE_OT_resize(wmOperatorType *ot)
/* api callbacks */
ot->invoke = image_scale_invoke;
ot->exec = image_scale_exec;
- ot->poll = image_from_context_has_data_poll_no_image_user;
+ ot->poll = image_from_context_has_data_poll_active_tile;
/* properties */
RNA_def_int_vector(ot->srna, "size", 2, NULL, 1, INT_MAX, "Size", "", 1, SHRT_MAX);
@@ -3189,7 +3204,7 @@ bool ED_space_image_get_position(SpaceImage *sima,
}
bool ED_space_image_color_sample(
- SpaceImage *sima, ARegion *region, int mval[2], float r_col[3], bool *r_is_data)
+ SpaceImage *sima, ARegion *region, const int mval[2], float r_col[3], bool *r_is_data)
{
if (r_is_data) {
*r_is_data = false;
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index 1fd9fde084b..a7a8bde1115 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -287,7 +287,7 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
}
if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* Force MIP-MAP recreation. */
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 9832fcfdb70..ab8143c5bf5 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -316,6 +316,9 @@ static void image_listener(const wmSpaceTypeListenerParams *params)
ED_area_tag_redraw(area);
break;
case ND_MODE:
+ ED_paint_cursor_start(&params->scene->toolsettings->imapaint.paint,
+ ED_image_tools_paint_poll);
+
if (wmn->subtype == NS_EDITMODE_MESH) {
ED_area_tag_refresh(area);
}
diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index b817ff887ce..29a7eb150a1 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -46,6 +46,7 @@
#include "BKE_pbvh.h"
#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_modifier.h"
#include "DEG_depsgraph_query.h"
@@ -92,15 +93,18 @@ static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *st
}
int totvert, totedge, totface, totloop;
- if (me_eval->runtime.subdiv_ccg != nullptr) {
- const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
+
+ const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
+ const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime.subsurf_runtime_data;
+
+ if (subdiv_ccg != nullptr) {
BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop);
}
- else if (me_eval->runtime.subsurf_resolution != 0) {
- totvert = me_eval->runtime.subsurf_totvert;
- totedge = me_eval->runtime.subsurf_totedge;
- totface = me_eval->runtime.subsurf_totpoly;
- totloop = me_eval->runtime.subsurf_totloop;
+ else if (subsurf_runtime_data && subsurf_runtime_data->resolution != 0) {
+ totvert = subsurf_runtime_data->stats_totvert;
+ totedge = subsurf_runtime_data->stats_totedge;
+ totface = subsurf_runtime_data->stats_totpoly;
+ totloop = subsurf_runtime_data->stats_totloop;
}
else {
totvert = me_eval->totvert;
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 2aa9b347ed7..81520445000 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -1004,7 +1004,7 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op))
NlaStrip *strip;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
- /* No making metastrips in non-local tracks of override data. */
+ /* No making meta-strips in non-local tracks of override data. */
continue;
}
@@ -1078,7 +1078,7 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op))
NlaTrack *nlt = (NlaTrack *)ale->data;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
- /* No removing metastrips from non-local tracks of override data. */
+ /* No removing meta-strips from non-local tracks of override data. */
continue;
}
@@ -1714,7 +1714,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
BKE_nlatrack_add_strip(nlt, sb, is_liboverride);
}
- /* clear (temp) metastrips */
+ /* Clear (temp) meta-strips. */
BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
}
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 7b8413b656a..7003d51b2b6 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -66,6 +66,7 @@
#include "NOD_geometry_nodes_eval_log.hh"
#include "NOD_node_declaration.hh"
+#include "NOD_socket_declarations_geometry.hh"
#include "FN_field.hh"
#include "FN_field_cpp_type.hh"
@@ -871,7 +872,8 @@ static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &v
}
static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log,
- std::stringstream &ss)
+ std::stringstream &ss,
+ const nodes::decl::Geometry *geometry)
{
Span<GeometryComponentType> component_types = value_log.component_types();
if (component_types.is_empty()) {
@@ -938,6 +940,45 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
}
}
}
+
+ /* If the geometry declaration is null, as is the case for input to group output,
+ * or it is an output socket don't show supported types. */
+ if (geometry == nullptr || geometry->in_out() == SOCK_OUT) {
+ return;
+ }
+
+ Span<GeometryComponentType> supported_types = geometry->supported_types();
+ if (supported_types.is_empty()) {
+ ss << ".\n\n" << TIP_("Supported: All Types");
+ return;
+ }
+
+ ss << ".\n\n" << TIP_("Supported: ");
+ for (GeometryComponentType type : supported_types) {
+ switch (type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ ss << TIP_("Mesh");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ ss << TIP_("Point Cloud");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ ss << TIP_("Curve");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ ss << TIP_("Instances");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ ss << TIP_("Volume");
+ break;
+ }
+ }
+ ss << ((type == supported_types.last()) ? "" : ", ");
+ }
}
static std::optional<std::string> create_socket_inspection_string(bContext *C,
@@ -970,7 +1011,10 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
}
else if (const geo_log::GeometryValueLog *geo_value_log =
dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
- create_inspection_string_for_geometry(*geo_value_log, ss);
+ create_inspection_string_for_geometry(
+ *geo_value_log,
+ ss,
+ dynamic_cast<const nodes::decl::Geometry *>(socket.runtime->declaration));
}
return ss.str();
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index ab80a44d636..ffc9befc81c 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -15,6 +15,7 @@
#include "DNA_text_types.h"
#include "DNA_world_types.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -275,6 +276,7 @@ static void compo_startjob(void *cjv,
// XXX BIF_store_spare();
/* 1 is do_previews */
+ BKE_callback_exec_id(cj->bmain, &scene->id, BKE_CB_EVT_COMPOSITE_PRE);
if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, "");
@@ -293,6 +295,22 @@ static void compo_startjob(void *cjv,
ntree->progress = nullptr;
}
+static void compo_canceljob(void *cjv)
+{
+ CompoJob *cj = (CompoJob *)cjv;
+ Main *bmain = cj->bmain;
+ Scene *scene = cj->scene;
+ BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_COMPOSITE_CANCEL);
+}
+
+static void compo_completejob(void *cjv)
+{
+ CompoJob *cj = (CompoJob *)cjv;
+ Main *bmain = cj->bmain;
+ Scene *scene = cj->scene;
+ BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_COMPOSITE_POST);
+}
+
/** \} */
} // namespace blender::ed::space_node
@@ -339,7 +357,13 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
/* setup job */
WM_jobs_customdata_set(wm_job, cj, compo_freejob);
WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_COMPO_RESULT, NC_SCENE | ND_COMPO_RESULT);
- WM_jobs_callbacks(wm_job, compo_startjob, compo_initjob, compo_updatejob, nullptr);
+ WM_jobs_callbacks_ex(wm_job,
+ compo_startjob,
+ compo_initjob,
+ compo_updatejob,
+ nullptr,
+ compo_completejob,
+ compo_canceljob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc
index bd6d3d89706..877e0fc325c 100644
--- a/source/blender/editors/space_outliner/outliner_select.cc
+++ b/source/blender/editors/space_outliner/outliner_select.cc
@@ -1693,7 +1693,7 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
- ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection for activation");
@@ -2028,7 +2028,7 @@ void OUTLINER_OT_select_walk(wmOperatorType *ot)
ot->invoke = outliner_walk_select_invoke;
ot->poll = ED_operator_outliner_active;
- ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
PropertyRNA *prop;
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index bfb4c7251a8..ec19e8d5e5b 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -222,13 +222,33 @@ static void unlink_action_fn(bContext *C,
}
static void unlink_material_fn(bContext *UNUSED(C),
- ReportList *UNUSED(reports),
+ ReportList *reports,
Scene *UNUSED(scene),
TreeElement *te,
TreeStoreElem *tsep,
- TreeStoreElem *UNUSED(tselem),
+ TreeStoreElem *tselem,
void *UNUSED(user_data))
{
+ const bool te_is_material = TSE_IS_REAL_ID(tselem) && (GS(tselem->id->name) == ID_MA);
+
+ if (!te_is_material) {
+ /* Just fail silently. Another element may be selected that is a material, we don't want to
+ * confuse users with an error in that case. */
+ return;
+ }
+
+ if (!tsep || !TSE_IS_REAL_ID(tsep)) {
+ /* Valid case, no parent element of the material or it is not an ID (could be a #TSE_ID_BASE
+ * for example) so there's no data to unlink from. */
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Cannot unlink material '%s'. It's not clear which object or object-data it "
+ "should be unlinked from, there's no object or object-data as parent in the "
+ "Outliner tree",
+ tselem->id->name + 2);
+ return;
+ }
+
Material **matar = nullptr;
int a, totcol = 0;
@@ -1954,7 +1974,7 @@ void OUTLINER_OT_delete(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
/* flags */
- ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
PropertyRNA *prop = RNA_def_boolean(
diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc
index e6098631a68..aa739758ecb 100644
--- a/source/blender/editors/space_outliner/outliner_tree.cc
+++ b/source/blender/editors/space_outliner/outliner_tree.cc
@@ -802,7 +802,8 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
void *idv,
TreeElement *parent,
short type,
- short index)
+ short index,
+ const bool expand)
{
ID *id = reinterpret_cast<ID *>(idv);
@@ -894,10 +895,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->idcode = GS(id->name);
}
- if (te->abstract_element && te->abstract_element->isExpandValid()) {
+ if (expand && te->abstract_element && te->abstract_element->isExpandValid()) {
tree_element_expand(*te->abstract_element, *space_outliner);
}
- else if (type == TSE_SOME_ID) {
+ else if (expand && (type == TSE_SOME_ID)) {
/* ID types not (fully) ported to new design yet. */
if (te->abstract_element->expandPoll(*space_outliner)) {
outliner_add_id_contents(space_outliner, te, tselem, id);
diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
index 38025b58fd2..67798e978ab 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
@@ -34,13 +34,6 @@ TreeDisplayOverrideLibraryHierarchies::TreeDisplayOverrideLibraryHierarchies(
{
}
-/* XXX Remove expanded subtree, we add our own items here. Expanding should probably be
- * optional. */
-static void remove_expanded_children(TreeElement &te)
-{
- outliner_free_tree(&te.subtree);
-}
-
ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData &source_data)
{
ListBase tree = {nullptr};
@@ -114,8 +107,7 @@ ListBase TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main(
});
TreeElement *new_id_te = outliner_add_element(
- &space_outliner_, &new_base_te->subtree, iter_id, new_base_te, TSE_SOME_ID, 0);
- remove_expanded_children(*new_id_te);
+ &space_outliner_, &new_base_te->subtree, iter_id, new_base_te, TSE_SOME_ID, 0, false);
build_hierarchy_for_ID(bmain, *iter_id, *tree_element_cast<TreeElementID>(new_id_te));
}
@@ -193,8 +185,8 @@ static int build_hierarchy_foreach_ID_cb(LibraryIDLinkCallbackData *cb_data)
&id,
&build_data.parent_te->getLegacyElement(),
TSE_SOME_ID,
- 0);
- remove_expanded_children(*new_te);
+ 0,
+ false);
build_data.sibling_ids.add(&id);
BuildHierarchyForeachIDCbData child_build_data{build_data.bmain,
diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
index 80b3365766a..c8869d90eca 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
@@ -271,14 +271,14 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
if (!found) {
/* We add the child in the tree even if it is not in the collection.
- * We deliberately clear its sub-tree though, to make it less prominent. */
+ * We don't expand its sub-tree though, to make it less prominent. */
TreeElement *child_ob_tree_element = outliner_add_element(&outliner_,
&parent_ob_tree_element->subtree,
child,
parent_ob_tree_element,
TSE_SOME_ID,
- 0);
- outliner_free_tree(&child_ob_tree_element->subtree);
+ 0,
+ false);
child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION;
child_ob_tree_elements.append(child_ob_tree_element);
}
diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh
index 0dcd75d340d..1098068d628 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element.hh
@@ -94,13 +94,19 @@ class AbstractTreeElement {
* \note "ID" is not always a real ID.
* \note If child items are only added to the tree if the item is open,
* the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change().
+ *
+ * \param expand: If true, the element may add its own sub-tree. E.g. objects will list their
+ * animation data, object data, constraints, modifiers, ... This often adds visual
+ * noise, and can be expensive to add in big scenes. So prefer setting this to
+ * false.
*/
struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
struct TreeElement *parent,
short type,
- short index);
+ short index,
+ const bool expand = true);
void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner);
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
index 53e7b88c923..871de39b1dd 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -67,21 +67,38 @@ void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
for (auto *override_prop :
ListBaseWrapper<IDOverrideLibraryProperty>(id.override_library->properties)) {
+ int rnaprop_index = 0;
const bool is_rna_path_valid = BKE_lib_override_rna_property_find(
- &idpoin, override_prop, &override_rna_ptr, &override_rna_prop);
- if (is_rna_path_valid && !show_system_overrides &&
- ELEM(override_prop->rna_prop_type, PROP_POINTER, PROP_COLLECTION) &&
- RNA_struct_is_ID(RNA_property_pointer_type(&override_rna_ptr, override_rna_prop))) {
- bool do_continue = true;
- for (auto *override_prop_op :
- ListBaseWrapper<IDOverrideLibraryPropertyOperation>(override_prop->operations)) {
- if ((override_prop_op->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
- do_continue = false;
- break;
+ &idpoin, override_prop, &override_rna_ptr, &override_rna_prop, &rnaprop_index);
+
+ /* Check for conditions where the liboverride property should be considered as a system
+ * override, if needed. */
+ if (is_rna_path_valid && !show_system_overrides) {
+ bool do_skip = true;
+ bool is_system_override = false;
+
+ /* Matching ID pointers are considered as system overrides. */
+ if (ELEM(override_prop->rna_prop_type, PROP_POINTER, PROP_COLLECTION) &&
+ RNA_struct_is_ID(RNA_property_pointer_type(&override_rna_ptr, override_rna_prop))) {
+ for (auto *override_prop_op :
+ ListBaseWrapper<IDOverrideLibraryPropertyOperation>(override_prop->operations)) {
+ if ((override_prop_op->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
+ do_skip = false;
+ break;
+ }
+ else {
+ is_system_override = true;
+ }
}
}
- if (do_continue) {
+ /* Animated/driven properties are considered as system overrides. */
+ if (!is_system_override && !BKE_lib_override_library_property_is_animated(
+ &id, override_prop, override_rna_prop, rnaprop_index)) {
+ do_skip = false;
+ }
+
+ if (do_skip) {
continue;
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.cc b/source/blender/editors/space_outliner/tree/tree_iterator.cc
index 85ff9e6437e..8d2b0b21433 100644
--- a/source/blender/editors/space_outliner/tree/tree_iterator.cc
+++ b/source/blender/editors/space_outliner/tree/tree_iterator.cc
@@ -43,13 +43,14 @@ void all_open(const SpaceOutliner &space_outliner,
{
LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) {
/* Get needed data out in case element gets freed. */
- const bool is_open = TSELEM_OPEN(element->store_elem, &space_outliner);
+ const TreeStoreElem *tselem = TREESTORE(element);
const ListBase subtree = element->subtree;
visitor(element);
- /* Don't access element from now on, it may be freed. */
+ /* Don't access element from now on, it may be freed. Note that the open/collapsed state may
+ * also have been changed in the visitor callback. */
- if (is_open) {
+ if (TSELEM_OPEN(tselem, &space_outliner)) {
all_open(space_outliner, subtree, visitor);
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.hh b/source/blender/editors/space_outliner/tree/tree_iterator.hh
index e3b3c90eaad..de5bcd2c462 100644
--- a/source/blender/editors/space_outliner/tree/tree_iterator.hh
+++ b/source/blender/editors/space_outliner/tree/tree_iterator.hh
@@ -26,7 +26,7 @@ void all(const ListBase &subtree, VisitorFn visitor);
/**
* Preorder (meaning depth-first) traversal of all elements not part of a collapsed sub-tree.
- * Freeing the currently visited element in \a visitor is fine.
+ * Freeing the currently visited element in \a visitor is fine (but not its tree-store element).
*/
void all_open(const SpaceOutliner &, VisitorFn visitor);
void all_open(const SpaceOutliner &, const ListBase &subtree, VisitorFn visitor);
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index ea6d3351eaa..647d13a4d56 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -340,7 +340,7 @@ static void seq_load_apply_generic_options(bContext *C, wmOperator *op, Sequence
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag & SEQ_MARKER_TRANS) !=
0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
SEQ_collection_free(strip_col);
}
@@ -863,7 +863,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
}
SEQ_collection_free(strip_col);
@@ -913,7 +913,7 @@ static bool sequencer_add_movie_single_strip(bContext *C,
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
}
SEQ_collection_free(strip_col);
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 08e42a5b4c4..25701c323b9 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -668,7 +668,10 @@ float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx)
const float maxhandle = (pixelx * SEQ_HANDLE_SIZE) * U.pixelsize;
/* Ensure that handle is not wider, than quarter of strip. */
- return min_ff(maxhandle, ((float)(SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq)) / 4.0f));
+ return min_ff(
+ maxhandle,
+ ((float)(SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq)) /
+ 4.0f));
}
/* Draw a handle, on left or right side of strip. */
@@ -739,7 +742,11 @@ static void draw_seq_handle(View2D *v2d,
BLF_set_default();
/* Calculate if strip is wide enough for showing the labels. */
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d%d", SEQ_time_left_handle_frame_get(seq), SEQ_time_right_handle_frame_get(seq));
+ numstr_len = BLI_snprintf_rlen(numstr,
+ sizeof(numstr),
+ "%d%d",
+ SEQ_time_left_handle_frame_get(seq),
+ SEQ_time_right_handle_frame_get(seq));
float tot_width = BLF_width(fontid, numstr, numstr_len);
if ((x2 - x1) / pixelx > 20 + tot_width) {
@@ -747,12 +754,14 @@ static void draw_seq_handle(View2D *v2d,
float text_margin = 1.2f * handsize_clamped;
if (direction == SEQ_LEFTHANDLE) {
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", SEQ_time_left_handle_frame_get(seq));
+ numstr_len = BLI_snprintf_rlen(
+ numstr, sizeof(numstr), "%d", SEQ_time_left_handle_frame_get(seq));
x1 += text_margin;
y1 += 0.09f;
}
else {
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", SEQ_time_right_handle_frame_get(seq) - 1);
+ numstr_len = BLI_snprintf_rlen(
+ numstr, sizeof(numstr), "%d", SEQ_time_right_handle_frame_get(seq) - 1);
x1 = x2 - (text_margin + pixelx * BLF_width(fontid, numstr, numstr_len));
y1 += 0.09f;
}
@@ -913,7 +922,8 @@ static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq,
char strip_duration_text[16];
if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION) {
- const int strip_duration = SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq);
+ const int strip_duration = SEQ_time_right_handle_frame_get(seq) -
+ SEQ_time_left_handle_frame_get(seq);
SNPRINTF(strip_duration_text, "%d", strip_duration);
if (i != 0) {
text_array[i++] = text_sep;
@@ -1038,7 +1048,11 @@ static void draw_color_strip_band(
immUniformColor4ubv(col);
- immRectf(pos, SEQ_time_left_handle_frame_get(seq), y1, SEQ_time_right_handle_frame_get(seq), text_margin_y);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(seq),
+ y1,
+ SEQ_time_right_handle_frame_get(seq),
+ text_margin_y);
/* 1px line to better separate the color band. */
UI_GetColorPtrShade3ubv(col, col, -20);
@@ -1335,7 +1349,8 @@ static void draw_seq_strip(const bContext *C,
/* Draw strip body. */
x1 = SEQ_time_has_left_still_frames(seq) ? seq->start : SEQ_time_left_handle_frame_get(seq);
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
- x2 = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) : SEQ_time_right_handle_frame_get(seq);
+ x2 = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) :
+ SEQ_time_right_handle_frame_get(seq);
y2 = seq->machine + SEQ_STRIP_OFSTOP;
/* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */
@@ -2597,7 +2612,8 @@ static void draw_cache_view(const bContext *C)
continue;
}
- if (SEQ_time_left_handle_frame_get(seq) > v2d->cur.xmax || SEQ_time_right_handle_frame_get(seq) < v2d->cur.xmin) {
+ if (SEQ_time_left_handle_frame_get(seq) > v2d->cur.xmax ||
+ SEQ_time_right_handle_frame_get(seq) < v2d->cur.xmin) {
continue;
}
@@ -2607,7 +2623,11 @@ static void draw_cache_view(const bContext *C)
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_RAW) {
const float bg_color[4] = {1.0f, 0.1f, 0.02f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
- immRectf(pos, SEQ_time_left_handle_frame_get(seq), stripe_bot, SEQ_time_right_handle_frame_get(seq), stripe_top);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(seq),
+ stripe_bot,
+ SEQ_time_right_handle_frame_get(seq),
+ stripe_top);
}
stripe_bot += stripe_ht + stripe_ofs_y;
@@ -2616,7 +2636,11 @@ static void draw_cache_view(const bContext *C)
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED) {
const float bg_color[4] = {0.1f, 0.1f, 0.75f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
- immRectf(pos, SEQ_time_left_handle_frame_get(seq), stripe_bot, SEQ_time_right_handle_frame_get(seq), stripe_top);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(seq),
+ stripe_bot,
+ SEQ_time_right_handle_frame_get(seq),
+ stripe_top);
}
stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y;
@@ -2625,7 +2649,11 @@ static void draw_cache_view(const bContext *C)
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_COMPOSITE) {
const float bg_color[4] = {1.0f, 0.6f, 0.0f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
- immRectf(pos, SEQ_time_left_handle_frame_get(seq), stripe_bot, SEQ_time_right_handle_frame_get(seq), stripe_top);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(seq),
+ stripe_bot,
+ SEQ_time_right_handle_frame_get(seq),
+ stripe_top);
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 75966d4f070..86c438c616e 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -581,21 +581,13 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
static void sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
{
- /* Iterate in reverse so meta-strips are iterated after their children. */
for (int i = data->num_seq - 1; i >= 0; i--) {
Sequence *seq = data->seq_array[i];
- int endframe;
- /* Offset seq start. */
seq->start = data->ts[i].start + offset;
-
if (data->trim[i]) {
- /* Find the end-frame. */
- endframe = seq->start + seq->len;
-
- /* Compute the sequence offsets. */
- seq->endofs = endframe - SEQ_time_right_handle_frame_get(seq);
- seq->startofs = SEQ_time_left_handle_frame_get(seq) - seq->start;
+ seq->startofs = data->ts[i].startofs - offset;
+ seq->endofs = data->ts[i].endofs + offset;
}
}
@@ -2397,6 +2389,13 @@ static void sequencer_copy_animation(Scene *scene, Sequence *seq)
return;
}
+ /* Add curves for strips inside meta strip. */
+ if (seq->type == SEQ_TYPE_META) {
+ LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) {
+ sequencer_copy_animation(scene, meta_child);
+ }
+ }
+
GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
if (fcurves == NULL) {
return;
@@ -2406,6 +2405,7 @@ static void sequencer_copy_animation(Scene *scene, Sequence *seq)
BLI_addtail(&fcurves_clipboard, BKE_fcurve_copy(fcu));
}
GSET_FOREACH_END();
+
BLI_gset_free(fcurves, NULL);
}
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index a498e5e99cf..dd3aac1eae9 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -302,6 +302,7 @@ static float get_default_column_width(const ColumnValues &values)
switch (values.type()) {
case SPREADSHEET_VALUE_TYPE_BOOL:
return 2.0f;
+ case SPREADSHEET_VALUE_TYPE_INT8:
case SPREADSHEET_VALUE_TYPE_INT32:
return float_width;
case SPREADSHEET_VALUE_TYPE_FLOAT:
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index a29aa1fd026..46e98acb8e8 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -23,6 +23,9 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
if (type.is<bool>()) {
return SPREADSHEET_VALUE_TYPE_BOOL;
}
+ if (type.is<int8_t>()) {
+ return SPREADSHEET_VALUE_TYPE_INT8;
+ }
if (type.is<int>()) {
return SPREADSHEET_VALUE_TYPE_INT32;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index 91ce5c2f6ec..e1ff4b59b14 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -71,6 +71,35 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
}
}
}
+ else if (column_data.type().is<int8_t>()) {
+ const int value = row_filter.value_int;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ column_data.typed<int8_t>(),
+ [&](const int cell) { return cell == value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<int8_t>(),
+ [value](const int cell) { return cell > value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<int8_t>(),
+ [&](const int cell) { return cell < value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
+ }
else if (column_data.type().is<int>()) {
const int value = row_filter.value_int;
switch (row_filter.operation) {
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
index 7c1ac024c12..d42a371c666 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
@@ -63,6 +63,7 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
const eSpreadsheetColumnValueType data_type)
{
switch (data_type) {
+ case SPREADSHEET_VALUE_TYPE_INT8:
case SPREADSHEET_VALUE_TYPE_INT32:
return std::to_string(row_filter.value_int);
case SPREADSHEET_VALUE_TYPE_FLOAT: {
@@ -200,6 +201,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
}
switch (static_cast<eSpreadsheetColumnValueType>(column->data_type)) {
+ case SPREADSHEET_VALUE_TYPE_INT8:
+ uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
+ uiItemR(layout, filter_ptr, "value_int8", 0, IFACE_("Value"), ICON_NONE);
+ break;
case SPREADSHEET_VALUE_TYPE_INT32:
uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
uiItemR(layout, filter_ptr, "value_int", 0, IFACE_("Value"), ICON_NONE);
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 48abe71e35f..9ed2fec96db 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -594,7 +594,7 @@ static char *view3d_mat_drop_tooltip(bContext *C,
{
const char *name = WM_drag_get_item_name(drag);
ARegion *region = CTX_wm_region(C);
- int mval[2] = {
+ const int mval[2] = {
xy[0] - region->winrct.xmin,
xy[1] - region->winrct.ymin,
};
diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c
index 1e54afe46f0..395df42b2cb 100644
--- a/source/blender/editors/space_view3d/view3d_cursor_snap.c
+++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c
@@ -8,7 +8,6 @@
*/
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BLI_listbase.h"
#include "BLI_rect.h"
@@ -53,7 +52,7 @@ typedef struct SnapCursorDataIntern {
struct SnapObjectContext *snap_context_v3d;
const Scene *scene;
- short snap_elem_hidden;
+ eSnapMode snap_elem_hidden;
float prevpoint_stack[3];
@@ -373,7 +372,7 @@ void ED_view3d_cursor_snap_draw_util(RegionView3D *rv3d,
const float normal[3],
const uchar color_line[4],
const uchar color_point[4],
- const short snap_elem_type)
+ const eSnapMode snap_elem_type)
{
if (!loc_prev && !loc_curr) {
return;
@@ -538,9 +537,9 @@ static bool v3d_cursor_is_snap_invert(SnapCursorDataIntern *data_intern, const w
/** \name Update
* \{ */
-static short v3d_cursor_snap_elements(V3DSnapCursorState *snap_state, Scene *scene)
+static eSnapMode v3d_cursor_snap_elements(V3DSnapCursorState *snap_state, Scene *scene)
{
- short snap_elements = snap_state->snap_elem_force;
+ eSnapMode snap_elements = snap_state->snap_elem_force;
if (!snap_elements) {
return scene->toolsettings->snap_mode;
}
@@ -586,7 +585,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
v3d_cursor_snap_context_ensure(scene);
float co[3], no[3], face_nor[3], obmat[4][4], omat[3][3];
- short snap_elem = 0;
+ eSnapMode snap_elem = SCE_SNAP_MODE_NONE;
int snap_elem_index[3] = {-1, -1, -1};
int index = -1;
@@ -595,8 +594,8 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
zero_v3(face_nor);
unit_m3(omat);
- ushort snap_elements = v3d_cursor_snap_elements(state, scene);
- data_intern->snap_elem_hidden = 0;
+ eSnapMode snap_elements = v3d_cursor_snap_elements(state, scene);
+ data_intern->snap_elem_hidden = SCE_SNAP_MODE_NONE;
const bool calc_plane_omat = v3d_cursor_snap_calc_plane();
if (calc_plane_omat && !(snap_elements & SCE_SNAP_MODE_FACE)) {
data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
@@ -612,7 +611,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
if (snap_data->is_snap_invert != !(ts->snap_flag & SCE_SNAP)) {
snap_data->is_enabled = false;
if (!calc_plane_omat) {
- snap_data->snap_elem = 0;
+ snap_data->snap_elem = SCE_SNAP_MODE_NONE;
return;
}
snap_elements = data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
@@ -620,8 +619,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
}
#endif
- if (snap_elements & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (snap_elements & SCE_SNAP_MODE_GEOM) {
float prev_co[3] = {0.0f};
if (state->prevpoint) {
copy_v3_v3(prev_co, state->prevpoint);
@@ -647,7 +645,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
v3d,
snap_elements,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = edit_mode_type,
.use_occlusion_test = use_occlusion_test,
},
@@ -668,7 +666,8 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
if (calc_plane_omat) {
RegionView3D *rv3d = region->regiondata;
- bool orient_surface = snap_elem && (state->plane_orient == V3D_PLACE_ORIENT_SURFACE);
+ bool orient_surface = (snap_elem != SCE_SNAP_MODE_NONE) &&
+ (state->plane_orient == V3D_PLACE_ORIENT_SURFACE);
if (orient_surface) {
copy_m3_m4(omat, obmat);
}
@@ -699,7 +698,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
}
}
- float *co_depth = snap_elem ? co : scene->cursor.location;
+ float *co_depth = (snap_elem != SCE_SNAP_MODE_NONE) ? co : scene->cursor.location;
snap_elem &= ~data_intern->snap_elem_hidden;
if (snap_elem == 0) {
RegionView3D *rv3d = region->regiondata;
@@ -815,7 +814,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
}
const bool draw_plane = state->draw_plane || state->draw_box;
- if (!snap_data->snap_elem && !draw_plane) {
+ if (snap_data->snap_elem == SCE_SNAP_MODE_NONE && !draw_plane) {
return;
}
@@ -833,7 +832,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
v3d_cursor_plane_draw(rv3d, state->plane_axis, matrix);
}
- if (snap_data->snap_elem && (state->draw_point || state->draw_box)) {
+ if (snap_data->snap_elem != SCE_SNAP_MODE_NONE && (state->draw_point || state->draw_box)) {
const float *prev_point = (snap_data->snap_elem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) ?
state->prevpoint :
NULL;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 5b068750d76..b9e4c19295d 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1786,11 +1786,13 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
}
/* Disable other overlays (set all available _HIDE_ flags). */
v3d.overlay.flag |= V3D_OVERLAY_HIDE_CURSOR | V3D_OVERLAY_HIDE_TEXT |
- V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES |
- V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
+ V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
if ((draw_flags & V3D_OFSDRAW_SHOW_OBJECT_EXTRAS) == 0) {
v3d.overlay.flag |= V3D_OVERLAY_HIDE_OBJECT_XTRAS;
}
+ if ((object_type_exclude_viewport_override & (1 << OB_ARMATURE)) != 0) {
+ v3d.overlay.flag |= V3D_OVERLAY_HIDE_BONES;
+ }
v3d.flag |= V3D_HIDE_HELPLINES;
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index a65e9a8d506..5fbdbef676c 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -910,7 +910,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
v3d,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_FINAL,
.use_occlusion_test = true,
},
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index 567022cc9d1..9aae30c4a7e 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -359,7 +359,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C,
v3d,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_CAGE,
},
mval_fl,
@@ -374,7 +374,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C,
depsgraph,
v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_CAGE,
},
ray_start,
@@ -1228,11 +1228,7 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
- RNA_enum_set(gizmo->ptr,
- "snap_elements_force",
- (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
- SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
+ RNA_enum_set(gizmo->ptr, "snap_elements_force", SCE_SNAP_MODE_GEOM);
ED_gizmotypes_snap_3d_flag_set(gizmo, V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE);
WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index 19e064438fc..c4eff01375b 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -412,7 +412,7 @@ static bool walk_floor_distance_get(RegionView3D *rv3d,
walk->depsgraph,
walk->v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
/* Avoid having to convert the edit-mesh to a regular mesh. */
.edit_mode_type = SNAP_GEOM_EDIT,
},
@@ -454,7 +454,7 @@ static bool walk_ray_cast(RegionView3D *rv3d,
walk->depsgraph,
walk->v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
},
ray_start,
ray_normal,
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
index eefc085bdf8..d3b82476d09 100644
--- a/source/blender/editors/space_view3d/view3d_placement.c
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -695,7 +695,7 @@ static bool view3d_interactive_add_calc_snap(bContext *UNUSED(C),
if (r_is_snap_invert) {
*r_is_snap_invert = snap_data->is_snap_invert;
}
- return snap_data->snap_elem != 0;
+ return snap_data->snap_elem != SCE_SNAP_MODE_NONE;
}
/** \} */
@@ -1303,7 +1303,7 @@ static int idp_rna_snap_target_get_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop))
{
V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
- if (!snap_state->snap_elem_force) {
+ if (snap_state->snap_elem_force == SCE_SNAP_MODE_NONE) {
return PLACE_SNAP_TO_DEFAULT;
}
@@ -1316,7 +1316,7 @@ static void idp_rna_snap_target_set_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop),
int value)
{
- short snap_mode = 0; /* #toolsettings->snap_mode. */
+ eSnapMode snap_mode = SCE_SNAP_MODE_NONE; /* #toolsettings->snap_mode. */
const enum ePlace_SnapTo snap_to = value;
if (snap_to == PLACE_SNAP_TO_GEOMETRY) {
snap_mode = SCE_SNAP_MODE_GEOM;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index fc817b43a8b..8eff9ee472f 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -57,8 +57,6 @@
#include "BKE_tracking.h"
#include "BKE_workspace.h"
-#include "DEG_depsgraph.h"
-
#include "WM_api.h"
#include "WM_toolsystem.h"
#include "WM_types.h"
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index a7e2f616c9e..960d9a25ca7 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1425,9 +1425,6 @@ static void drawTransformView(const struct bContext *C, ARegion *region, void *a
/* edge slide, vert slide */
drawEdgeSlide(t);
drawVertSlide(t);
-
- /* Rotation */
- drawDial3d(t);
}
}
@@ -1579,6 +1576,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
/* do we check for parameter? */
if (transformModeUseSnap(t)) {
if (!(t->modifiers & MOD_SNAP) != !(t->tsnap.flag & SCE_SNAP)) {
+ /* Type is #eSnapFlag, but type must match various snap attributes in #ToolSettings. */
char *snap_flag_ptr;
wmMsgParams_RNA msg_key_params = {{0}};
@@ -1786,13 +1784,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1;
t->is_launch_event_drag = event ? (event->val == KM_CLICK_DRAG) : false;
- /* XXX Remove this when wm_operator_call_internal doesn't use window->eventstate
- * (which can have type = 0) */
- /* For gizmo only, so assume LEFTMOUSE. */
- if (t->launch_event == 0) {
- t->launch_event = LEFTMOUSE;
- }
-
unit_m3(t->spacemtx);
initTransInfo(C, t, op, event);
@@ -2061,3 +2052,17 @@ bool checkUseAxisMatrix(TransInfo *t)
return false;
}
+
+bool transform_apply_matrix(TransInfo *t, float mat[4][4])
+{
+ if (t->transform_matrix != NULL) {
+ t->transform_matrix(t, mat);
+ return true;
+ }
+ return false;
+}
+
+void transform_final_value_get(const TransInfo *t, float *value, const int value_num)
+{
+ memcpy(value, t->values_final, sizeof(float) * value_num);
+}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index a3df6a44682..a35942aedec 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -13,6 +13,7 @@
#include "DNA_listBase.h"
#include "DNA_object_enums.h"
+#include "DNA_scene_types.h"
#include "DEG_depsgraph.h"
@@ -153,7 +154,8 @@ typedef enum {
} eTModifier;
/** #TransSnap.status */
-typedef enum {
+typedef enum eTSnap {
+ SNAP_RESETTED = 0,
SNAP_FORCED = 1 << 0,
TARGET_INIT = 1 << 1,
/* Special flag for snap to grid. */
@@ -294,11 +296,14 @@ typedef struct TransSnapPoint {
} TransSnapPoint;
typedef struct TransSnap {
- char flag;
- char mode;
- short target;
- short modePoint;
- short modeSelect;
+ /* Snapping options stored as flags */
+ eSnapFlag flag;
+ /* Method(s) used for snapping source to target */
+ eSnapMode mode;
+ /* Part of source to snap to target */
+ eSnapSourceSelect source_select;
+ /* Determines which objects are possible target */
+ eSnapTargetSelect target_select;
bool align;
bool project;
bool snap_self;
@@ -306,7 +311,7 @@ typedef struct TransSnap {
bool use_backface_culling;
eTSnap status;
/* Snapped Element Type (currently for objects only). */
- char snapElem;
+ eSnapMode snapElem;
/** snapping from this point (in global-space). */
float snapTarget[3];
/** to this point (in global-space). */
@@ -533,6 +538,13 @@ typedef struct TransInfo {
/* Event handler function that determines whether the viewport needs to be redrawn. */
eRedrawFlag (*handleEvent)(struct TransInfo *, const struct wmEvent *);
+ /**
+ * Optional callback to transform a single matrix.
+ *
+ * \note used by the gizmo to transform the matrix used to position it.
+ */
+ void (*transform_matrix)(struct TransInfo *t, float mat_xform[4][4]);
+
/** Constraint Data. */
TransCon con;
@@ -713,6 +725,12 @@ void removeAspectRatio(TransInfo *t, float vec[2]);
*/
struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
+/**
+ * Transform a single matrix using the current `t->final_values`.
+ */
+bool transform_apply_matrix(TransInfo *t, float mat[4][4]);
+void transform_final_value_get(const TransInfo *t, float *value, int value_num);
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -725,7 +743,6 @@ struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
bool gimbal_axis_pose(struct Object *ob, const struct bPoseChannel *pchan, float gmat[3][3]);
bool gimbal_axis_object(struct Object *ob, float gmat[3][3]);
-void drawDial3d(const TransInfo *t);
/** \} */
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 018468dcd03..d9b971c5478 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -1607,10 +1607,9 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
}
}
-void animrecord_check_state(TransInfo *t, struct Object *ob)
+void animrecord_check_state(TransInfo *t, struct ID *id)
{
Scene *scene = t->scene;
- ID *id = &ob->id;
wmTimer *animtimer = t->animtimer;
ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 7080deaec66..037fbe26c77 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -95,7 +95,7 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc);
/**
* For the realtime animation recording feature, handle overlapping data.
*/
-void animrecord_check_state(TransInfo *t, struct Object *ob);
+void animrecord_check_state(TransInfo *t, struct ID *id);
/* transform_convert_action.c */
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 3c1101d48a5..e1b25acb21e 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -1471,7 +1471,7 @@ void recalcData_pose(TransInfo *t)
/* XXX: this currently doesn't work, since flags aren't set yet! */
int targetless_ik = (t->flag & T_AUTOIK);
- animrecord_check_state(t, ob);
+ animrecord_check_state(t, &ob->id);
autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik);
}
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index 54222fbb117..2039daee386 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -24,12 +24,9 @@
#include "UI_view2d.h"
#include "transform.h"
-#include "transform_snap.h"
-
#include "transform_convert.h"
-#include "transform_snap.h"
-
#include "transform_mode.h"
+#include "transform_snap.h"
typedef struct TransDataGraph {
float unit_scale;
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index d2585493679..5879a65eb4b 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -884,7 +884,7 @@ void recalcData_objects(TransInfo *t)
/* TODO: autokeyframe calls need some setting to specify to add samples
* (FPoints) instead of keyframes? */
if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
- animrecord_check_state(t, ob);
+ animrecord_check_state(t, &ob->id);
autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
}
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 68f04aab969..226b0f84f14 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -281,296 +281,21 @@ static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips
}
}
-static bool seq_transform_check_overlap(SeqCollection *transformed_strips)
-{
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if (seq->flag & SEQ_OVERLAP) {
- return true;
- }
- }
- return false;
-}
-
-static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips)
-{
- SeqCollection *collection = SEQ_collection_create(__func__);
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) {
- SEQ_collection_append_strip(seq, collection);
- }
- }
- return collection;
-}
-
-/* Query strips positioned after left edge of transformed strips bound-box. */
-static SeqCollection *query_right_side_strips(ListBase *seqbase, SeqCollection *transformed_strips)
-{
- int minframe = MAXFRAME;
- {
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- minframe = min_ii(minframe, SEQ_time_left_handle_frame_get(seq));
- }
- }
-
- SeqCollection *collection = SEQ_collection_create(__func__);
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if ((seq->flag & SELECT) == 0 && SEQ_time_left_handle_frame_get(seq) >= minframe) {
- SEQ_collection_append_strip(seq, collection);
- }
- }
- return collection;
-}
-
static ListBase *seqbase_active_get(const TransInfo *t)
{
Editing *ed = SEQ_editing_get(t->scene);
return SEQ_active_seqbase_get(ed);
}
-/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal
- * to overlap of transformed strips. */
-static void seq_transform_handle_expand_to_fit(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
-{
- ListBase *markers = &scene->markers;
-
- SeqCollection *right_side_strips = query_right_side_strips(seqbasep, transformed_strips);
-
- /* Temporarily move right side strips beyond timeline boundary. */
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
- seq->machine += MAXSEQ * 2;
- }
-
- /* Shuffle transformed standalone strips. This is because transformed strips can overlap with
- * strips on left side. */
- SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
- SEQ_transform_seqbase_shuffle_time(
- standalone_strips, seqbasep, scene, markers, use_sync_markers);
- SEQ_collection_free(standalone_strips);
-
- /* Move temporarily moved strips back to their original place and tag for shuffling. */
- SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
- seq->machine -= MAXSEQ * 2;
- }
- /* Shuffle again to displace strips on right side. Final effect shuffling is done in
- * SEQ_transform_handle_overlap. */
- SEQ_transform_seqbase_shuffle_time(
- right_side_strips, seqbasep, scene, markers, use_sync_markers);
- SEQ_collection_free(right_side_strips);
-}
-
-static SeqCollection *query_overwrite_targets(ListBase *seqbasep,
- SeqCollection *transformed_strips)
-{
- SeqCollection *collection = SEQ_query_unselected_strips(seqbasep);
-
- Sequence *seq, *seq_transformed;
- SEQ_ITERATOR_FOREACH (seq, collection) {
- bool does_overlap = false;
-
- SEQ_ITERATOR_FOREACH (seq_transformed, transformed_strips) {
- /* Effects of transformed strips can be unselected. These must not be included. */
- if (seq == seq_transformed) {
- SEQ_collection_remove_strip(seq, collection);
- }
- if (SEQ_transform_test_overlap_seq_seq(seq, seq_transformed)) {
- does_overlap = true;
- }
- }
-
- if (!does_overlap) {
- SEQ_collection_remove_strip(seq, collection);
- }
- }
-
- return collection;
-}
-
-typedef enum eOvelapDescrition {
- /* No overlap. */
- STRIP_OVERLAP_NONE,
- /* Overlapping strip covers overlapped completely. */
- STRIP_OVERLAP_IS_FULL,
- /* Overlapping strip is inside overlapped. */
- STRIP_OVERLAP_IS_INSIDE,
- /* Partial overlap between 2 strips. */
- STRIP_OVERLAP_LEFT_SIDE,
- STRIP_OVERLAP_RIGHT_SIDE,
-} eOvelapDescrition;
-
-static eOvelapDescrition overlap_description_get(const Sequence *transformed,
- const Sequence *target)
-{
- if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
- SEQ_time_right_handle_frame_get(transformed) >= SEQ_time_right_handle_frame_get(target)) {
- return STRIP_OVERLAP_IS_FULL;
- }
- if (SEQ_time_left_handle_frame_get(transformed) > SEQ_time_left_handle_frame_get(target) &&
- SEQ_time_right_handle_frame_get(transformed) < SEQ_time_right_handle_frame_get(target)) {
- return STRIP_OVERLAP_IS_INSIDE;
- }
- if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
- SEQ_time_left_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
- return STRIP_OVERLAP_LEFT_SIDE;
- }
- if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_right_handle_frame_get(target) &&
- SEQ_time_right_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
- return STRIP_OVERLAP_RIGHT_SIDE;
- }
- return STRIP_OVERLAP_NONE;
-}
-
-/* Split strip in 3 parts, remove middle part and fit transformed inside. */
-static void seq_transform_handle_overwrite_split(Scene *scene,
- ListBase *seqbasep,
- const Sequence *transformed,
- Sequence *target)
-{
- /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass
- * NULL here. */
- Main *bmain = NULL;
-
- Sequence *split_strip = SEQ_edit_strip_split(bmain,
- scene,
- seqbasep,
- target,
- SEQ_time_left_handle_frame_get(transformed),
- SEQ_SPLIT_SOFT,
- NULL);
- SEQ_edit_strip_split(bmain,
- scene,
- seqbasep,
- split_strip,
- SEQ_time_right_handle_frame_get(transformed),
- SEQ_SPLIT_SOFT,
- NULL);
- SEQ_edit_flag_for_removal(scene, seqbasep, split_strip);
- SEQ_edit_remove_flagged_sequences(scene, seqbasep);
-}
-
-/* Trim strips by adjusting handle position.
- * This is bit more complicated in case overlap happens on effect. */
-static void seq_transform_handle_overwrite_trim(Scene *scene,
- ListBase *seqbasep,
- const Sequence *transformed,
- Sequence *target,
- const eOvelapDescrition overlap)
-{
- SeqCollection *targets = SEQ_query_by_reference(target, seqbasep, SEQ_query_strip_effect_chain);
-
- /* Expand collection by adding all target's children, effects and their children. */
- if ((target->type & SEQ_TYPE_EFFECT) != 0) {
- SEQ_collection_expand(seqbasep, targets, SEQ_query_strip_effect_chain);
- }
-
- /* Trim all non effects, that have influence on effect length which is overlapping. */
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, targets) {
- if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) {
- continue;
- }
- if (overlap == STRIP_OVERLAP_LEFT_SIDE) {
- SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(transformed));
- }
- else {
- BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE);
- SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(transformed));
- }
- }
- SEQ_collection_free(targets);
-}
-
-static void seq_transform_handle_overwrite(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips)
-{
- SeqCollection *targets = query_overwrite_targets(seqbasep, transformed_strips);
- SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
-
- Sequence *target;
- Sequence *transformed;
- SEQ_ITERATOR_FOREACH (target, targets) {
- SEQ_ITERATOR_FOREACH (transformed, transformed_strips) {
- if (transformed->machine != target->machine) {
- continue;
- }
-
- const eOvelapDescrition overlap = overlap_description_get(transformed, target);
-
- if (overlap == STRIP_OVERLAP_IS_FULL) {
- SEQ_collection_append_strip(target, strips_to_delete);
- }
- else if (overlap == STRIP_OVERLAP_IS_INSIDE) {
- seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target);
- }
- else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) {
- seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap);
- }
- }
- }
-
- SEQ_collection_free(targets);
-
- /* Remove covered strips. This must be done in separate loop, because `SEQ_edit_strip_split()`
- * also uses `SEQ_edit_remove_flagged_sequences()`. See T91096. */
- if (SEQ_collection_len(strips_to_delete) > 0) {
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, strips_to_delete) {
- SEQ_edit_flag_for_removal(scene, seqbasep, seq);
- }
- SEQ_edit_remove_flagged_sequences(scene, seqbasep);
- }
- SEQ_collection_free(strips_to_delete);
-}
-
-static void seq_transform_handle_overlap_shuffle(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
-{
- ListBase *markers = &scene->markers;
-
- /* Shuffle non strips with no effects attached. */
- SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
- SEQ_transform_seqbase_shuffle_time(
- standalone_strips, seqbasep, scene, markers, use_sync_markers);
- SEQ_collection_free(standalone_strips);
-}
-
-void SEQ_transform_handle_overlap(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
+static bool seq_transform_check_overlap(SeqCollection *transformed_strips)
{
- const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene);
-
- switch (overlap_mode) {
- case SEQ_OVERLAP_EXPAND:
- seq_transform_handle_expand_to_fit(scene, seqbasep, transformed_strips, use_sync_markers);
- break;
- case SEQ_OVERLAP_OVERWRITE:
- seq_transform_handle_overwrite(scene, seqbasep, transformed_strips);
- break;
- case SEQ_OVERLAP_SHUFFLE:
- seq_transform_handle_overlap_shuffle(scene, seqbasep, transformed_strips, use_sync_markers);
- break;
- }
-
- /* If any effects still overlap, we need to move them up.
- * In some cases other strips can be overlapping still, see T90646. */
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if (SEQ_transform_test_overlap(seqbasep, seq)) {
- SEQ_transform_seqbase_shuffle(seqbasep, seq, scene);
+ if (seq->flag & SEQ_OVERLAP) {
+ return true;
}
- seq->flag &= ~SEQ_OVERLAP;
}
+ return false;
}
static SeqCollection *seq_transform_collection_from_transdata(TransDataContainer *tc)
@@ -607,12 +332,14 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
return;
}
+ TransSeq *ts = tc->custom.type.data;
ListBase *seqbasep = seqbase_active_get(t);
Scene *scene = t->scene;
const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
if (seq_transform_check_overlap(transformed_strips)) {
- SEQ_transform_handle_overlap(scene, seqbasep, transformed_strips, use_sync_markers);
+ SEQ_transform_handle_overlap(
+ scene, seqbasep, transformed_strips, ts->time_dependent_strips, use_sync_markers);
}
SEQ_collection_free(transformed_strips);
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index deae51a1149..76c6632039a 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -154,6 +154,42 @@ void createTransSeqImageData(TransInfo *t)
SEQ_collection_free(strips);
}
+static bool autokeyframe_sequencer_image(bContext *C,
+ Scene *scene,
+ StripTransform *transform,
+ const int tmode)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr);
+
+ const bool around_cursor = scene->toolsettings->sequencer_tool_settings->pivot_point ==
+ V3D_AROUND_CURSOR;
+ const bool do_loc = tmode == TFM_TRANSLATION || around_cursor;
+ const bool do_rot = tmode == TFM_ROTATION;
+ const bool do_scale = tmode == TFM_RESIZE;
+
+ bool changed = false;
+ if (do_rot) {
+ prop = RNA_struct_find_property(&ptr, "rotation");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ }
+ if (do_loc) {
+ prop = RNA_struct_find_property(&ptr, "offset_x");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ prop = RNA_struct_find_property(&ptr, "offset_y");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ }
+ if (do_scale) {
+ prop = RNA_struct_find_property(&ptr, "scale_x");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ prop = RNA_struct_find_property(&ptr, "scale_y");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ }
+
+ return changed;
+}
+
void recalcData_sequencer_image(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
@@ -187,6 +223,7 @@ void recalcData_sequencer_image(TransInfo *t)
copy_v2_v2(translation, tdseq->orig_origin_position);
sub_v2_v2(translation, origin);
mul_v2_v2(translation, mirror);
+ translation[0] *= t->scene->r.yasp / t->scene->r.xasp;
transform->xofs = tdseq->orig_translation[0] - translation[0];
transform->yofs = tdseq->orig_translation[1] - translation[1];
@@ -199,6 +236,12 @@ void recalcData_sequencer_image(TransInfo *t)
if (t->mode == TFM_ROTATION) {
transform->rotation = tdseq->orig_rotation - t->values_final[0];
}
+
+ if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
+ animrecord_check_state(t, &t->scene->id);
+ autokeyframe_sequencer_image(t->context, t->scene, transform, t->mode);
+ }
+
SEQ_relations_invalidate_cache_preprocessed(t->scene, seq);
}
}
@@ -211,9 +254,6 @@ void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *
TransData2D *td2d = NULL;
int i;
- PointerRNA ptr;
- PropertyRNA *prop;
-
for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
TransDataSeq *tdseq = td->extra;
Sequence *seq = tdseq->seq;
@@ -225,24 +265,8 @@ void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *
continue;
}
- Scene *scene = t->scene;
- RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr);
-
- if (t->mode == TFM_ROTATION) {
- prop = RNA_struct_find_property(&ptr, "rotation");
- ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
- }
- if (t->mode == TFM_TRANSLATION) {
- prop = RNA_struct_find_property(&ptr, "offset_x");
- ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
- prop = RNA_struct_find_property(&ptr, "offset_y");
- ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
- }
- if (t->mode == TFM_RESIZE) {
- prop = RNA_struct_find_property(&ptr, "scale_x");
- ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
- prop = RNA_struct_find_property(&ptr, "scale_y");
- ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ if (IS_AUTOKEY_ON(t->scene)) {
+ autokeyframe_sequencer_image(t->context, t->scene, transform, t->mode);
}
}
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 975dbc2e986..e45cac36736 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -358,6 +358,10 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else if (t->spacetype == SPACE_SEQ && region->regiontype == RGN_TYPE_PREVIEW) {
t->options |= CTX_SEQUENCER_IMAGE;
+
+ /* Needed for autokeying transforms in preview during playback. */
+ bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
+ t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
}
setTransformViewAspect(t, t->aspect);
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index aa8dad2b95f..5b749e05052 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -45,7 +45,6 @@
#include "WM_api.h"
#include "WM_message.h"
#include "WM_types.h"
-#include "wm.h"
#include "ED_armature.h"
#include "ED_gizmo_library.h"
@@ -71,6 +70,10 @@
#include "GPU_state.h"
+static void gizmo_refresh_from_matrix(wmGizmoGroup *gzgroup,
+ const float twmat[4][4],
+ const float scale[3]);
+
/* return codes for select, and drawing flags */
#define MAN_TRANS_X (1 << 0)
@@ -155,6 +158,9 @@ typedef struct GizmoGroup {
float viewinv_m3[3][3];
} prev;
+ /* Only for Rotate operator. */
+ float rotation;
+
struct wmGizmo *gizmos[MAN_AXIS_LAST];
} GizmoGroup;
@@ -1269,103 +1275,31 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
WM_msg_subscribe_rna_anon_prop(mbus, EditBone, lock, &msg_sub_value_gz_tag_refresh);
}
-void drawDial3d(const TransInfo *t)
+static void gizmo_3d_dial_matrixbasis_calc(const ARegion *region,
+ float axis[3],
+ float center_global[3],
+ float mval_init[2],
+ float r_mat_basis[4][4])
{
- if (t->mode == TFM_ROTATION && t->spacetype == SPACE_VIEW3D) {
- if (t->options & CTX_PAINT_CURVE) {
- /* Matrices are in the screen space. Not supported. */
- return;
- }
-
- wmGizmo *gz = wm_gizmomap_modal_get(t->region->gizmo_map);
- if (gz == NULL) {
- /* We only draw Dial3d if the operator has been called by a gizmo. */
- return;
- }
-
- float mat_basis[4][4];
- float mat_final[4][4];
- float color[4];
- float increment = 0.0f;
- float line_with = GIZMO_AXIS_LINE_WIDTH + 1.0f;
- float scale = UI_DPI_FAC * U.gizmo_size;
-
- int axis_idx;
-
- const TransCon *tc = &(t->con);
- if (tc->mode & CON_APPLY) {
- if (tc->mode & CON_AXIS0) {
- axis_idx = MAN_AXIS_ROT_X;
- negate_v3_v3(mat_basis[2], t->spacemtx[0]);
- }
- else if (tc->mode & CON_AXIS1) {
- axis_idx = MAN_AXIS_ROT_Y;
- negate_v3_v3(mat_basis[2], t->spacemtx[1]);
- }
- else {
- BLI_assert((tc->mode & CON_AXIS2) != 0);
- axis_idx = MAN_AXIS_ROT_Z;
- negate_v3_v3(mat_basis[2], t->spacemtx[2]);
- }
- }
- else {
- axis_idx = MAN_AXIS_ROT_C;
- copy_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]);
- scale *= 1.2f;
- line_with -= 1.0f;
- }
-
- copy_v3_v3(mat_basis[3], t->center_global);
- mat_basis[2][3] = -dot_v3v3(mat_basis[2], mat_basis[3]);
-
- if (ED_view3d_win_to_3d_on_plane(
- t->region, mat_basis[2], (float[2]){UNPACK2(t->mouse.imval)}, false, mat_basis[1])) {
- sub_v3_v3(mat_basis[1], mat_basis[3]);
- normalize_v3(mat_basis[1]);
- cross_v3_v3v3(mat_basis[0], mat_basis[1], mat_basis[2]);
- }
- else {
- /* The plane and the mouse direction are parallel.
- * Calculate a matrix orthogonal to the axis. */
- ortho_basis_v3v3_v3(mat_basis[0], mat_basis[1], mat_basis[2]);
- }
-
- mat_basis[0][3] = 0.0f;
- mat_basis[1][3] = 0.0f;
- mat_basis[2][3] = 0.0f;
- mat_basis[3][3] = 1.0f;
-
- copy_m4_m4(mat_final, mat_basis);
- scale *= ED_view3d_pixel_size_no_ui_scale(t->region->regiondata, mat_final[3]);
- mul_mat3_m4_fl(mat_final, scale);
+ copy_v3_v3(r_mat_basis[2], axis);
+ copy_v3_v3(r_mat_basis[3], center_global);
+ r_mat_basis[2][3] = -dot_v3v3(axis, center_global);
- if (activeSnap(t) && (!transformModeUseSnap(t) ||
- (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
- increment = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
- }
-
- BLI_assert(axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END);
- gizmo_get_axis_color(axis_idx, NULL, color, color);
-
- GPU_depth_test(GPU_DEPTH_NONE);
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_line_smooth(true);
-
- ED_gizmotypes_dial_3d_draw_util(mat_basis,
- mat_final,
- line_with,
- color,
- false,
- &(struct Dial3dParams){
- .draw_options = ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE,
- .angle_delta = t->values_final[0],
- .angle_increment = increment,
- });
-
- GPU_line_smooth(false);
- GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
- GPU_blend(GPU_BLEND_NONE);
+ if (ED_view3d_win_to_3d_on_plane(region, axis, mval_init, false, r_mat_basis[1])) {
+ sub_v3_v3(r_mat_basis[1], center_global);
+ normalize_v3(r_mat_basis[1]);
+ cross_v3_v3v3(r_mat_basis[0], r_mat_basis[1], r_mat_basis[2]);
+ }
+ else {
+ /* The plane and the mouse direction are parallel.
+ * Calculate a matrix orthogonal to the axis. */
+ ortho_basis_v3v3_v3(r_mat_basis[0], r_mat_basis[1], r_mat_basis[2]);
}
+
+ r_mat_basis[0][3] = 0.0f;
+ r_mat_basis[1][3] = 0.0f;
+ r_mat_basis[2][3] = 0.0f;
+ r_mat_basis[3][3] = 1.0f;
}
/** \} */
@@ -1374,6 +1308,23 @@ void drawDial3d(const TransInfo *t)
/** \name Transform Gizmo
* \{ */
+/** Scale of the two-axis planes. */
+#define MAN_AXIS_SCALE_PLANE_SCALE 0.07f
+/** Offset of the two-axis planes, depends on the gizmos scale. Define to avoid repeating. */
+#define MAN_AXIS_SCALE_PLANE_OFFSET 7.0f
+
+static void rotation_get_fn(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, void *value)
+{
+ const GizmoGroup *ggd = (const GizmoGroup *)gz_prop->custom_func.user_data;
+ *(float *)value = ggd->rotation;
+}
+
+static void rotation_set_fn(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, const void *value)
+{
+ GizmoGroup *ggd = (GizmoGroup *)gz_prop->custom_func.user_data;
+ ggd->rotation = *(const float *)value;
+}
+
static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
{
GizmoGroup *ggd;
@@ -1384,6 +1335,9 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true);
const wmGizmoType *gzt_prim = WM_gizmotype_find("GIZMO_GT_primitive_3d", true);
+ wmGizmoPropertyFnParams params = {
+ .value_get_fn = rotation_get_fn, .value_set_fn = rotation_set_fn, .user_data = ggd};
+
#define GIZMO_NEW_ARROW(v, draw_style) \
{ \
ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); \
@@ -1394,6 +1348,7 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
{ \
ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); \
RNA_enum_set(ggd->gizmos[v]->ptr, "draw_options", draw_options); \
+ WM_gizmo_target_property_def_func(ggd->gizmos[v], "offset", &params); \
} \
((void)0)
#define GIZMO_NEW_PRIM(v, draw_style) \
@@ -1461,18 +1416,104 @@ static int gizmo_modal(bContext *C,
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = region->regiondata;
- struct TransformBounds tbounds;
-
- if (ED_transform_calc_gizmo_stats(C,
- &(struct TransformCalcParams){
- .use_only_center = true,
- },
- &tbounds)) {
- gizmo_prepare_mat(C, rv3d, &tbounds);
- WM_gizmo_set_matrix_location(widget, rv3d->twmat[3]);
+ wmGizmoGroup *gzgroup = widget->parent_gzgroup;
+
+ /* Recalculating the orientation has two problems.
+ * - The matrix calculated based on the transformed selection may not match the matrix
+ * that was set when transform started.
+ * - Inspecting the selection for every update is expensive (for *every* redraw).
+ *
+ * Instead, use #transform_apply_matrix to transform `rv3d->twmat` or the final scale value
+ * when scaling.
+ */
+ if (false) {
+ struct TransformBounds tbounds;
+
+ if (ED_transform_calc_gizmo_stats(C,
+ &(struct TransformCalcParams){
+ .use_only_center = true,
+ },
+ &tbounds)) {
+ gizmo_prepare_mat(C, rv3d, &tbounds);
+ for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
+ }
+ }
}
+ else {
+ GizmoGroup *ggd = gzgroup->customdata;
+
+ short axis_type = 0;
+ MAN_ITER_AXES_BEGIN (axis, axis_idx) {
+ if (axis == widget) {
+ axis_type = gizmo_get_axis_type(axis_idx);
+ break;
+ }
+ }
+ MAN_ITER_AXES_END;
+
+ /* Showing axes which aren't being manipulated doesn't always work so well.
+ *
+ * For rotate: global axis will reset after finish.
+ * Also, gimbal axis isn't properly recalculated while transforming.
+ */
+ if (axis_type == MAN_AXES_ROTATE) {
+ MAN_ITER_AXES_BEGIN (axis, axis_idx) {
+ if (axis == widget) {
+ continue;
+ }
+
+ bool is_plane_dummy;
+ const uint aidx_norm = gizmo_orientation_axis(axis_idx, &is_plane_dummy);
+ /* Always show the axis-aligned handle as it's distracting when it's disabled. */
+ if (aidx_norm == 3) {
+ continue;
+ }
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ }
+ MAN_ITER_AXES_END;
+ }
- ED_region_tag_redraw_editor_overlays(region);
+ wmWindow *win = CTX_wm_window(C);
+ wmOperator *op = NULL;
+ for (int i = 0; i < widget->op_data_len; i++) {
+ wmGizmoOpElem *gzop = WM_gizmo_operator_get(widget, i);
+ op = WM_operator_find_modal_by_type(win, gzop->type);
+ if (op != NULL) {
+ break;
+ }
+ }
+
+ if (op != NULL) {
+ float twmat[4][4];
+ float scale_buf[3];
+ float *scale = NULL;
+ bool update = false;
+ copy_m4_m4(twmat, rv3d->twmat);
+
+ if (axis_type == MAN_AXES_SCALE) {
+ scale = scale_buf;
+ transform_final_value_get(op->customdata, scale, 3);
+ update = true;
+ }
+ else if (axis_type == MAN_AXES_ROTATE) {
+ transform_final_value_get(op->customdata, &ggd->rotation, 1);
+ if (widget != ggd->gizmos[MAN_AXIS_ROT_C]) {
+ ggd->rotation *= -1;
+ }
+ RNA_float_set(
+ widget->ptr, "incremental_angle", transform_snap_increment_get(op->customdata));
+ }
+ else if (transform_apply_matrix(op->customdata, twmat)) {
+ update = true;
+ }
+
+ if (update) {
+ gizmo_refresh_from_matrix(gzgroup, twmat, scale);
+ ED_region_tag_redraw_editor_overlays(region);
+ }
+ }
+ }
return OPERATOR_RUNNING_MODAL;
}
@@ -1524,9 +1565,8 @@ static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup)
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX: {
- const float ofs_ax = 7.0f;
- const float ofs[3] = {ofs_ax, ofs_ax, 0.0f};
- WM_gizmo_set_scale(axis, 0.07f);
+ const float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
+ WM_gizmo_set_scale(axis, MAN_AXIS_SCALE_PLANE_SCALE);
WM_gizmo_set_matrix_offset_location(axis, ofs);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
break;
@@ -1638,46 +1678,23 @@ static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup)
gizmogroup_init_properties_from_twtype(gzgroup);
}
-static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+/**
+ * Set properties for axes.
+ *
+ * \param twmat: The transform matrix (typically #RegionView3D.twmat).
+ * \param scale: Optional scale, to show scale while modally dragging the scale handles.
+ */
+static void gizmo_refresh_from_matrix(wmGizmoGroup *gzgroup,
+ const float twmat[4][4],
+ const float scale[3])
{
GizmoGroup *ggd = gzgroup->customdata;
- Scene *scene = CTX_data_scene(C);
- ScrArea *area = CTX_wm_area(C);
- View3D *v3d = area->spacedata.first;
- ARegion *region = CTX_wm_region(C);
- RegionView3D *rv3d = region->regiondata;
- struct TransformBounds tbounds;
-
- if (ggd->use_twtype_refresh) {
- ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init;
- if (ggd->twtype != ggd->twtype_prev) {
- ggd->twtype_prev = ggd->twtype;
- gizmogroup_init_properties_from_twtype(gzgroup);
- }
- }
-
- const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, ggd->twtype_init);
-
- /* skip, we don't draw anything anyway */
- if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats(C,
- &(struct TransformCalcParams){
- .use_only_center = true,
- .orientation_index = orient_index + 1,
- },
- &tbounds) == 0))) {
- return;
- }
-
- gizmo_prepare_mat(C, rv3d, &tbounds);
-
- /* *** set properties for axes *** */
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
const short axis_type = gizmo_get_axis_type(axis_idx);
const int aidx_norm = gizmo_orientation_axis(axis_idx, NULL);
- WM_gizmo_set_matrix_location(axis, rv3d->twmat[3]);
-
+ WM_gizmo_set_matrix_location(axis, twmat[3]);
switch (axis_idx) {
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
@@ -1690,8 +1707,17 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
gizmo_line_range(ggd->twtype, axis_type, &start_co[2], &len);
- WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
- RNA_float_set(axis->ptr, "length", len);
+ const float *z_axis = twmat[aidx_norm];
+ if (axis_type == MAN_AXES_SCALE) {
+ /* Scale handles are cubes that don't look right when not aligned with other axes.
+ * This is noticeable when the axis is rotated to something besides the global-axis. */
+ const int aidx_norm_y = (aidx_norm + 2) % 3;
+ const float *y_axis = twmat[aidx_norm_y];
+ WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
+ }
+ else {
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, z_axis);
+ }
if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
if (ggd->twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) {
@@ -1699,24 +1725,56 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
start_co[2] += 0.215f;
}
}
+
+ if (scale) {
+ if (axis_type == MAN_AXES_SCALE) {
+ len = ((start_co[2] + len) * scale[aidx_norm]) - start_co[2];
+ }
+ }
+
+ RNA_float_set(axis->ptr, "length", len);
+
WM_gizmo_set_matrix_offset_location(axis, start_co);
+
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
+
break;
}
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
- WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
- break;
+ case MAN_AXIS_ROT_C: {
+ if (axis_idx != MAN_AXIS_ROT_C) {
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, twmat[aidx_norm]);
+ }
+
+ /* Remove #ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE. It is used only for modal drawing. */
+ PropertyRNA *prop = RNA_struct_find_property(axis->ptr, "draw_options");
+ RNA_property_enum_set(axis->ptr,
+ prop,
+ RNA_property_enum_get(axis->ptr, prop) &
+ ~ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE);
+ } break;
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX: {
- const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1];
- const float *z_axis = rv3d->twmat[aidx_norm];
+ const int aidx_norm_x = (aidx_norm + 1) % 3;
+ const int aidx_norm_y = (aidx_norm + 2) % 3;
+ const float *y_axis = twmat[aidx_norm_y];
+ const float *z_axis = twmat[aidx_norm];
WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
+
+ if (axis_type == MAN_AXES_SCALE) {
+ float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
+ if (scale) {
+ ofs[0] *= scale[aidx_norm_x];
+ ofs[1] *= scale[aidx_norm_y];
+ }
+ WM_gizmo_set_matrix_offset_location(axis, ofs);
+ }
break;
}
}
@@ -1733,6 +1791,49 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
}
}
+static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ARegion *region = CTX_wm_region(C);
+
+ {
+ wmGizmo *gz = WM_gizmomap_get_modal(region->gizmo_map);
+ if (gz && gz->parent_gzgroup == gzgroup) {
+ return;
+ }
+ }
+
+ GizmoGroup *ggd = gzgroup->customdata;
+ Scene *scene = CTX_data_scene(C);
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
+ RegionView3D *rv3d = region->regiondata;
+ struct TransformBounds tbounds;
+
+ if (ggd->use_twtype_refresh) {
+ ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init;
+ if (ggd->twtype != ggd->twtype_prev) {
+ ggd->twtype_prev = ggd->twtype;
+ gizmogroup_init_properties_from_twtype(gzgroup);
+ }
+ }
+
+ const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, ggd->twtype_init);
+
+ /* skip, we don't draw anything anyway */
+ if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats(C,
+ &(struct TransformCalcParams){
+ .use_only_center = true,
+ .orientation_index = orient_index + 1,
+ },
+ &tbounds) == 0))) {
+ return;
+ }
+
+ gizmo_prepare_mat(C, rv3d, &tbounds);
+
+ gizmo_refresh_from_matrix(gzgroup, rv3d->twmat, NULL);
+}
+
static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus)
@@ -1756,11 +1857,22 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
copy_m3_m4(viewinv_m3, rv3d->viewinv);
float idot[3];
+ /* Re-calculate hidden unless modal. */
+ bool is_modal = false;
+ {
+ wmGizmo *gz = WM_gizmomap_get_modal(region->gizmo_map);
+ if (gz && gz->parent_gzgroup == gzgroup) {
+ is_modal = true;
+ }
+ }
+
/* when looking through a selected camera, the gizmo can be at the
* exact same position as the view, skip so we don't break selection */
if (ggd->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 5e-7f) {
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
- WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ if (!is_modal) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ }
}
MAN_ITER_AXES_END;
return;
@@ -1771,12 +1883,15 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
const short axis_type = gizmo_get_axis_type(axis_idx);
/* XXX maybe unset _HIDDEN flag on redraw? */
-
if (gizmo_is_axis_visible(rv3d, ggd->twtype, idot, axis_type, axis_idx)) {
- WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
+ if (!is_modal) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
+ }
}
else {
- WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ if (!is_modal) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ }
continue;
}
@@ -1785,13 +1900,15 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
WM_gizmo_set_color(axis, color);
WM_gizmo_set_color_highlight(axis, color_hi);
- switch (axis_idx) {
- case MAN_AXIS_TRANS_C:
- case MAN_AXIS_ROT_C:
- case MAN_AXIS_SCALE_C:
- case MAN_AXIS_ROT_T:
- WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
- break;
+ if (!is_modal) {
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_C:
+ case MAN_AXIS_ROT_C:
+ case MAN_AXIS_SCALE_C:
+ case MAN_AXIS_ROT_T:
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
+ break;
+ }
}
}
MAN_ITER_AXES_END;
@@ -1879,6 +1996,17 @@ static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C,
}
}
}
+ else if (ELEM(axis_idx, MAN_AXIS_ROT_X, MAN_AXIS_ROT_Y, MAN_AXIS_ROT_Z, MAN_AXIS_ROT_C)) {
+ gizmo_3d_dial_matrixbasis_calc(CTX_wm_region(C),
+ gz->matrix_basis[2],
+ gz->matrix_basis[3],
+ (float[2]){UNPACK2(event->mval)},
+ gz->matrix_basis);
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "draw_options");
+ RNA_property_enum_set(
+ gz->ptr, prop, RNA_property_enum_get(gz->ptr, prop) | ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE);
+ RNA_float_set(gz->ptr, "incremental_angle", 0.0f);
+ }
}
static bool WIDGETGROUP_gizmo_poll_generic(View3D *v3d)
@@ -1944,8 +2072,8 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
gzgt->name = "3D View: Transform Gizmo";
gzgt->idname = "VIEW3D_GGT_xform_gizmo";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
- WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index 2fd81486bb6..83f1bd35f81 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -35,7 +35,7 @@
/* Own include. */
#include "transform_mode.h"
-int transform_mode_really_used(bContext *C, int mode)
+eTfmMode transform_mode_really_used(bContext *C, eTfmMode mode)
{
if (mode == TFM_BONESIZE) {
Object *ob = CTX_data_active_object(C);
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index 6930b87090c..eac6734ed88 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -25,7 +25,7 @@ typedef struct TransDataGenericSlideVert {
/* transform_mode.c */
-int transform_mode_really_used(struct bContext *C, int mode);
+eTfmMode transform_mode_really_used(struct bContext *C, eTfmMode mode);
bool transdata_check_local_center(const TransInfo *t, short around);
/**
* Informs if the mode can be switched during modal.
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index 4b86adc4f46..94caaa288e5 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -322,10 +322,30 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
+static void applyRotationMatrix(TransInfo *t, float mat_xform[4][4])
+{
+ float axis_final[3];
+ const float angle_final = t->values_final[0];
+ if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
+ t->con.applyRot(t, NULL, NULL, axis_final, NULL);
+ }
+ else {
+ negate_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
+ }
+
+ float mat3[3][3];
+ float mat4[4][4];
+ axis_angle_normalized_to_mat3(mat3, axis_final, angle_final);
+ copy_m4_m3(mat4, mat3);
+ transform_pivot_set_m4(mat4, t->center_global);
+ mul_m4_m4m4(mat_xform, mat4, mat_xform);
+}
+
void initRotation(TransInfo *t)
{
t->mode = TFM_ROTATION;
t->transform = applyRotation;
+ t->transform_matrix = applyRotationMatrix;
t->tsnap.applySnap = ApplySnapRotation;
t->tsnap.distance = RotationBetween;
diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c
index 2e405449bc3..3716826800b 100644
--- a/source/blender/editors/transform/transform_mode_trackball.c
+++ b/source/blender/editors/transform/transform_mode_trackball.c
@@ -75,19 +75,25 @@ static void transdata_elem_trackball_fn(void *__restrict iter_data_v,
/** \name Transform (Rotation - Trackball)
* \{ */
-static void applyTrackballValue(TransInfo *t,
- const float axis1[3],
- const float axis2[3],
- const float angles[2])
+static void applyTrackballValue_calc_axis_angle(const TransInfo *t,
+ const float phi[2],
+ float r_axis[3],
+ float *r_angle)
+{
+ float axis1[3], axis2[3];
+ normalize_v3_v3(axis1, t->persinv[0]);
+ normalize_v3_v3(axis2, t->persinv[1]);
+
+ mul_v3_v3fl(r_axis, axis1, phi[0]);
+ madd_v3_v3fl(r_axis, axis2, phi[1]);
+ *r_angle = normalize_v3(r_axis);
+}
+
+static void applyTrackballValue(TransInfo *t, const float axis[3], const float angle)
{
float mat_final[3][3];
- float axis[3];
- float angle;
int i;
- mul_v3_v3fl(axis, axis1, angles[0]);
- madd_v3_v3fl(axis, axis2, angles[1]);
- angle = normalize_v3(axis);
axis_angle_normalized_to_mat3(mat_final, axis, angle);
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -120,17 +126,8 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
{
char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
- float axis1[3], axis2[3];
-#if 0 /* UNUSED */
- float mat[3][3], totmat[3][3], smat[3][3];
-#endif
float phi[2];
- copy_v3_v3(axis1, t->persinv[0]);
- copy_v3_v3(axis2, t->persinv[1]);
- normalize_v3(axis1);
- normalize_v3(axis2);
-
copy_v2_v2(phi, t->values);
transform_snap_increment(t, phi);
@@ -165,27 +162,35 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
str + ofs, sizeof(str) - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
}
-#if 0 /* UNUSED */
- axis_angle_normalized_to_mat3(smat, axis1, phi[0]);
- axis_angle_normalized_to_mat3(totmat, axis2, phi[1]);
+ float axis_final[3], angle_final;
+ applyTrackballValue_calc_axis_angle(t, phi, axis_final, &angle_final);
+ applyTrackballValue(t, axis_final, angle_final);
- mul_m3_m3m3(mat, smat, totmat);
+ recalcData(t);
- /* TRANSFORM_FIX_ME */
- // copy_m3_m3(t->mat, mat); /* used in gizmo. */
-#endif
+ ED_area_status_text(t->area, str);
+}
- applyTrackballValue(t, axis1, axis2, phi);
+static void applyTrackballMatrix(TransInfo *t, float mat_xform[4][4])
+{
+ const float phi[2] = {UNPACK2(t->values_final)};
- recalcData(t);
+ float axis_final[3], angle_final;
+ applyTrackballValue_calc_axis_angle(t, phi, axis_final, &angle_final);
- ED_area_status_text(t->area, str);
+ float mat3[3][3], mat4[4][4];
+ axis_angle_normalized_to_mat3(mat3, axis_final, angle_final);
+
+ copy_m4_m3(mat4, mat3);
+ transform_pivot_set_m4(mat4, t->center_global);
+ mul_m4_m4m4(mat_xform, mat4, mat_xform);
}
void initTrackball(TransInfo *t)
{
t->mode = TFM_TRACKBALL;
t->transform = applyTrackball;
+ t->transform_matrix = applyTrackballMatrix;
initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL);
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index c881cde351e..3c6b6ea4117 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -469,7 +469,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
add_v3_v3(global_dir, values_ofs);
}
- t->tsnap.snapElem = 0;
+ t->tsnap.snapElem = SCE_SNAP_MODE_NONE;
applySnapping(t, global_dir);
transform_snap_grid(t, global_dir);
@@ -486,7 +486,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
/* Test for mixed snap with grid. */
float snap_dist_sq = FLT_MAX;
- if (t->tsnap.snapElem != 0) {
+ if (t->tsnap.snapElem != SCE_SNAP_MODE_NONE) {
snap_dist_sq = len_squared_v3v3(t->values, global_dir);
}
if ((snap_dist_sq == FLT_MAX) || (len_squared_v3v3(global_dir, incr_dir) < snap_dist_sq)) {
@@ -518,6 +518,13 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
+static void applyTranslationMatrix(TransInfo *t, float mat_xform[4][4])
+{
+ float delta[3];
+ mul_v3_m3v3(delta, t->spacemtx, t->values_final);
+ add_v3_v3(mat_xform[3], delta);
+}
+
void initTranslation(TransInfo *t)
{
if (t->spacetype == SPACE_ACTION) {
@@ -530,6 +537,7 @@ void initTranslation(TransInfo *t)
}
t->transform = applyTranslation;
+ t->transform_matrix = applyTranslationMatrix;
t->tsnap.applySnap = ApplySnapTranslation;
t->tsnap.distance = transform_snap_distance_len_squared_fn;
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 600f525b428..cd8a2f17554 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -419,7 +419,7 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* XXX, workaround: active needs to be calculated before transforming,
* since we're not reading from 'td->center' in this case. see: T40241 */
- if (t->tsnap.target == SCE_SNAP_TARGET_ACTIVE) {
+ if (t->tsnap.source_select == SCE_SNAP_SOURCE_ACTIVE) {
/* In camera view, tsnap callback is not set
* (see #initSnappingMode() in transform_snap.c, and T40348). */
if (t->tsnap.targetSnap && ((t->tsnap.status & TARGET_INIT) == 0)) {
@@ -648,7 +648,11 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
RNA_def_property_flag(prop, PROP_HIDDEN);
if (flags & P_GEO_SNAP) {
- prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_target_items, 0, "Target", "");
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid
+ * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is
+ * geometry to which moved geometry is snapped). Use "Source snap point" and "Point on
+ * source that will snap to target" for name and description, respectively. */
+ prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_source_items, 0, "Target", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_float_vector(
ot->srna, "snap_point", 3, NULL, -FLT_MAX, FLT_MAX, "Point", "", -FLT_MAX, FLT_MAX);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 769fd28c57b..649217092aa 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -79,8 +79,8 @@ static void TargetSnapActive(TransInfo *t);
/** \name Implementations
* \{ */
-static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select);
-static NodeBorder snapNodeBorder(int snap_node_mode);
+static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select);
+static NodeBorder snapNodeBorder(eSnapMode snap_node_mode);
#if 0
int BIF_snappingSupported(Object *obedit)
@@ -377,56 +377,59 @@ void applyProject(TransInfo *t)
if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) ==
V3D_PROJ_RET_OK) {
- if (ED_transform_snap_object_project_view3d(
- t->tsnap.object_context,
- t->depsgraph,
- t->region,
- t->view,
- SCE_SNAP_MODE_FACE,
- &(const struct SnapObjectParams){
- .snap_select = t->tsnap.modeSelect,
- .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
- .use_occlusion_test = false,
- .use_backface_culling = t->tsnap.use_backface_culling,
- },
- mval_fl,
- NULL,
- 0,
- loc,
- no)) {
+ eSnapMode hit = ED_transform_snap_object_project_view3d(
+ t->tsnap.object_context,
+ t->depsgraph,
+ t->region,
+ t->view,
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_target_select = t->tsnap.target_select,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
+ .use_occlusion_test = false,
+ .use_backface_culling = t->tsnap.use_backface_culling,
+ },
+ mval_fl,
+ NULL,
+ 0,
+ loc,
+ no);
+ if (hit != SCE_SNAP_MODE_FACE) {
+ return;
+ }
+
#if 0
- if (tc->use_local_mat) {
- mul_m4_v3(tc->imat, loc);
- }
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->imat, loc);
+ }
#endif
- sub_v3_v3v3(tvec, loc, iloc);
+ sub_v3_v3v3(tvec, loc, iloc);
- mul_m3_v3(td->smtx, tvec);
+ mul_m3_v3(td->smtx, tvec);
- add_v3_v3(td->loc, tvec);
+ add_v3_v3(td->loc, tvec);
- if (t->tsnap.align && (t->options & CTX_OBJECT)) {
- /* handle alignment as well */
- const float *original_normal;
- float mat[3][3];
+ if (t->tsnap.align && (t->options & CTX_OBJECT)) {
+ /* handle alignment as well */
+ const float *original_normal;
+ float mat[3][3];
- /* In pose mode, we want to align normals with Y axis of bones... */
- original_normal = td->axismtx[2];
+ /* In pose mode, we want to align normals with Y axis of bones... */
+ original_normal = td->axismtx[2];
- rotation_between_vecs_to_mat3(mat, original_normal, no);
+ rotation_between_vecs_to_mat3(mat, original_normal, no);
- transform_data_ext_rotate(td, mat, true);
+ transform_data_ext_rotate(td, mat, true);
- /* TODO: support constraints for rotation too? see #ElementRotation. */
- }
+ /* TODO: support constraints for rotation too? see #ElementRotation. */
}
}
+ }
#if 0 /* TODO: support this? */
- constraintTransLim(t, td);
+ constraintTransLim(t, td);
#endif
- }
}
}
@@ -522,13 +525,13 @@ void applySnapping(TransInfo *t, float *vec)
void resetSnapping(TransInfo *t)
{
- t->tsnap.status = 0;
- t->tsnap.snapElem = 0;
+ t->tsnap.status = SNAP_RESETTED;
+ t->tsnap.snapElem = SCE_SNAP_MODE_NONE;
t->tsnap.align = false;
- t->tsnap.project = 0;
- t->tsnap.mode = 0;
- t->tsnap.modeSelect = 0;
- t->tsnap.target = 0;
+ t->tsnap.project = false;
+ t->tsnap.mode = SCE_SNAP_MODE_NONE;
+ t->tsnap.target_select = SCE_SNAP_TARGET_ALL;
+ t->tsnap.source_select = SCE_SNAP_SOURCE_CLOSEST;
t->tsnap.last = 0;
t->tsnap.snapNormal[0] = 0;
@@ -581,7 +584,7 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
return true;
}
-static char snap_flag_from_spacetype(TransInfo *t)
+static eSnapFlag snap_flag_from_spacetype(TransInfo *t)
{
ToolSettings *ts = t->settings;
if (t->spacetype == SPACE_NODE) {
@@ -596,7 +599,7 @@ static char snap_flag_from_spacetype(TransInfo *t)
return ts->snap_flag;
}
-static short snap_mode_from_spacetype(TransInfo *t)
+static eSnapMode snap_mode_from_spacetype(TransInfo *t)
{
ToolSettings *ts = t->settings;
@@ -605,7 +608,7 @@ static short snap_mode_from_spacetype(TransInfo *t)
}
if (t->spacetype == SPACE_IMAGE) {
- short snap_mode = ts->snap_uv_mode;
+ eSnapMode snap_mode = ts->snap_uv_mode;
if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) &&
(t->mode == TFM_TRANSLATION)) {
snap_mode &= ~SCE_SNAP_MODE_INCREMENT;
@@ -623,7 +626,7 @@ static short snap_mode_from_spacetype(TransInfo *t)
return SCE_SNAP_MODE_INCREMENT;
}
- short snap_mode = ts->snap_mode;
+ eSnapMode snap_mode = ts->snap_mode;
if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) &&
(t->mode == TFM_TRANSLATION)) {
/* Special case in which snap to increments is transformed to snap to grid. */
@@ -641,7 +644,7 @@ static short snap_mode_from_spacetype(TransInfo *t)
return SCE_SNAP_MODE_INCREMENT;
}
-static short snap_select_type_get(TransInfo *t)
+static eSnapTargetSelect snap_select_type_get(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
Base *base_act = view_layer->basact;
@@ -652,7 +655,7 @@ static short snap_select_type_get(TransInfo *t)
* TODO: perform self snap in gpencil_strokes.
*
* When we're moving the origins, allow snapping onto our own geometry (see T69132). */
- return SNAP_ALL;
+ return SCE_SNAP_TARGET_ALL;
}
const int obedit_type = t->obedit_type;
@@ -669,44 +672,44 @@ static short snap_select_type_get(TransInfo *t)
if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
/* Exclude editmesh if using proportional edit */
- return SNAP_NOT_EDITED;
+ return SCE_SNAP_TARGET_NOT_EDITED;
}
if (!t->tsnap.snap_self) {
- return SNAP_NOT_ACTIVE;
+ return SCE_SNAP_TARGET_NOT_ACTIVE;
}
- return SNAP_NOT_SELECTED;
+ return SCE_SNAP_TARGET_NOT_SELECTED;
}
- return SNAP_ALL;
+ return SCE_SNAP_TARGET_ALL;
}
if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) {
/* Particles edit mode. */
- return SNAP_ALL;
+ return SCE_SNAP_TARGET_ALL;
}
/* Object or pose mode. */
- return SNAP_NOT_SELECTED;
+ return SCE_SNAP_TARGET_NOT_SELECTED;
}
if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
- return SNAP_NOT_SELECTED;
+ return SCE_SNAP_TARGET_NOT_SELECTED;
}
- return SNAP_ALL;
+ return SCE_SNAP_TARGET_ALL;
}
static void initSnappingMode(TransInfo *t)
{
ToolSettings *ts = t->settings;
t->tsnap.mode = snap_mode_from_spacetype(t);
- t->tsnap.modeSelect = snap_select_type_get(t);
+ t->tsnap.target_select = snap_select_type_get(t);
if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) {
/* Force project off when not supported. */
- t->tsnap.project = 0;
+ t->tsnap.project = false;
}
if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) {
@@ -752,7 +755,7 @@ void initSnapping(TransInfo *t, wmOperator *op)
{
resetSnapping(t);
t->tsnap.flag = snap_flag_from_spacetype(t);
- short snap_target = t->settings->snap_target;
+ eSnapSourceSelect snap_source = t->settings->snap_target;
/* if snap property exists */
PropertyRNA *prop;
@@ -763,7 +766,10 @@ void initSnapping(TransInfo *t, wmOperator *op)
if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) &&
RNA_property_is_set(op->ptr, prop)) {
- snap_target = RNA_property_enum_get(op->ptr, prop);
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid
+ * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is
+ * geometry to which moved geometry is snapped). */
+ snap_source = RNA_property_enum_get(op->ptr, prop);
}
if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) &&
@@ -803,7 +809,7 @@ void initSnapping(TransInfo *t, wmOperator *op)
t->tsnap.peel = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0);
}
- t->tsnap.target = snap_target;
+ t->tsnap.source_select = snap_source;
initSnappingMode(t);
}
@@ -844,11 +850,11 @@ static void setSnappingCallback(TransInfo *t)
return;
}
- switch (t->tsnap.target) {
- case SCE_SNAP_TARGET_CLOSEST:
+ switch (t->tsnap.source_select) {
+ case SCE_SNAP_SOURCE_CLOSEST:
t->tsnap.targetSnap = TargetSnapClosest;
break;
- case SCE_SNAP_TARGET_CENTER:
+ case SCE_SNAP_SOURCE_CENTER:
if (!ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
t->tsnap.targetSnap = TargetSnapCenter;
break;
@@ -856,10 +862,10 @@ static void setSnappingCallback(TransInfo *t)
/* Can't do TARGET_CENTER with these modes,
* use TARGET_MEDIAN instead. */
ATTR_FALLTHROUGH;
- case SCE_SNAP_TARGET_MEDIAN:
+ case SCE_SNAP_SOURCE_MEDIAN:
t->tsnap.targetSnap = TargetSnapMedian;
break;
- case SCE_SNAP_TARGET_ACTIVE:
+ case SCE_SNAP_SOURCE_ACTIVE:
t->tsnap.targetSnap = TargetSnapActive;
break;
}
@@ -973,7 +979,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
float no[3];
float mval[2];
bool found = false;
- short snap_elem = 0;
+ eSnapMode snap_elem = SCE_SNAP_MODE_NONE;
float dist_px = SNAP_MIN_DISTANCE; /* Use a user defined value here. */
mval[0] = t->mval[0];
@@ -982,7 +988,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) {
zero_v3(no); /* objects won't set this */
snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no);
- found = snap_elem != 0;
+ found = (snap_elem != SCE_SNAP_MODE_NONE);
}
if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) {
found = peelObjectsTransform(
@@ -1003,7 +1009,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
t->tsnap.status &= ~POINT_INIT;
}
- t->tsnap.snapElem = (char)snap_elem;
+ t->tsnap.snapElem = snap_elem;
}
static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
@@ -1020,7 +1026,7 @@ static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
objects,
objects_len,
t->mval,
- t->tsnap.modeSelect == SNAP_NOT_SELECTED,
+ t->tsnap.target_select == SCE_SNAP_TARGET_NOT_SELECTED,
&dist_sq,
t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
@@ -1190,7 +1196,7 @@ static void TargetSnapActive(TransInfo *t)
}
/* No active, default to median */
else {
- t->tsnap.target = SCE_SNAP_TARGET_MEDIAN;
+ t->tsnap.source_select = SCE_SNAP_SOURCE_MEDIAN;
t->tsnap.targetSnap = TargetSnapMedian;
TargetSnapMedian(t);
}
@@ -1302,7 +1308,7 @@ static void TargetSnapClosest(TransInfo *t)
/** \name Snap Objects
* \{ */
-short snapObjectsTransform(
+eSnapMode snapObjectsTransform(
TransInfo *t, const float mval[2], float *dist_px, float r_loc[3], float r_no[3])
{
float *target = (t->tsnap.status & TARGET_INIT) ? t->tsnap.snapTarget : t->center_global;
@@ -1313,7 +1319,7 @@ short snapObjectsTransform(
t->view,
t->tsnap.mode,
&(const struct SnapObjectParams){
- .snap_select = t->tsnap.modeSelect,
+ .snap_target_select = t->tsnap.target_select,
.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
.use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE,
.use_backface_culling = t->tsnap.use_backface_culling,
@@ -1346,7 +1352,7 @@ bool peelObjectsTransform(TransInfo *t,
t->region,
t->view,
&(const struct SnapObjectParams){
- .snap_select = t->tsnap.modeSelect,
+ .snap_target_select = t->tsnap.target_select,
.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
},
mval,
@@ -1414,16 +1420,16 @@ bool peelObjectsTransform(TransInfo *t,
/** \name snap Nodes
* \{ */
-static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select)
+static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select)
{
/* node is use for snapping only if a) snap mode matches and b) node is inside the view */
- return ((snap_select == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) ||
- (snap_select == SNAP_ALL && !(node->flag & NODE_ACTIVE))) &&
+ return ((snap_target_select == SCE_SNAP_TARGET_NOT_SELECTED && !(node->flag & NODE_SELECT)) ||
+ (snap_target_select == SCE_SNAP_TARGET_ALL && !(node->flag & NODE_ACTIVE))) &&
(node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin &&
node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin);
}
-static NodeBorder snapNodeBorder(int snap_node_mode)
+static NodeBorder snapNodeBorder(eSnapMode snap_node_mode)
{
NodeBorder flag = 0;
if (snap_node_mode & SCE_SNAP_MODE_NODE_X) {
@@ -1499,7 +1505,7 @@ static bool snapNodes(ToolSettings *ts,
SpaceNode *snode,
ARegion *region,
const int mval[2],
- eSnapSelect snap_select,
+ eSnapTargetSelect snap_target_select,
float r_loc[2],
float *r_dist_px,
char *r_node_border)
@@ -1511,7 +1517,7 @@ static bool snapNodes(ToolSettings *ts,
*r_node_border = 0;
for (node = ntree->nodes.first; node; node = node->next) {
- if (snapNodeTest(&region->v2d, node, snap_select)) {
+ if (snapNodeTest(&region->v2d, node, snap_target_select)) {
retval |= snapNode(ts, snode, region, node, mval, r_loc, r_dist_px, r_node_border);
}
}
@@ -1526,7 +1532,7 @@ bool snapNodesTransform(
t->area->spacedata.first,
t->region,
mval,
- t->tsnap.modeSelect,
+ t->tsnap.target_select,
r_loc,
r_dist_px,
r_node_border);
@@ -1548,7 +1554,7 @@ static void snap_grid_apply(
float in[3];
if (t->con.mode & CON_APPLY) {
- BLI_assert(t->tsnap.snapElem == 0);
+ BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE);
t->con.applyVec(t, NULL, NULL, loc, in);
}
else {
@@ -1676,6 +1682,16 @@ bool transform_snap_increment(const TransInfo *t, float *r_val)
return transform_snap_increment_ex(t, false, r_val);
}
+float transform_snap_increment_get(const TransInfo *t)
+{
+ if (activeSnap(t) && (!transformModeUseSnap(t) ||
+ (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
+ return (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
+ }
+
+ return 0.0f;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index cde97d14be4..6db027df067 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -19,12 +19,12 @@ bool peelObjectsTransform(struct TransInfo *t,
float r_no[3],
float *r_thickness);
-short snapObjectsTransform(struct TransInfo *t,
- const float mval[2],
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3]);
+eSnapMode snapObjectsTransform(struct TransInfo *t,
+ const float mval[2],
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3]);
bool snapNodesTransform(struct TransInfo *t,
const int mval[2],
/* return args */
@@ -36,6 +36,7 @@ bool transformModeUseSnap(const TransInfo *t);
bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val);
bool transform_snap_increment(const TransInfo *t, float *val);
+float transform_snap_increment_get(const TransInfo *t);
bool transform_snap_grid(TransInfo *t, float *val);
bool activeSnap(const TransInfo *t);
diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc
index 6beae690b12..cf99d4b2ef3 100644
--- a/source/blender/editors/transform/transform_snap_object.cc
+++ b/source/blender/editors/transform/transform_snap_object.cc
@@ -157,7 +157,7 @@ struct SnapObjectContext {
enum eViewProj view_proj;
float clip_plane[MAX_CLIPPLANE_LEN][4];
short clip_plane_len;
- short snap_to_flag;
+ eSnapMode snap_to_flag;
bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */
} runtime;
};
@@ -283,8 +283,10 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
}
}
else {
- /* Any existing #SnapData_EditMesh is now invalid. */
- sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval));
+ if (ob_eval->type == OB_MESH) {
+ /* Any existing #SnapData_EditMesh is now invalid. */
+ sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval));
+ }
std::unique_ptr<SnapData_Mesh> sod_ptr = std::make_unique<SnapData_Mesh>();
sod = sod_ptr.get();
@@ -417,7 +419,7 @@ using IterSnapObjsCallback = void (*)(SnapObjectContext *sctx,
void *data);
static bool snap_object_is_snappable(const SnapObjectContext *sctx,
- const eSnapSelect snap_select,
+ const eSnapTargetSelect snap_select,
const Base *base_act,
const Base *base,
const bool is_in_object_mode)
@@ -426,7 +428,7 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx,
return false;
}
- if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
+ if ((snap_select == SCE_SNAP_TARGET_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
return true;
}
@@ -434,15 +436,15 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx,
return false;
}
- if (snap_select == SNAP_NOT_ACTIVE) {
+ if (snap_select == SCE_SNAP_TARGET_NOT_ACTIVE) {
return base_act != base;
}
- if (snap_select == SNAP_NOT_EDITED) {
+ if (snap_select == SCE_SNAP_TARGET_NOT_EDITED) {
return base->object->mode != OB_MODE_EDIT;
}
- if (snap_select == SNAP_NOT_SELECTED) {
+ if (snap_select == SCE_SNAP_TARGET_NOT_SELECTED) {
if (is_in_object_mode) {
return !((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL));
}
@@ -451,7 +453,7 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx,
return true;
}
- if (snap_select == SNAP_SELECTABLE) {
+ if (snap_select == SCE_SNAP_TARGET_ONLY_SELECTABLE) {
return (base->flag & BASE_SELECTABLE) != 0;
}
@@ -467,12 +469,12 @@ static void iter_snap_objects(SnapObjectContext *sctx,
void *data)
{
ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph);
- const eSnapSelect snap_select = params->snap_select;
+ const eSnapTargetSelect snap_target_select = params->snap_target_select;
Base *base_act = view_layer->basact;
const bool is_in_object_mode = !base_act || base_act->object->mode == OB_MODE_OBJECT;
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
- if (!snap_object_is_snappable(sctx, snap_select, base_act, base, is_in_object_mode)) {
+ if (!snap_object_is_snappable(sctx, snap_target_select, base_act, base, is_in_object_mode)) {
continue;
}
@@ -1533,18 +1535,18 @@ static void nearest2d_data_init_editmesh(SnapData_EditMesh *sod,
/** \name Internal Object Snapping API
* \{ */
-static short snap_mesh_polygon(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- short elem = 0;
+ eSnapMode elem = SCE_SNAP_MODE_NONE;
float lpmat[4][4];
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
@@ -1663,23 +1665,23 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- float original_dist_px,
- const float prev_co[3],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ float original_dist_px,
+ const float prev_co[3],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- short elem = SCE_SNAP_MODE_EDGE;
+ eSnapMode elem = SCE_SNAP_MODE_EDGE;
if (ob_eval->type != OB_MESH) {
return elem;
@@ -1826,19 +1828,19 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
return elem;
}
-static short snapArmature(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- bool is_object_active,
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snapArmature(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ bool is_object_active,
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */
return retval;
@@ -1875,7 +1877,7 @@ static short snapArmature(SnapObjectContext *sctx,
const bool is_posemode = is_object_active && (ob_eval->mode & OB_MODE_POSE);
const bool skip_selected = (is_editmode || is_posemode) &&
- (params->snap_select == SNAP_NOT_SELECTED);
+ (params->snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED);
const bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
if (arm->edbo) {
@@ -1990,25 +1992,25 @@ static short snapArmature(SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapCurve(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snapCurve(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
bool has_snap = false;
/* only vertex snapping mode (eg control points and handles) supported for now) */
if ((sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
Curve *cu = static_cast<Curve *>(ob_eval->data);
@@ -2032,7 +2034,7 @@ static short snapCurve(SnapObjectContext *sctx,
sctx->runtime.win_size,
sctx->runtime.mval,
dist_px_sq)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
@@ -2054,7 +2056,7 @@ static short snapCurve(SnapObjectContext *sctx,
}
bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
- bool skip_selected = params->snap_select == SNAP_NOT_SELECTED;
+ bool skip_selected = params->snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED;
LISTBASE_FOREACH (Nurb *, nu, (use_obedit ? &cu->editnurb->nurbs : &cu->nurb)) {
for (int u = 0; u < nu->pntsu; u++) {
@@ -2160,21 +2162,21 @@ static short snapCurve(SnapObjectContext *sctx,
return SCE_SNAP_MODE_VERTEX;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
/* may extend later (for now just snaps to empty center) */
-static short snap_object_center(const SnapObjectContext *sctx,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snap_object_center(const SnapObjectContext *sctx,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
if (ob_eval->transflag & OB_DUPLI) {
return retval;
@@ -2216,20 +2218,20 @@ static short snap_object_center(const SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapCamera(const SnapObjectContext *sctx,
- Object *object,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *r_no,
- int *r_index)
+static eSnapMode snapCamera(const SnapObjectContext *sctx,
+ Object *object,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *r_no,
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
Scene *scene = sctx->scene;
@@ -2310,28 +2312,28 @@ static short snapCamera(const SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapMesh(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const Mesh *me_eval,
- const float obmat[4][4],
- bool use_hide,
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snapMesh(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const Mesh *me_eval,
+ const float obmat[4][4],
+ bool use_hide,
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
if (me_eval->totvert == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
if (me_eval->totedge == 0 && !(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
float lpmat[4][4];
@@ -2344,7 +2346,7 @@ static short snapMesh(SnapObjectContext *sctx,
if (bb &&
!snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
@@ -2385,7 +2387,7 @@ static short snapMesh(SnapObjectContext *sctx,
nearest.dist_sq = dist_px_sq;
int last_index = nearest.index;
- short elem = SCE_SNAP_MODE_VERTEX;
+ eSnapMode elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
@@ -2489,31 +2491,31 @@ static short snapMesh(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapEditMesh(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- BMEditMesh *em,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snapEditMesh(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ BMEditMesh *em,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
if (em->bm->totvert == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
else {
if (em->bm->totedge == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
@@ -2529,7 +2531,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
if (!snap_bound_box_check_dist(
sod->min, sod->max, lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
@@ -2604,7 +2606,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
nearest.index = -1;
nearest.dist_sq = dist_px_sq;
- short elem = SCE_SNAP_MODE_VERTEX;
+ eSnapMode elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
@@ -2670,7 +2672,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
struct SnapObjUserData {
@@ -2682,7 +2684,7 @@ struct SnapObjUserData {
int *r_index;
Object **r_ob;
float (*r_obmat)[4];
- short ret;
+ eSnapMode ret;
};
/**
@@ -2696,7 +2698,7 @@ static void snap_obj_fn(SnapObjectContext *sctx,
void *data)
{
SnapObjUserData *dt = static_cast<SnapObjUserData *>(data);
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
switch (ob_eval->type) {
case OB_MESH: {
@@ -2743,11 +2745,8 @@ static void snap_obj_fn(SnapObjectContext *sctx,
dt->r_index);
break;
case OB_CURVES_LEGACY:
- retval = snapCurve(
- sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
- break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
case OB_SURF:
- if (BKE_object_is_in_editmode(ob_eval)) {
+ if (ob_eval->type == OB_CURVES_LEGACY || BKE_object_is_in_editmode(ob_eval)) {
retval = snapCurve(
sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
if (params->edit_mode_type != SNAP_GEOM_FINAL) {
@@ -2816,18 +2815,18 @@ static void snap_obj_fn(SnapObjectContext *sctx,
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
*/
-static short snapObjectsRay(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- /* read/write args */
- /* Parameters below cannot be const, because they are assigned to a
- * non-const variable (readability-non-const-parameter). */
- float *dist_px /* NOLINT */,
- /* return args */
- float r_loc[3] /* NOLINT */,
- float r_no[3] /* NOLINT */,
- int *r_index /* NOLINT */,
- Object **r_ob,
- float r_obmat[4][4])
+static eSnapMode snapObjectsRay(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ /* read/write args */
+ /* Parameters below cannot be const, because they are assigned to a
+ * non-const variable (readability-non-const-parameter). */
+ float *dist_px /* NOLINT */,
+ /* return args */
+ float r_loc[3] /* NOLINT */,
+ float r_no[3] /* NOLINT */,
+ int *r_index /* NOLINT */,
+ Object **r_ob,
+ float r_obmat[4][4])
{
SnapObjUserData data = {};
data.dist_px = dist_px;
@@ -2836,7 +2835,7 @@ static short snapObjectsRay(SnapObjectContext *sctx,
data.r_ob = r_ob;
data.r_index = r_index;
data.r_obmat = r_obmat;
- data.ret = 0;
+ data.ret = SCE_SNAP_MODE_NONE;
iter_snap_objects(sctx, params, snap_obj_fn, &data);
@@ -3009,31 +3008,29 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
sctx, depsgraph, v3d, params, ray_origin, ray_direction, ray_depth, r_co, r_no);
}
-static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const ushort snap_to_flag,
- const SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4],
- float r_face_nor[3])
+static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to_flag,
+ const SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3],
+ int *r_index,
+ Object **r_ob,
+ float r_obmat[4][4],
+ float r_face_nor[3])
{
sctx->runtime.depsgraph = depsgraph;
sctx->runtime.region = region;
sctx->runtime.v3d = v3d;
- BLI_assert((snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) !=
- 0);
+ BLI_assert((snap_to_flag & SCE_SNAP_MODE_GEOM) != 0);
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
bool has_hit = false;
Object *ob_eval = nullptr;
@@ -3052,7 +3049,7 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
float ray_start[3], ray_normal[3];
if (!ED_view3d_win_to_ray_clipped_ex(
depsgraph, region, v3d, mval, nullptr, ray_normal, ray_start, true)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
float dummy_ray_depth = BVH_RAYCAST_DIST_MAX;
@@ -3096,7 +3093,7 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- short elem_test, elem = 0;
+ eSnapMode elem_test, elem = SCE_SNAP_MODE_NONE;
float dist_px_tmp = *dist_px;
copy_m4_m4(sctx->runtime.pmat, rv3d->persmat);
@@ -3106,9 +3103,11 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
sctx->runtime.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
/* First snap to edge instead of middle or perpendicular. */
- sctx->runtime.snap_to_flag = snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE);
+ sctx->runtime.snap_to_flag = static_cast<eSnapMode>(
+ snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE));
if (snap_to_flag & (SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- sctx->runtime.snap_to_flag |= SCE_SNAP_MODE_EDGE;
+ sctx->runtime.snap_to_flag = static_cast<eSnapMode>(sctx->runtime.snap_to_flag |
+ SCE_SNAP_MODE_EDGE);
}
planes_from_projmat(sctx->runtime.pmat,
@@ -3192,21 +3191,21 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
return retval;
}
-short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const ushort snap_to,
- const SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4],
- float r_face_nor[3])
+eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to,
+ const SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3],
+ int *r_index,
+ Object **r_ob,
+ float r_obmat[4][4],
+ float r_face_nor[3])
{
return transform_snap_context_project_view3d_mixed_impl(sctx,
depsgraph,
@@ -3225,17 +3224,17 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
r_face_nor);
}
-short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const ushort snap_to,
- const SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3])
+eSnapMode ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to,
+ const SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3])
{
return ED_transform_snap_object_project_view3d_ex(sctx,
depsgraph,
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 89d80d582f8..5c2a3374aa1 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -91,6 +91,7 @@ set(SRC
../include/ED_uvedit.h
../include/ED_view3d.h
../include/ED_view3d_offscreen.h
+ ../include/UI_grid_view.hh
../include/UI_icons.h
../include/UI_interface.h
../include/UI_interface.hh
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index ead017a91bf..cea2bb05547 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -2425,7 +2425,7 @@ static bool uv_mouse_select_multi(bContext *C,
UvNearestHit hit = UV_NEAREST_HIT_INIT_DIST_PX(&region->v2d, 75.0f);
int selectmode, sticky;
bool found_item = false;
- /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */
int flush = 0;
/* Penalty (in pixels) applied to elements that are already selected
@@ -2514,8 +2514,15 @@ static bool uv_mouse_select_multi(bContext *C,
else if (selectmode == UV_SELECT_EDGE) {
is_selected = uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset);
}
- else { /* Vertex or island. */
- is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ else {
+ /* Vertex or island. For island (if we were using #uv_find_nearest_face_multi_ex, see above),
+ * `hit.l` is NULL, use `hit.efa` instead. */
+ if (hit.l != NULL) {
+ is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ }
+ else {
+ is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset);
+ }
}
}
@@ -2728,7 +2735,7 @@ static int uv_mouse_select_loop_generic_multi(bContext *C,
const ToolSettings *ts = scene->toolsettings;
UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
bool found_item = false;
- /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */
int flush = 0;
/* Find edge. */
@@ -3282,8 +3289,6 @@ static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, co
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (select) {
@@ -3353,8 +3358,6 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co
/* now select tagged verts */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
@@ -3373,8 +3376,6 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co
}
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
uv_select_flush_from_tag_sticky_loc_internal(
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index bacf321fce1..55e44607f6f 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1716,7 +1716,7 @@ static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float
GPU_batch_discard(batch);
}
-/* TODO: make things pretier : store batches inside StitchPreviewer instead of the bare verts pos
+/* TODO: make things prettier : store batches inside StitchPreviewer instead of the bare verts pos
*/
static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
{
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index cbc9b2a8d06..3618286ec01 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -298,6 +298,44 @@ void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy)
ED_uvedit_get_aspect_from_material(ob, efa->mat_nr, r_aspx, r_aspy);
}
+static bool uvedit_is_face_affected(const Scene *scene,
+ BMFace *efa,
+ const UnwrapOptions *options,
+ const int cd_loop_uv_offset)
+{
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ return false;
+ }
+
+ if (options->only_selected_faces && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ return false;
+ }
+
+ if (options->topology_from_uvs && options->only_selected_uvs &&
+ !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Prepare unique indices for each unique pinned UV, even if it shares a BMVert.
+ */
+static void uvedit_prepare_pinned_indices(ParamHandle *handle,
+ BMFace *efa,
+ const int cd_loop_uv_offset)
+{
+ BMIter liter;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_PINNED) {
+ int bmvertindex = BM_elem_index_get(l->v);
+ GEO_uv_prepare_pin_index(handle, bmvertindex, luv->uv);
+ }
+ }
+}
+
static void construct_param_handle_face_add(ParamHandle *handle,
const Scene *scene,
BMFace *efa,
@@ -319,7 +357,7 @@ static void construct_param_handle_face_add(ParamHandle *handle,
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- vkeys[i] = (ParamKey)BM_elem_index_get(l->v);
+ vkeys[i] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv->uv);
co[i] = l->v->co;
uv[i] = luv->uv;
pin[i] = (luv->flag & MLOOPUV_PINNED) != 0;
@@ -337,13 +375,10 @@ static ParamHandle *construct_param_handle(const Scene *scene,
UnwrapResultInfo *result_info)
{
BMFace *efa;
- BMLoop *l;
BMEdge *eed;
- BMIter iter, liter;
+ BMIter iter;
int i;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
if (options->correct_aspect) {
@@ -359,30 +394,17 @@ static ParamHandle *construct_param_handle(const Scene *scene,
/* we need the vert indices */
BM_mesh_elem_index_ensure(bm, BM_VERT);
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
-
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ||
- (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
- continue;
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ uvedit_prepare_pinned_indices(handle, efa, cd_loop_uv_offset);
}
+ }
- if (options->topology_from_uvs) {
- bool is_loopsel = false;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (options->only_selected_uvs &&
- (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
- continue;
- }
- is_loopsel = true;
- break;
- }
- if (is_loopsel == false) {
- continue;
- }
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
}
-
- construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
}
if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
@@ -414,9 +436,8 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
int *count_fail)
{
BMFace *efa;
- BMLoop *l;
BMEdge *eed;
- BMIter iter, liter;
+ BMIter iter;
int i;
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
@@ -448,29 +469,15 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
}
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
-
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ||
- (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
- continue;
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ uvedit_prepare_pinned_indices(handle, efa, cd_loop_uv_offset);
}
+ }
- if (options->topology_from_uvs) {
- bool is_loopsel = false;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (options->only_selected_uvs &&
- (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
- continue;
- }
- is_loopsel = true;
- break;
- }
- if (is_loopsel == false) {
- continue;
- }
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
}
-
- construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
}
if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 46051a58e8b..a8136d06c5f 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -476,6 +476,8 @@ template<typename T> T evaluate_constant_field(const Field<T> &field)
return value;
}
+Field<bool> invert_boolean_field(const Field<bool> &field);
+
GField make_constant_field(const CPPType &type, const void *value);
template<typename T> Field<T> make_constant_field(T value)
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index a53da717606..47f6a0f19ca 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -518,6 +518,14 @@ GField make_field_constant_if_possible(GField field)
return new_field;
}
+Field<bool> invert_boolean_field(const Field<bool> &field)
+{
+ static CustomMF_SI_SO<bool, bool> not_fn{
+ "Not", [](bool a) { return !a; }, CustomMF_presets::AllSpanOrSingle()};
+ auto not_op = std::make_shared<FieldOperation>(FieldOperation(not_fn, {field}));
+ return Field<bool>(not_op);
+}
+
GField make_constant_field(const CPPType &type, const void *value)
{
auto constant_node = std::make_shared<FieldConstant>(type, value);
diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt
index 010c327d482..531487a45e2 100644
--- a/source/blender/geometry/CMakeLists.txt
+++ b/source/blender/geometry/CMakeLists.txt
@@ -15,20 +15,24 @@ set(INC
)
set(SRC
+ intern/add_curves_on_mesh.cc
intern/mesh_merge_by_distance.cc
intern/mesh_primitive_cuboid.cc
intern/mesh_to_curve_convert.cc
intern/point_merge_by_distance.cc
intern/realize_instances.cc
intern/resample_curves.cc
+ intern/reverse_uv_sampler.cc
intern/uv_parametrizer.c
+ GEO_add_curves_on_mesh.hh
GEO_mesh_merge_by_distance.hh
GEO_mesh_primitive_cuboid.hh
GEO_mesh_to_curve.hh
GEO_point_merge_by_distance.hh
GEO_realize_instances.hh
GEO_resample_curves.hh
+ GEO_reverse_uv_sampler.hh
GEO_uv_parametrizer.h
)
diff --git a/source/blender/geometry/GEO_add_curves_on_mesh.hh b/source/blender/geometry/GEO_add_curves_on_mesh.hh
new file mode 100644
index 00000000000..cf60a8e8ace
--- /dev/null
+++ b/source/blender/geometry/GEO_add_curves_on_mesh.hh
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_float4x4.hh"
+#include "BLI_kdtree.h"
+#include "BLI_math_vector.hh"
+#include "BLI_span.hh"
+
+#include "BKE_bvhutils.h"
+#include "BKE_curves.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+namespace blender::geometry {
+
+struct AddCurvesOnMeshInputs {
+ /** Information about the root points where new curves should be generated. */
+ Span<float3> root_positions_cu;
+ Span<float3> bary_coords;
+ Span<int> looptri_indices;
+
+ /** Determines shape of new curves. */
+ bool interpolate_length = false;
+ bool interpolate_shape = false;
+ bool interpolate_point_count = false;
+ float fallback_curve_length = 0.0f;
+ int fallback_point_count = 0;
+
+ /** Information about the surface that the new curves are attached to. */
+ const Mesh *surface = nullptr;
+ BVHTreeFromMesh *surface_bvh = nullptr;
+ Span<MLoopTri> surface_looptris;
+ Span<float2> surface_uv_map;
+ Span<float3> corner_normals_su;
+
+ /** Transformation matrices. */
+ float4x4 curves_to_surface_mat;
+ float4x4 surface_to_curves_normal_mat;
+
+ /**
+ * KD-Tree that contains the root points of existing curves. This is only necessary when
+ * interpolation is used.
+ */
+ KDTree_3d *old_roots_kdtree = nullptr;
+};
+
+/**
+ * Generate new curves on a mesh surface with the given inputs. Existing curves stay intact.
+ */
+void add_curves_on_mesh(bke::CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_reverse_uv_sampler.hh b/source/blender/geometry/GEO_reverse_uv_sampler.hh
new file mode 100644
index 00000000000..d392b65eaf4
--- /dev/null
+++ b/source/blender/geometry/GEO_reverse_uv_sampler.hh
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include <optional>
+
+#include "BLI_math_vector.hh"
+#include "BLI_span.hh"
+
+#include "DNA_meshdata_types.h"
+
+namespace blender::geometry {
+
+/**
+ * Can find the polygon/triangle that maps to a specific uv coordinate.
+ *
+ * \note this uses a trivial implementation currently that has to be replaced.
+ */
+class ReverseUVSampler {
+ private:
+ const Span<float2> uv_map_;
+ const Span<MLoopTri> looptris_;
+
+ public:
+ ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTri> looptris);
+
+ enum class ResultType {
+ None,
+ Ok,
+ Multiple,
+ };
+
+ struct Result {
+ ResultType type = ResultType::None;
+ const MLoopTri *looptri = nullptr;
+ float3 bary_weights;
+ };
+
+ Result sample(const float2 &query_uv) const;
+};
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_uv_parametrizer.h b/source/blender/geometry/GEO_uv_parametrizer.h
index 7fe60a3a855..2181f95945e 100644
--- a/source/blender/geometry/GEO_uv_parametrizer.h
+++ b/source/blender/geometry/GEO_uv_parametrizer.h
@@ -14,6 +14,7 @@ extern "C" {
typedef struct ParamHandle ParamHandle; /* Handle to an array of charts. */
typedef intptr_t ParamKey; /* Key (hash) for identifying verts and faces. */
+#define PARAM_KEY_MAX INTPTR_MAX
/* -------------------------------------------------------------------- */
/** \name Chart Construction:
@@ -34,6 +35,10 @@ ParamHandle *GEO_uv_parametrizer_construct_begin(void);
void GEO_uv_parametrizer_aspect_ratio(ParamHandle *handle, float aspx, float aspy);
+void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
+
+ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
+
void GEO_uv_parametrizer_face_add(ParamHandle *handle,
const ParamKey key,
const int nverts,
diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc
new file mode 100644
index 00000000000..34551bd474f
--- /dev/null
+++ b/source/blender/geometry/intern/add_curves_on_mesh.cc
@@ -0,0 +1,354 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_mesh_sample.hh"
+#include "BKE_spline.hh"
+
+#include "GEO_add_curves_on_mesh.hh"
+
+/**
+ * The code below uses a suffix naming convention to indicate the coordinate space:
+ * cu: Local space of the curves object that is being edited.
+ * su: Local space of the surface object.
+ */
+
+namespace blender::geometry {
+
+using bke::CurvesGeometry;
+
+struct NeighborCurve {
+ /* Curve index of the neighbor. */
+ int index;
+ /* The weights of all neighbors of a new curve add up to 1. */
+ float weight;
+};
+
+static constexpr int max_neighbors = 5;
+using NeighborCurves = Vector<NeighborCurve, max_neighbors>;
+
+static float3 compute_surface_point_normal(const MLoopTri &looptri,
+ const float3 &bary_coord,
+ const Span<float3> corner_normals)
+{
+ const int l0 = looptri.tri[0];
+ const int l1 = looptri.tri[1];
+ const int l2 = looptri.tri[2];
+
+ const float3 &l0_normal = corner_normals[l0];
+ const float3 &l1_normal = corner_normals[l1];
+ const float3 &l2_normal = corner_normals[l2];
+
+ const float3 normal = math::normalize(
+ attribute_math::mix3(bary_coord, l0_normal, l1_normal, l2_normal));
+ return normal;
+}
+
+static void initialize_straight_curve_positions(const float3 &p1,
+ const float3 &p2,
+ MutableSpan<float3> r_positions)
+{
+ const float step = 1.0f / (float)(r_positions.size() - 1);
+ for (const int i : r_positions.index_range()) {
+ r_positions[i] = math::interpolate(p1, p2, i * step);
+ }
+}
+
+static Array<NeighborCurves> find_curve_neighbors(const Span<float3> root_positions,
+ const KDTree_3d &old_roots_kdtree)
+{
+ const int tot_added_curves = root_positions.size();
+ Array<NeighborCurves> neighbors_per_curve(tot_added_curves);
+ threading::parallel_for(IndexRange(tot_added_curves), 128, [&](const IndexRange range) {
+ for (const int i : range) {
+ const float3 root = root_positions[i];
+ std::array<KDTreeNearest_3d, max_neighbors> nearest_n;
+ const int found_neighbors = BLI_kdtree_3d_find_nearest_n(
+ &old_roots_kdtree, root, nearest_n.data(), max_neighbors);
+ float tot_weight = 0.0f;
+ for (const int neighbor_i : IndexRange(found_neighbors)) {
+ KDTreeNearest_3d &nearest = nearest_n[neighbor_i];
+ const float weight = 1.0f / std::max(nearest.dist, 0.00001f);
+ tot_weight += weight;
+ neighbors_per_curve[i].append({nearest.index, weight});
+ }
+ /* Normalize weights. */
+ for (NeighborCurve &neighbor : neighbors_per_curve[i]) {
+ neighbor.weight /= tot_weight;
+ }
+ }
+ });
+ return neighbors_per_curve;
+}
+
+template<typename T, typename GetValueF>
+void interpolate_from_neighbors(const Span<NeighborCurves> neighbors_per_curve,
+ const T &fallback,
+ const GetValueF &get_value_from_neighbor,
+ MutableSpan<T> r_interpolated_values)
+{
+ attribute_math::DefaultMixer<T> mixer{r_interpolated_values};
+ threading::parallel_for(r_interpolated_values.index_range(), 512, [&](const IndexRange range) {
+ for (const int i : range) {
+ const NeighborCurves &neighbors = neighbors_per_curve[i];
+ if (neighbors.is_empty()) {
+ mixer.mix_in(i, fallback, 1.0f);
+ }
+ else {
+ for (const NeighborCurve &neighbor : neighbors) {
+ const T neighbor_value = get_value_from_neighbor(neighbor.index);
+ mixer.mix_in(i, neighbor_value, neighbor.weight);
+ }
+ }
+ }
+ });
+ mixer.finalize();
+}
+
+static void interpolate_position_without_interpolation(
+ CurvesGeometry &curves,
+ const int old_curves_num,
+ const Span<float3> root_positions_cu,
+ const Span<float> new_lengths_cu,
+ const Span<float3> new_normals_su,
+ const float4x4 &surface_to_curves_normal_mat)
+{
+ const int added_curves_num = root_positions_cu.size();
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+ threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int curve_i = old_curves_num + i;
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const float3 &root_cu = root_positions_cu[i];
+ const float length = new_lengths_cu[i];
+ const float3 &normal_su = new_normals_su[i];
+ const float3 normal_cu = math::normalize(surface_to_curves_normal_mat * normal_su);
+ const float3 tip_cu = root_cu + length * normal_cu;
+
+ initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
+ }
+ });
+}
+
+static void interpolate_position_with_interpolation(CurvesGeometry &curves,
+ const Span<float3> root_positions_cu,
+ const Span<NeighborCurves> neighbors_per_curve,
+ const int old_curves_num,
+ const Span<float> new_lengths_cu,
+ const Span<float3> new_normals_su,
+ const float4x4 &surface_to_curves_normal_mat,
+ const float4x4 &curves_to_surface_mat,
+ const BVHTreeFromMesh &surface_bvh,
+ const Span<MLoopTri> surface_looptris,
+ const Mesh &surface,
+ const Span<float3> corner_normals_su)
+{
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+ const int added_curves_num = root_positions_cu.size();
+
+ threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const NeighborCurves &neighbors = neighbors_per_curve[i];
+ const int curve_i = old_curves_num + i;
+ const IndexRange points = curves.points_for_curve(curve_i);
+
+ const float length_cu = new_lengths_cu[i];
+ const float3 &normal_su = new_normals_su[i];
+ const float3 normal_cu = math::normalize(surface_to_curves_normal_mat * normal_su);
+
+ const float3 &root_cu = root_positions_cu[i];
+
+ if (neighbors.is_empty()) {
+ /* If there are no neighbors, just make a straight line. */
+ const float3 tip_cu = root_cu + length_cu * normal_cu;
+ initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
+ continue;
+ }
+
+ positions_cu.slice(points).fill(root_cu);
+
+ for (const NeighborCurve &neighbor : neighbors) {
+ const int neighbor_curve_i = neighbor.index;
+ const float3 &neighbor_first_pos_cu = positions_cu[curves.offsets()[neighbor_curve_i]];
+ const float3 neighbor_first_pos_su = curves_to_surface_mat * neighbor_first_pos_cu;
+
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(surface_bvh.tree,
+ neighbor_first_pos_su,
+ &nearest,
+ surface_bvh.nearest_callback,
+ const_cast<BVHTreeFromMesh *>(&surface_bvh));
+ const int neighbor_looptri_index = nearest.index;
+ const MLoopTri &neighbor_looptri = surface_looptris[neighbor_looptri_index];
+
+ const float3 neighbor_bary_coord =
+ bke::mesh_surface_sample::compute_bary_coord_in_triangle(
+ surface, neighbor_looptri, nearest.co);
+
+ const float3 neighbor_normal_su = compute_surface_point_normal(
+ surface_looptris[neighbor_looptri_index], neighbor_bary_coord, corner_normals_su);
+ const float3 neighbor_normal_cu = math::normalize(surface_to_curves_normal_mat *
+ neighbor_normal_su);
+
+ /* The rotation matrix used to transform relative coordinates of the neighbor curve
+ * to the new curve. */
+ float normal_rotation_cu[3][3];
+ rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu);
+
+ const IndexRange neighbor_points = curves.points_for_curve(neighbor_curve_i);
+ const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]];
+
+ /* Use a temporary #PolySpline, because that's the easiest way to resample an
+ * existing curve right now. Resampling is necessary if the length of the new curve
+ * does not match the length of the neighbors or the number of handle points is
+ * different. */
+ PolySpline neighbor_spline;
+ neighbor_spline.resize(neighbor_points.size());
+ neighbor_spline.positions().copy_from(positions_cu.slice(neighbor_points));
+ neighbor_spline.mark_cache_invalid();
+
+ const float neighbor_length_cu = neighbor_spline.length();
+ const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu);
+
+ const float resample_factor = (1.0f / (points.size() - 1.0f)) * length_factor;
+ for (const int j : IndexRange(points.size())) {
+ const Spline::LookupResult lookup = neighbor_spline.lookup_evaluated_factor(
+ j * resample_factor);
+ const float index_factor = lookup.evaluated_index + lookup.factor;
+ float3 p;
+ neighbor_spline.sample_with_index_factors<float3>(
+ neighbor_spline.positions(), {&index_factor, 1}, {&p, 1});
+ const float3 relative_coord = p - neighbor_root_cu;
+ float3 rotated_relative_coord = relative_coord;
+ mul_m3_v3(normal_rotation_cu, rotated_relative_coord);
+ positions_cu[points[j]] += neighbor.weight * rotated_relative_coord;
+ }
+ }
+ }
+ });
+}
+
+void add_curves_on_mesh(CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs)
+{
+ const bool use_interpolation = inputs.interpolate_length || inputs.interpolate_point_count ||
+ inputs.interpolate_shape;
+
+ Array<NeighborCurves> neighbors_per_curve;
+ if (use_interpolation) {
+ BLI_assert(inputs.old_roots_kdtree != nullptr);
+ neighbors_per_curve = find_curve_neighbors(inputs.root_positions_cu, *inputs.old_roots_kdtree);
+ }
+
+ const int added_curves_num = inputs.root_positions_cu.size();
+ const int old_points_num = curves.points_num();
+ const int old_curves_num = curves.curves_num();
+ const int new_curves_num = old_curves_num + added_curves_num;
+
+ /* Grow number of curves first, so that the offsets array can be filled. */
+ curves.resize(old_points_num, new_curves_num);
+
+ /* Compute new curve offsets. */
+ MutableSpan<int> curve_offsets = curves.offsets_for_write();
+ MutableSpan<int> new_point_counts_per_curve = curve_offsets.take_back(added_curves_num);
+ if (inputs.interpolate_point_count) {
+ interpolate_from_neighbors<int>(
+ neighbors_per_curve,
+ inputs.fallback_point_count,
+ [&](const int curve_i) { return curves.points_for_curve(curve_i).size(); },
+ new_point_counts_per_curve);
+ }
+ else {
+ new_point_counts_per_curve.fill(inputs.fallback_point_count);
+ }
+ for (const int i : IndexRange(added_curves_num)) {
+ curve_offsets[old_curves_num + i + 1] += curve_offsets[old_curves_num + i];
+ }
+
+ const int new_points_num = curves.offsets().last();
+ curves.resize(new_points_num, new_curves_num);
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+
+ /* Determine length of new curves. */
+ Array<float> new_lengths_cu(added_curves_num);
+ if (inputs.interpolate_length) {
+ interpolate_from_neighbors<float>(
+ neighbors_per_curve,
+ inputs.fallback_curve_length,
+ [&](const int curve_i) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ float length = 0.0f;
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 &p1 = positions_cu[segment_i];
+ const float3 &p2 = positions_cu[segment_i + 1];
+ length += math::distance(p1, p2);
+ }
+ return length;
+ },
+ new_lengths_cu);
+ }
+ else {
+ new_lengths_cu.fill(inputs.fallback_curve_length);
+ }
+
+ /* Find surface normal at root points. */
+ Array<float3> new_normals_su(added_curves_num);
+ threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int looptri_index = inputs.looptri_indices[i];
+ const float3 &bary_coord = inputs.bary_coords[i];
+ new_normals_su[i] = compute_surface_point_normal(
+ inputs.surface_looptris[looptri_index], bary_coord, inputs.corner_normals_su);
+ }
+ });
+
+ /* Propagate attachment information. */
+ if (!inputs.surface_uv_map.is_empty()) {
+ MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write();
+ bke::mesh_surface_sample::sample_corner_attribute(
+ *inputs.surface,
+ inputs.looptri_indices,
+ inputs.bary_coords,
+ GVArray::ForSpan(inputs.surface_uv_map),
+ IndexRange(added_curves_num),
+ surface_uv_coords.take_back(added_curves_num));
+ }
+
+ /* Update selection arrays when available. */
+ const VArray<float> points_selection = curves.selection_point_float();
+ if (points_selection.is_span()) {
+ MutableSpan<float> points_selection_span = curves.selection_point_float_for_write();
+ points_selection_span.drop_front(old_points_num).fill(1.0f);
+ }
+ const VArray<float> curves_selection = curves.selection_curve_float();
+ if (curves_selection.is_span()) {
+ MutableSpan<float> curves_selection_span = curves.selection_curve_float_for_write();
+ curves_selection_span.drop_front(old_curves_num).fill(1.0f);
+ }
+
+ /* Initialize position attribute. */
+ if (inputs.interpolate_shape) {
+ interpolate_position_with_interpolation(curves,
+ inputs.root_positions_cu,
+ neighbors_per_curve,
+ old_curves_num,
+ new_lengths_cu,
+ new_normals_su,
+ inputs.surface_to_curves_normal_mat,
+ inputs.curves_to_surface_mat,
+ *inputs.surface_bvh,
+ inputs.surface_looptris,
+ *inputs.surface,
+ inputs.corner_normals_su);
+ }
+ else {
+ interpolate_position_without_interpolation(curves,
+ old_curves_num,
+ inputs.root_positions_cu,
+ new_lengths_cu,
+ new_normals_su,
+ inputs.surface_to_curves_normal_mat);
+ }
+
+ curves.update_curve_types();
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc
index 9eaab327e01..36525e1bdf0 100644
--- a/source/blender/geometry/intern/resample_curves.cc
+++ b/source/blender/geometry/intern/resample_curves.cc
@@ -165,38 +165,6 @@ static void gather_point_attributes_to_interpolate(const CurveComponent &src_com
dst_curves.update_customdata_pointers();
}
-/**
- * Copy the provided point attribute values between all curves in the #curve_ranges index
- * ranges, assuming that all curves are the same size in #src_curves and #dst_curves.
- */
-template<typename T>
-static void copy_between_curves(const bke::CurvesGeometry &src_curves,
- const bke::CurvesGeometry &dst_curves,
- const Span<IndexRange> curve_ranges,
- const Span<T> src,
- const MutableSpan<T> dst)
-{
- threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
- for (const IndexRange range : curve_ranges.slice(range)) {
- const IndexRange src_points = src_curves.points_for_curves(range);
- const IndexRange dst_points = dst_curves.points_for_curves(range);
- /* The arrays might be large, so a threaded copy might make sense here too. */
- dst.slice(dst_points).copy_from(src.slice(src_points));
- }
- });
-}
-static void copy_between_curves(const bke::CurvesGeometry &src_curves,
- const bke::CurvesGeometry &dst_curves,
- const Span<IndexRange> unselected_ranges,
- const GSpan src,
- const GMutableSpan dst)
-{
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src.typed<T>(), dst.typed<T>());
- });
-}
-
static Curves *resample_to_uniform(const CurveComponent &src_component,
const fn::Field<bool> &selection_field,
const fn::Field<int> &count_field)
@@ -328,20 +296,21 @@ static Curves *resample_to_uniform(const CurveComponent &src_component,
/* Any attribute data from unselected curve points can be directly copied. */
for (const int i : attributes.src.index_range()) {
- copy_between_curves(
+ bke::curves::copy_point_data(
src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
}
for (const int i : attributes.src_no_interpolation.index_range()) {
- copy_between_curves(src_curves,
- dst_curves,
- unselected_ranges,
- attributes.src_no_interpolation[i],
- attributes.dst_no_interpolation[i]);
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ unselected_ranges,
+ attributes.src_no_interpolation[i],
+ attributes.dst_no_interpolation[i]);
}
/* Copy positions for unselected curves. */
Span<float3> src_positions = src_curves.positions();
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
for (bke::OutputAttribute &attribute : attributes.dst_attributes) {
attribute.save();
@@ -449,20 +418,21 @@ Curves *resample_to_evaluated(const CurveComponent &src_component,
/* Any attribute data from unselected curve points can be directly copied. */
for (const int i : attributes.src.index_range()) {
- copy_between_curves(
+ bke::curves::copy_point_data(
src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
}
for (const int i : attributes.src_no_interpolation.index_range()) {
- copy_between_curves(src_curves,
- dst_curves,
- unselected_ranges,
- attributes.src_no_interpolation[i],
- attributes.dst_no_interpolation[i]);
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ unselected_ranges,
+ attributes.src_no_interpolation[i],
+ attributes.dst_no_interpolation[i]);
}
/* Copy positions for unselected curves. */
Span<float3> src_positions = src_curves.positions();
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
for (bke::OutputAttribute &attribute : attributes.dst_attributes) {
attribute.save();
diff --git a/source/blender/geometry/intern/reverse_uv_sampler.cc b/source/blender/geometry/intern/reverse_uv_sampler.cc
new file mode 100644
index 00000000000..9aa98895a86
--- /dev/null
+++ b/source/blender/geometry/intern/reverse_uv_sampler.cc
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "GEO_reverse_uv_sampler.hh"
+
+#include "BLI_math_geom.h"
+
+namespace blender::geometry {
+
+ReverseUVSampler::ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTri> looptris)
+ : uv_map_(uv_map), looptris_(looptris)
+{
+}
+
+ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const
+{
+ for (const MLoopTri &looptri : looptris_) {
+ const float2 &uv0 = uv_map_[looptri.tri[0]];
+ const float2 &uv1 = uv_map_[looptri.tri[1]];
+ const float2 &uv2 = uv_map_[looptri.tri[2]];
+ float3 bary_weights;
+ if (!barycentric_coords_v2(uv0, uv1, uv2, query_uv, bary_weights)) {
+ continue;
+ }
+ if (IN_RANGE_INCL(bary_weights.x, 0.0f, 1.0f) && IN_RANGE_INCL(bary_weights.y, 0.0f, 1.0f) &&
+ IN_RANGE_INCL(bary_weights.z, 0.0f, 1.0f)) {
+ return Result{ResultType::Ok, &looptri, bary_weights};
+ }
+ }
+ return Result{};
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/uv_parametrizer.c b/source/blender/geometry/intern/uv_parametrizer.c
index af3bcc3bdec..46ebe6cfdce 100644
--- a/source/blender/geometry/intern/uv_parametrizer.c
+++ b/source/blender/geometry/intern/uv_parametrizer.c
@@ -8,6 +8,7 @@
#include "BLI_boxpack_2d.h"
#include "BLI_convexhull_2d.h"
+#include "BLI_ghash.h"
#include "BLI_heap.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
@@ -190,6 +191,9 @@ typedef struct ParamHandle {
PHash *hash_edges;
PHash *hash_faces;
+ struct GHash *pin_hash;
+ int unique_pin_count;
+
PChart **charts;
int ncharts;
@@ -3817,8 +3821,11 @@ void GEO_uv_parametrizer_delete(ParamHandle *phandle)
p_chart_delete(phandle->charts[i]);
}
- if (phandle->charts) {
- MEM_freeN(phandle->charts);
+ MEM_SAFE_FREE(phandle->charts);
+
+ if (phandle->pin_hash) {
+ BLI_ghash_free(phandle->pin_hash, NULL, NULL);
+ phandle->pin_hash = NULL;
}
if (phandle->construction_chart) {
@@ -3835,6 +3842,80 @@ void GEO_uv_parametrizer_delete(ParamHandle *phandle)
MEM_freeN(phandle);
}
+typedef struct GeoUVPinIndex {
+ struct GeoUVPinIndex *next;
+ float uv[2];
+ ParamKey reindex;
+} GeoUVPinIndex;
+
+/* Find a (mostly) unique ParamKey given a BMVert index and UV co-ordinates.
+ * For each unique pinned UVs, return a unique ParamKey, starting with
+ * a very large number, and decreasing steadily from there.
+ * For non-pinned UVs which share a BMVert with a pinned UV,
+ * return the index corresponding to the closest pinned UV.
+ * For everything else, just return the BMVert index.
+ * Note that ParamKeys will eventually be hashed, so they don't need to be contiguous.
+ */
+ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
+{
+ if (!handle->pin_hash) {
+ return bmvertindex; /* No verts pinned. */
+ }
+
+ GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, POINTER_FROM_INT(bmvertindex));
+ if (!pinuvlist) {
+ return bmvertindex; /* Vert not pinned. */
+ }
+
+ /* At least one of the UVs associated with bmvertindex is pinned. Find the best one. */
+ float bestdistsquared = len_squared_v2v2(pinuvlist->uv, uv);
+ ParamKey bestkey = pinuvlist->reindex;
+ pinuvlist = pinuvlist->next;
+ while (pinuvlist) {
+ const float distsquared = len_squared_v2v2(pinuvlist->uv, uv);
+ if (bestdistsquared > distsquared) {
+ bestdistsquared = distsquared;
+ bestkey = pinuvlist->reindex;
+ }
+ pinuvlist = pinuvlist->next;
+ }
+ return bestkey;
+}
+
+static GeoUVPinIndex *new_geo_uv_pinindex(ParamHandle *handle, const float uv[2])
+{
+ GeoUVPinIndex *pinuv = BLI_memarena_alloc(handle->arena, sizeof(*pinuv));
+ pinuv->next = NULL;
+ copy_v2_v2(pinuv->uv, uv);
+ pinuv->reindex = PARAM_KEY_MAX - (handle->unique_pin_count++);
+ return pinuv;
+}
+
+void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
+{
+ if (!handle->pin_hash) {
+ handle->pin_hash = BLI_ghash_int_new("uv pin reindex");
+ }
+
+ GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, POINTER_FROM_INT(bmvertindex));
+ if (!pinuvlist) {
+ BLI_ghash_insert(
+ handle->pin_hash, POINTER_FROM_INT(bmvertindex), new_geo_uv_pinindex(handle, uv));
+ return;
+ }
+
+ while (true) {
+ if (equals_v2v2(pinuvlist->uv, uv)) {
+ return;
+ }
+ if (!pinuvlist->next) {
+ pinuvlist->next = new_geo_uv_pinindex(handle, uv);
+ return;
+ }
+ pinuvlist = pinuvlist->next;
+ }
+}
+
static void p_add_ngon(ParamHandle *handle,
const ParamKey key,
const int nverts,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 6cf7f6f11e5..d59d2cb52fc 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -7,7 +7,7 @@
#include <stdio.h>
-#include "BLI_blenlib.h"
+#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
index f5ecce69129..092253dde79 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
@@ -8,10 +8,9 @@
#include <stdio.h>
#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
-#include "BLI_math.h"
-
#include "BLT_translation.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
index 38866bcd32a..407055c6165 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
@@ -9,14 +9,11 @@
#include "MEM_guardedalloc.h"
-#include "BLI_utildefines.h"
-
#include "BLI_hash.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLI_rand.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_rand.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
index 88515d849bc..cf390e8d3a0 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -7,14 +7,15 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "MEM_guardedalloc.h"
-#include "BLI_utildefines.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_math_vector.h"
#include "BLI_sort.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
index 792def30812..8ada66cfd55 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
@@ -9,7 +9,6 @@
#include "BLI_utildefines.h"
-#include "BLI_blenlib.h"
#include "BLI_math_color.h"
#include "BLI_math_vector.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
index f023b00480c..41015c429fe 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
@@ -9,7 +9,7 @@
#include <string.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_string.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
index e5604005240..0f1652a5620 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
@@ -8,8 +8,8 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_math_geom.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -22,7 +22,6 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
index bc0464cb4f9..652894af017 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -6,12 +6,14 @@
*/
#include <stdio.h>
+#include <string.h>
#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_math_matrix.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
-#include "BLI_math.h"
-
#include "BLT_translation.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
index c92c062348c..5a358f5b3a1 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
@@ -6,10 +6,11 @@
*/
#include <stdio.h>
+#include <string.h>
#include "BLI_hash.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_base.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index a07ef2eb195..f179713e8cb 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -7,9 +7,8 @@
#include <stdio.h>
-#include "BLI_utildefines.h"
-
#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -22,9 +21,6 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "MOD_gpencil_lineart.h"
-#include "lineart/MOD_lineart.h"
-
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -43,8 +39,10 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+#include "MOD_gpencil_lineart.h"
#include "MOD_gpencil_modifiertypes.h"
#include "MOD_gpencil_ui_common.h"
+#include "lineart/MOD_lineart.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -354,7 +352,7 @@ static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayout *sub = uiLayoutRowWithHeading(col, false, IFACE_("Crease"));
uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE);
uiLayout *entry = uiLayoutRow(sub, false);
- uiLayoutSetEnabled(entry, RNA_boolean_get(ptr, "use_crease") || is_first);
+ uiLayoutSetActive(entry, RNA_boolean_get(ptr, "use_crease") || is_first);
if (use_cache && !is_first) {
uiItemL(entry, IFACE_("Angle Cached"), ICON_INFO);
}
@@ -526,6 +524,7 @@ static void intersection_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "use_intersection_match", 0, IFACE_("Exact Match"), ICON_NONE);
}
+
static void face_mark_panel_draw_header(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
index 6460a69a6cc..df66251159c 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -10,7 +10,7 @@
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
index d80e32feb2e..fd4eb5da835 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
@@ -16,8 +16,8 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
index 259e62a249c..253603aea67 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -7,11 +7,10 @@
#include <stdio.h>
-#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
-
#include "BLI_hash.h"
+#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
index f201a147082..ba88c83161f 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
@@ -7,15 +7,14 @@
#include <stdio.h>
+#include "BLI_hash.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
-#include "BLI_hash.h"
-#include "BLI_math.h"
-#include "BLI_rand.h"
-
#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
index b964b143a0f..0bcbd71f029 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -6,12 +6,10 @@
*/
#include <stdio.h>
+#include <string.h>
#include "BLI_utildefines.h"
-#include "BLI_blenlib.h"
-#include "BLI_math_vector.h"
-
#include "BLT_translation.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
index 7de1cc89a45..cd2373dcb26 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
@@ -9,7 +9,7 @@
#include <string.h> /* For #MEMCPY_STRUCT_AFTER. */
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -18,7 +18,6 @@
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
index e7dfdfee8d2..07350b73ce3 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
@@ -16,7 +16,6 @@
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
-#include "DNA_vec_types.h"
#include "BKE_context.h"
#include "BKE_gpencil_geom.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
index 5c8c65b9f97..6ba7a934bff 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
index 3ddb508d58a..68fe15df898 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
index 8fa14496616..ad8804782e8 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -10,7 +10,7 @@
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h"
@@ -47,7 +47,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
static void initData(GpencilModifierData *md)
{
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c
index e90408b1a94..f40e6ba0728 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_defaults.h"
@@ -18,7 +18,6 @@
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
-#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
@@ -29,7 +28,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c
index d2c31591a98..1a6cadabf51 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_defaults.h"
@@ -29,7 +29,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index ad3e1b5d7f2..a72ce76d591 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -36,10 +36,10 @@ typedef struct LineartTriangle {
/* first culled in line list to use adjacent triangle info, then go through triangle list. */
double gn[3];
- unsigned char material_mask_bits;
- unsigned char intersection_mask;
- unsigned char mat_occlusion;
- unsigned char flags; /* #eLineartTriangleFlags */
+ uint8_t material_mask_bits;
+ uint8_t intersection_mask;
+ uint8_t mat_occlusion;
+ uint8_t flags; /* #eLineartTriangleFlags */
/**
* Only use single link list, because we don't need to go back in order.
@@ -84,10 +84,10 @@ typedef struct LineartEdgeSegment {
/** at==0: left at==1: right (this is in 2D projected space) */
double at;
/** Occlusion level after "at" point */
- unsigned char occlusion;
+ uint8_t occlusion;
/* Used to filter line art occlusion edges */
- unsigned char material_mask_bits;
+ uint8_t material_mask_bits;
} LineartEdgeSegment;
typedef struct LineartVert {
@@ -102,7 +102,7 @@ typedef struct LineartVert {
* size of the struct is extended to include intersection data.
* See #eLineArtVertFlags.
*/
- char flag;
+ uint8_t flag;
} LineartVert;
@@ -119,17 +119,14 @@ typedef enum eLineArtVertFlags {
} eLineArtVertFlags;
typedef struct LineartEdge {
- /** We only need link node kind of list here. */
- struct LineartEdge *next;
struct LineartVert *v1, *v2;
-
struct LineartTriangle *t1, *t2;
ListBase segments;
- char min_occ;
+ int8_t min_occ;
/** Also for line type determination on chaining. */
uint16_t flags;
- unsigned char intersection_mask;
+ uint8_t intersection_mask;
/**
* Still need this entry because culled lines will not add to object
@@ -149,15 +146,15 @@ typedef struct LineartEdgeChain {
float length;
/** Used when re-connecting and grease-pencil stroke generation. */
- char picked;
- char level;
+ int8_t picked;
+ int8_t level;
/** Chain now only contains one type of segments */
int type;
/** Will only connect chains that has the same loop id. */
int loop_id;
- unsigned char material_mask_bits;
- unsigned char intersection_mask;
+ uint8_t material_mask_bits;
+ uint8_t intersection_mask;
struct Object *object_ref;
} LineartEdgeChain;
@@ -170,9 +167,9 @@ typedef struct LineartEdgeChainItem {
float gpos[3];
float normal[3];
uint16_t line_type;
- char occlusion;
- unsigned char material_mask_bits;
- unsigned char intersection_mask;
+ int8_t occlusion;
+ uint8_t material_mask_bits;
+ uint8_t intersection_mask;
size_t index;
} LineartEdgeChainItem;
@@ -180,17 +177,17 @@ typedef struct LineartChainRegisterEntry {
struct LineartChainRegisterEntry *next, *prev;
LineartEdgeChain *ec;
LineartEdgeChainItem *eci;
- char picked;
+ int8_t picked;
/* left/right mark.
* Because we revert list in chaining so we need the flag. */
- char is_left;
+ int8_t is_left;
} LineartChainRegisterEntry;
typedef struct LineartAdjacentEdge {
- unsigned int v1;
- unsigned int v2;
- unsigned int e;
+ uint32_t v1;
+ uint32_t v2;
+ uint32_t e;
} LineartAdjacentEdge;
enum eLineArtTileRecursiveLimit {
@@ -210,49 +207,107 @@ typedef struct LineartPendingEdges {
int next;
} LineartPendingEdges;
-typedef struct LineartRenderBuffer {
- struct LineartRenderBuffer *prev, *next;
+typedef struct LineartData {
+ int w, h;
int thread_count;
+ int sizeof_triangle;
- int w, h;
- int tile_size_w, tile_size_h;
- int tile_count_x, tile_count_y;
- double width_per_tile, height_per_tile;
- double view_projection[4][4];
- double view[4][4];
+ LineartStaticMemPool render_data_pool;
+ /* A pointer to LineartCache::chain_data_pool, which acts as a cache for edge chains. */
+ LineartStaticMemPool *chain_data_pool;
- float overscan;
+ struct _qtree {
- struct LineartBoundingArea *initial_bounding_areas;
- unsigned int bounding_area_count;
+ int count_x, count_y;
+ double tile_width, tile_height;
- /* When splitting bounding areas, if there's an ortho camera placed at a straight angle, there
- * will be a lot of triangles aligned in line which can not be separated by continue subdividing
- * the tile. So we set a strict limit when using ortho camera. See eLineArtTileRecursiveLimit. */
- int tile_recursive_level;
+ /* When splitting bounding areas, if there's an ortho camera placed at a straight angle, there
+ * will be a lot of triangles aligned in line which can not be separated by continue
+ * subdividing the tile. So we set a strict limit when using ortho camera. See
+ * eLineArtTileRecursiveLimit. */
+ int recursive_level;
- ListBase vertex_buffer_pointers;
- ListBase line_buffer_pointers;
- ListBase triangle_buffer_pointers;
+ struct LineartBoundingArea *initials;
- /** This one's memory is not from main pool and is free()ed after culling stage. */
- ListBase triangle_adjacent_pointers;
+ uint32_t tile_count;
- ListBase intersecting_vertex_buffer;
- /** Use the one comes with Line Art. */
- LineartStaticMemPool render_data_pool;
- ListBase wasted_cuts;
- SpinLock lock_cuts;
+ } qtree;
- /* This is just a pointer to LineartCache::chain_data_pool, which acts as a cache for line
- * chains. */
- LineartStaticMemPool *chain_data_pool;
+ struct _geom {
+
+ ListBase vertex_buffer_pointers;
+ ListBase line_buffer_pointers;
+ ListBase triangle_buffer_pointers;
+
+ /** This one's memory is not from main pool and is free()ed after culling stage. */
+ ListBase triangle_adjacent_pointers;
+
+ ListBase intersecting_vertex_buffer;
+
+ } geom;
+
+ struct _conf {
+
+ double view_projection[4][4];
+ double view[4][4];
+
+ float overscan;
+
+ int max_occlusion_level;
+ double crease_angle;
+ double crease_cos;
- /* Render status */
- double view_vector[3];
+ int draw_material_preview;
+ double material_transparency;
- int triangle_size;
+ bool use_contour;
+ bool use_crease;
+ bool use_material;
+ bool use_edge_marks;
+ bool use_intersections;
+ bool use_loose;
+ bool fuzzy_intersections;
+ bool fuzzy_everything;
+ bool allow_boundaries;
+ bool allow_overlapping_edges;
+ bool allow_duplicated_types;
+ bool remove_doubles;
+ bool use_loose_as_contour;
+ bool use_loose_edge_chain;
+ bool use_geometry_space_chain;
+ bool use_image_boundary_trimming;
+ bool use_back_face_culling;
+
+ bool filter_face_mark;
+ bool filter_face_mark_invert;
+ bool filter_face_mark_boundaries;
+ bool filter_face_mark_keep_contour;
+
+ bool force_crease;
+ bool sharp_as_crease;
+
+ bool chain_preserve_details;
+
+ /* Keep an copy of these data so when line art is running it's self-contained. */
+ bool cam_is_persp;
+ float cam_obmat[4][4];
+ double camera_pos[3];
+ double active_camera_pos[3]; /* Stroke offset calculation may use active or selected camera. */
+ double near_clip, far_clip;
+ float shift_x, shift_y;
+ float crease_threshold;
+ float chaining_image_threshold;
+ float angle_splitting_threshold;
+
+ float chain_smooth_tolerance;
+
+ double view_vector[3];
+
+ } conf;
+
+ LineartElementLinkNode *isect_scheduled_up_to;
+ int isect_scheduled_up_to_index;
/* Note: Data inside #pending_edges are allocated with MEM_xxx call instead of in pool. */
struct LineartPendingEdges pending_edges;
@@ -260,79 +315,22 @@ typedef struct LineartRenderBuffer {
ListBase chains;
- /* For managing calculation tasks for multiple threads. */
+ ListBase wasted_cuts;
+ SpinLock lock_cuts;
SpinLock lock_task;
- /* settings */
-
- int max_occlusion_level;
- double crease_angle;
- double crease_cos;
-
- int draw_material_preview;
- double material_transparency;
-
- bool use_contour;
- bool use_crease;
- bool use_material;
- bool use_edge_marks;
- bool use_intersections;
- bool use_loose;
- bool fuzzy_intersections;
- bool fuzzy_everything;
- bool allow_boundaries;
- bool allow_overlapping_edges;
- bool allow_duplicated_types;
- bool remove_doubles;
- bool use_loose_as_contour;
- bool use_loose_edge_chain;
- bool use_geometry_space_chain;
- bool use_image_boundary_trimming;
- bool use_back_face_culling;
-
- bool filter_face_mark;
- bool filter_face_mark_invert;
- bool filter_face_mark_boundaries;
- bool filter_face_mark_keep_contour;
-
- bool force_crease;
- bool sharp_as_crease;
-
- bool chain_preserve_details;
-
- /* Keep an copy of these data so when line art is running it's self-contained. */
- bool cam_is_persp;
- float cam_obmat[4][4];
- double camera_pos[3];
- double active_camera_pos[3]; /* Stroke offset calculation may use active or selected camera. */
- double near_clip, far_clip;
- float shift_x, shift_y;
- float crease_threshold;
- float chaining_image_threshold;
- float angle_splitting_threshold;
-
- float chain_smooth_tolerance;
-
- /* FIXME(Yiming): Temporary solution for speeding up calculation by not including lines that
- * are not in the selected source. This will not be needed after we have a proper scene-wise
- * cache running because multiple modifiers can then select results from that without further
- * calculation. */
- int _source_type;
- struct Collection *_source_collection;
- struct Object *_source_object;
-
-} LineartRenderBuffer;
+} LineartData;
typedef struct LineartCache {
/** Separate memory pool for chain data, this goes to the cache, so when we free the main pool,
* chains will still be available. */
LineartStaticMemPool chain_data_pool;
- /** A copy of rb->chains so we have that data available after rb has been destroyed. */
+ /** A copy of ld->chains so we have that data available after ld has been destroyed. */
ListBase chains;
/** Cache only contains edge types specified in this variable. */
- char rb_edge_types;
+ int8_t rb_edge_types;
} LineartCache;
#define DBL_TRIANGLE_LIM 1e-8
@@ -358,13 +356,13 @@ typedef enum eLineartTriangleFlags {
#define LRT_THREAD_EDGE_COUNT 1000
typedef struct LineartRenderTaskInfo {
- struct LineartRenderBuffer *rb;
+ struct LineartData *ld;
int thread_id;
/**
* #pending_edges here only stores a reference to a portion in
- * LineartRenderbuffer::pending_edges, assigned by the occlusion scheduler.
+ * LineartData::pending_edges, assigned by the occlusion scheduler.
*/
struct LineartPendingEdges pending_edges;
@@ -390,12 +388,12 @@ typedef struct LineartObjectInfo {
} LineartObjectInfo;
typedef struct LineartObjectLoadTaskInfo {
- struct LineartRenderBuffer *rb;
+ struct LineartData *ld;
int thread_id;
/* LinkNode styled list */
LineartObjectInfo *pending;
/* Used to spread the load across several threads. This can not overflow. */
- long unsigned int total_faces;
+ uint64_t total_faces;
} LineartObjectLoadTaskInfo;
/**
@@ -429,15 +427,18 @@ typedef struct LineartBoundingArea {
/** 1,2,3,4 quadrant */
struct LineartBoundingArea *child;
+ SpinLock lock;
+
ListBase lp;
ListBase rp;
ListBase up;
ListBase bp;
- uint16_t triangle_count;
- uint16_t max_triangle_count;
- uint16_t line_count;
- uint16_t max_line_count;
+ uint32_t triangle_count;
+ uint32_t max_triangle_count;
+ uint32_t line_count;
+ uint32_t max_line_count;
+ uint32_t user_count;
/* Use array for speeding up multiple accesses. */
struct LineartTriangle **linked_triangles;
@@ -459,9 +460,6 @@ typedef struct LineartBoundingArea {
#define LRT_MIN3_INDEX_ABC(x, y, z) (x < y ? (x < z ? a : (y < z ? b : c)) : (y < z ? b : c))
-#define LRT_ABC(index) (index == 0 ? a : (index == 1 ? b : c))
-#define LRT_PABC(index) (index == 0 ? pa : (index == 1 ? pb : pc))
-
#define DBL_LOOSER 1e-5
#define LRT_DOUBLE_CLOSE_LOOSER(a, b) (((a) + DBL_LOOSER) >= (b) && ((a)-DBL_LOOSER) <= (b))
#define LRT_DOUBLE_CLOSE_ENOUGH(a, b) (((a) + DBL_EDGE_LIM) >= (b) && ((a)-DBL_EDGE_LIM) <= (b))
@@ -626,30 +624,28 @@ BLI_INLINE int lineart_intersect_seg_seg(const double *a1,
struct Depsgraph;
struct LineartGpencilModifierData;
-struct LineartRenderBuffer;
+struct LineartData;
struct Scene;
void MOD_lineart_destroy_render_data(struct LineartGpencilModifierData *lmd);
-void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb);
-void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb);
+void MOD_lineart_chain_feature_lines(LineartData *ld);
+void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld);
/**
* This function only connects two different chains. It will not do any clean up or smart chaining.
* So no: removing overlapping chains, removal of short isolated segments, and no loop reduction is
* implemented yet.
*/
-void MOD_lineart_chain_connect(LineartRenderBuffer *rb);
-void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, float threshold);
-void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb);
+void MOD_lineart_chain_connect(LineartData *ld);
+void MOD_lineart_chain_discard_short(LineartData *ld, float threshold);
+void MOD_lineart_chain_clip_at_border(LineartData *ld);
/**
* This should always be the last stage!, see the end of
* #MOD_lineart_chain_split_for_fixed_occlusion().
*/
-void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad);
-void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance);
-void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
- float dist,
- bool use_custom_camera);
+void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad);
+void MOD_lineart_smooth_chains(LineartData *ld, float tolerance);
+void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool use_custom_camera);
int MOD_lineart_chain_count(const LineartEdgeChain *ec);
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc);
@@ -669,14 +665,12 @@ struct Scene;
/**
* This only gets initial "biggest" tile.
*/
-LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
- double x,
- double y);
+LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartData *ld, double x, double y);
/**
* Wrapper for more convenience.
*/
-LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y);
+LineartBoundingArea *MOD_lineart_get_bounding_area(LineartData *ld, double x, double y);
struct bGPDframe;
struct bGPDlayer;
@@ -689,16 +683,16 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
struct Object *ob,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
- char source_type,
+ int8_t source_type,
void *source_reference,
int level_start,
int level_end,
int mat_nr,
- short edge_types,
- unsigned char mask_switches,
- unsigned char material_mask_bits,
- unsigned char intersection_mask,
- short thickness,
+ int16_t edge_types,
+ uint8_t mask_switches,
+ uint8_t material_mask_bits,
+ uint8_t intersection_mask,
+ int16_t thickness,
float opacity,
const char *source_vgname,
const char *vgname,
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index 226b8f532b5..1d84bb8e232 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -23,7 +23,7 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
LineartVert *vt,
LineartVert **new_vt,
int match_flag,
- unsigned char match_isec_mask)
+ uint8_t match_isec_mask)
{
for (int i = 0; i < ba->line_count; i++) {
LineartEdge *n_e = ba->linked_lines[i];
@@ -60,12 +60,12 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
return NULL;
}
-static LineartEdgeChain *lineart_chain_create(LineartRenderBuffer *rb)
+static LineartEdgeChain *lineart_chain_create(LineartData *ld)
{
LineartEdgeChain *ec;
- ec = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChain));
+ ec = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChain));
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
return ec;
}
@@ -85,14 +85,14 @@ static bool lineart_point_overlapping(LineartEdgeChainItem *eci,
return false;
}
-static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
+static LineartEdgeChainItem *lineart_chain_append_point(LineartData *ld,
LineartEdgeChain *ec,
float *fbcoord,
float *gpos,
float *normal,
- char type,
+ uint8_t type,
int level,
- unsigned char material_mask_bits,
+ uint8_t material_mask_bits,
size_t index)
{
LineartEdgeChainItem *eci;
@@ -108,7 +108,7 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
return old_eci;
}
- eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
+ eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem));
copy_v4_v4(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
@@ -122,14 +122,14 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
return eci;
}
-static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb,
+static LineartEdgeChainItem *lineart_chain_prepend_point(LineartData *ld,
LineartEdgeChain *ec,
float *fbcoord,
float *gpos,
float *normal,
- char type,
+ uint8_t type,
int level,
- unsigned char material_mask_bits,
+ uint8_t material_mask_bits,
size_t index)
{
LineartEdgeChainItem *eci;
@@ -138,7 +138,7 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb
return ec->chain.first;
}
- eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
+ eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem));
copy_v4_v4(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
@@ -152,14 +152,14 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb
return eci;
}
-void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
+void MOD_lineart_chain_feature_lines(LineartData *ld)
{
LineartEdgeChain *ec;
LineartEdgeChainItem *eci;
LineartBoundingArea *ba;
LineartEdgeSegment *es;
int last_occlusion;
- unsigned char last_transparency;
+ uint8_t last_transparency;
/* Used when converting from double. */
float use_fbcoord[4];
float use_gpos[3];
@@ -181,7 +181,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
- ec = lineart_chain_create(rb);
+ ec = lineart_chain_create(ld);
/* One chain can only have one object_ref and intersection_mask,
* so we assign them based on the first segment we found. */
@@ -207,11 +207,11 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
}
/* Step 1: grow left. */
- ba = MOD_lineart_get_bounding_area(rb, e->v1->fbcoord[0], e->v1->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, e->v1->fbcoord[0], e->v1->fbcoord[1]);
new_vt = e->v1;
es = e->segments.first;
VERT_COORD_TO_FLOAT(new_vt);
- lineart_chain_prepend_point(rb,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -248,7 +248,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
- lineart_chain_prepend_point(rb,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -274,7 +274,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
- lineart_chain_prepend_point(rb,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -287,7 +287,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
last_transparency = es->material_mask_bits;
}
VERT_COORD_TO_FLOAT(new_e->v2);
- lineart_chain_prepend_point(rb,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -297,7 +297,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
last_transparency,
new_e->v2->index);
}
- ba = MOD_lineart_get_bounding_area(rb, new_vt->fbcoord[0], new_vt->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]);
}
/* Restore normal value. */
@@ -328,7 +328,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
interp_v3_v3v3_db(gpos, e->v1->gloc, e->v2->gloc, global_at);
use_fbcoord[3] = interpf(e->v2->fbcoord[3], e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -341,7 +341,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
last_transparency = es->material_mask_bits;
}
VERT_COORD_TO_FLOAT(e->v2)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -352,7 +352,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
e->v2->index);
/* Step 3: grow right. */
- ba = MOD_lineart_get_bounding_area(rb, e->v2->fbcoord[0], e->v2->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, e->v2->fbcoord[0], e->v2->fbcoord[1]);
new_vt = e->v2;
while (ba && (new_e = lineart_line_get_connected(
ba, new_vt, &new_vt, e->flags, e->intersection_mask))) {
@@ -394,7 +394,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
last_occlusion = es->prev ? es->prev->occlusion : last_occlusion;
last_transparency = es->prev ? es->prev->material_mask_bits : last_transparency;
POS_TO_FLOAT(lpos, gpos)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -420,7 +420,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -433,7 +433,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
last_transparency = es->material_mask_bits;
}
VERT_COORD_TO_FLOAT(new_e->v2)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -443,9 +443,9 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
last_transparency,
new_e->v2->index);
}
- ba = MOD_lineart_get_bounding_area(rb, new_vt->fbcoord[0], new_vt->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]);
}
- if (rb->fuzzy_everything) {
+ if (ld->conf.fuzzy_everything) {
ec->type = LRT_EDGE_FLAG_CONTOUR;
}
else {
@@ -455,7 +455,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
LRT_ITER_ALL_LINES_END
}
-static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartRenderBuffer *rb,
+static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartData *ld,
LineartBoundingArea *root,
LineartEdgeChainItem *eci)
{
@@ -468,32 +468,32 @@ static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartRende
ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1]
if (IN_BOUND(ch[0], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[0], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[0], eci);
}
if (IN_BOUND(ch[1], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[1], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[1], eci);
}
if (IN_BOUND(ch[2], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[2], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[2], eci);
}
if (IN_BOUND(ch[3], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[3], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[3], eci);
}
#undef IN_BOUND
return NULL;
}
-static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartRenderBuffer *rb,
+static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartData *ld,
LineartEdgeChainItem *eci)
{
if (!eci) {
return NULL;
}
- LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(rb, eci->pos[0], eci->pos[1]);
+ LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(ld, eci->pos[0], eci->pos[1]);
if (root == NULL) {
return NULL;
}
- return lineart_bounding_area_get_eci_recursive(rb, root, eci);
+ return lineart_bounding_area_get_eci_recursive(ld, root, eci);
}
/**
@@ -502,14 +502,14 @@ static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartRenderBuf
* areas, this happens either when 1) the geometry is way too dense, or 2) the chaining threshold
* is too big that it covers multiple small bounding areas.
*/
-static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb,
+static void lineart_bounding_area_link_point_recursive(LineartData *ld,
LineartBoundingArea *root,
LineartEdgeChain *ec,
LineartEdgeChainItem *eci)
{
if (root->child == NULL) {
LineartChainRegisterEntry *cre = lineart_list_append_pointer_pool_sized(
- &root->linked_chains, &rb->render_data_pool, ec, sizeof(LineartChainRegisterEntry));
+ &root->linked_chains, &ld->render_data_pool, ec, sizeof(LineartChainRegisterEntry));
cre->eci = eci;
@@ -524,34 +524,34 @@ static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb,
ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1]
if (IN_BOUND(ch[0], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[0], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[0], ec, eci);
}
else if (IN_BOUND(ch[1], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[1], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[1], ec, eci);
}
else if (IN_BOUND(ch[2], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[2], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[2], ec, eci);
}
else if (IN_BOUND(ch[3], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[3], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[3], ec, eci);
}
#undef IN_BOUND
}
}
-static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartEdgeChain *ec)
+static void lineart_bounding_area_link_chain(LineartData *ld, LineartEdgeChain *ec)
{
LineartEdgeChainItem *pl = ec->chain.first;
LineartEdgeChainItem *pr = ec->chain.last;
- LineartBoundingArea *ba1 = MOD_lineart_get_parent_bounding_area(rb, pl->pos[0], pl->pos[1]);
- LineartBoundingArea *ba2 = MOD_lineart_get_parent_bounding_area(rb, pr->pos[0], pr->pos[1]);
+ LineartBoundingArea *ba1 = MOD_lineart_get_parent_bounding_area(ld, pl->pos[0], pl->pos[1]);
+ LineartBoundingArea *ba2 = MOD_lineart_get_parent_bounding_area(ld, pr->pos[0], pr->pos[1]);
if (ba1) {
- lineart_bounding_area_link_point_recursive(rb, ba1, ec, pl);
+ lineart_bounding_area_link_point_recursive(ld, ba1, ec, pl);
}
if (ba2) {
- lineart_bounding_area_link_point_recursive(rb, ba2, ec, pr);
+ lineart_bounding_area_link_point_recursive(ld, ba2, ec, pr);
}
}
@@ -564,7 +564,7 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
float dist_accum = 0;
int fixed_occ = last_matching_eci->occlusion;
- unsigned char fixed_mask = last_matching_eci->material_mask_bits;
+ uint8_t fixed_mask = last_matching_eci->material_mask_bits;
LineartEdgeChainItem *can_skip_to = NULL;
LineartEdgeChainItem *last_eci = last_matching_eci;
@@ -606,28 +606,28 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
return false;
}
-void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
+void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld)
{
LineartEdgeChain *ec, *new_ec;
LineartEdgeChainItem *eci, *next_eci;
ListBase swap = {0};
- swap.first = rb->chains.first;
- swap.last = rb->chains.last;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->chains.first = NULL;
int loop_id = 0;
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
ec->loop_id = loop_id;
loop_id++;
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
int fixed_occ = first_eci->occlusion;
- unsigned char fixed_mask = first_eci->material_mask_bits;
+ uint8_t fixed_mask = first_eci->material_mask_bits;
ec->level = fixed_occ;
ec->material_mask_bits = fixed_mask;
for (eci = first_eci->next; eci; eci = next_eci) {
@@ -639,8 +639,8 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
}
if (lineart_chain_fix_ambiguous_segments(ec,
eci->prev,
- rb->chaining_image_threshold,
- rb->chain_preserve_details,
+ ld->conf.chaining_image_threshold,
+ ld->conf.chain_preserve_details,
&next_eci)) {
continue;
}
@@ -653,7 +653,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
/* No need to split at the last point anyway. */
break;
}
- new_ec = lineart_chain_create(rb);
+ new_ec = lineart_chain_create(ld);
new_ec->chain.first = eci;
new_ec->chain.last = ec->chain.last;
new_ec->loop_id = loop_id;
@@ -662,7 +662,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
eci->prev = 0;
/* End the previous one. */
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
eci->pos,
eci->gpos,
@@ -683,16 +683,16 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
}
}
/* Get rid of those very short "zig-zag" lines that jumps around visibility. */
- MOD_lineart_chain_discard_short(rb, DBL_EDGE_LIM);
- LISTBASE_FOREACH (LineartEdgeChain *, iec, &rb->chains) {
- lineart_bounding_area_link_chain(rb, iec);
+ MOD_lineart_chain_discard_short(ld, DBL_EDGE_LIM);
+ LISTBASE_FOREACH (LineartEdgeChain *, iec, &ld->chains) {
+ lineart_bounding_area_link_chain(ld, iec);
}
}
/**
* NOTE: segment type (crease/material/contour...) is ambiguous after this.
*/
-static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb),
+static void lineart_chain_connect(LineartData *UNUSED(ld),
LineartEdgeChain *onto,
LineartEdgeChain *sub,
int reverse_1,
@@ -742,13 +742,13 @@ static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb),
}
}
-static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuffer *rb,
+static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartData *ld,
LineartBoundingArea *ba,
LineartEdgeChain *ec,
LineartEdgeChainItem *eci,
int occlusion,
- unsigned char material_mask_bits,
- unsigned char isec_mask,
+ uint8_t material_mask_bits,
+ uint8_t isec_mask,
int loop_id,
float dist,
float *result_new_len,
@@ -761,8 +761,8 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
* next one. */
LISTBASE_FOREACH_MUTABLE (LineartChainRegisterEntry *, cre, &ba->linked_chains) {
if (cre->ec->object_ref != ec->object_ref) {
- if (!rb->fuzzy_everything) {
- if (rb->fuzzy_intersections) {
+ if (!ld->conf.fuzzy_everything) {
+ if (ld->conf.fuzzy_intersections) {
/* If none of those are intersection lines... */
if ((!(cre->ec->type & LRT_EDGE_FLAG_INTERSECTION)) &&
(!(ec->type & LRT_EDGE_FLAG_INTERSECTION))) {
@@ -782,9 +782,9 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
(cre->ec->intersection_mask != isec_mask)) {
continue;
}
- if (!rb->fuzzy_everything) {
+ if (!ld->conf.fuzzy_everything) {
if (cre->ec->type != ec->type) {
- if (rb->fuzzy_intersections) {
+ if (ld->conf.fuzzy_intersections) {
if (!(cre->ec->type == LRT_EDGE_FLAG_INTERSECTION ||
ec->type == LRT_EDGE_FLAG_INTERSECTION)) {
continue; /* Fuzzy intersections but no intersection line found. */
@@ -796,8 +796,8 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
}
}
- float new_len = rb->use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) :
- len_v2v2(cre->eci->pos, eci->pos);
+ float new_len = ld->conf.use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) :
+ len_v2v2(cre->eci->pos, eci->pos);
/* Even if the vertex is not from the same contour loop, we try to chain it still if the
* distance is small enough. This way we can better chain smaller loops and smooth them out
* later. */
@@ -817,9 +817,9 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
#define LRT_TEST_ADJACENT_AREAS(dist_to, list) \
if (dist_to < dist && dist_to > 0) { \
- LISTBASE_FOREACH (LinkData *, ld, list) { \
- LineartBoundingArea *sba = (LineartBoundingArea *)ld->data; \
- adjacent_closest = lineart_chain_get_closest_cre(rb, \
+ LISTBASE_FOREACH (LinkData *, link, list) { \
+ LineartBoundingArea *sba = (LineartBoundingArea *)link->data; \
+ adjacent_closest = lineart_chain_get_closest_cre(ld, \
sba, \
ec, \
eci, \
@@ -848,36 +848,36 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
return closest_cre;
}
-void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
+void MOD_lineart_chain_connect(LineartData *ld)
{
LineartEdgeChain *ec;
LineartEdgeChainItem *eci_l, *eci_r;
LineartBoundingArea *ba_l, *ba_r;
LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre;
- float dist = rb->chaining_image_threshold;
+ float dist = ld->conf.chaining_image_threshold;
float dist_l, dist_r;
int occlusion, reverse_main, loop_id;
- unsigned char material_mask_bits, isec_mask;
+ uint8_t material_mask_bits, isec_mask;
ListBase swap = {0};
- if (rb->chaining_image_threshold < 0.0001) {
+ if (ld->conf.chaining_image_threshold < 0.0001) {
return;
}
- swap.first = rb->chains.first;
- swap.last = rb->chains.last;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->chains.first = NULL;
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
if (ec->picked) {
continue;
}
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
loop_id = ec->loop_id;
- if (ec->type == LRT_EDGE_FLAG_LOOSE && (!rb->use_loose_edge_chain)) {
+ if (ec->type == LRT_EDGE_FLAG_LOOSE && (!ld->conf.use_loose_edge_chain)) {
continue;
}
@@ -887,9 +887,9 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
eci_l = ec->chain.first;
eci_r = ec->chain.last;
- while ((ba_l = lineart_bounding_area_get_end_point(rb, eci_l)) &&
- (ba_r = lineart_bounding_area_get_end_point(rb, eci_r))) {
- closest_cre_l = lineart_chain_get_closest_cre(rb,
+ while ((ba_l = lineart_bounding_area_get_end_point(ld, eci_l)) &&
+ (ba_r = lineart_bounding_area_get_end_point(ld, eci_r))) {
+ closest_cre_l = lineart_chain_get_closest_cre(ld,
ba_l,
ec,
eci_l,
@@ -900,7 +900,7 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
dist,
&dist_l,
NULL);
- closest_cre_r = lineart_chain_get_closest_cre(rb,
+ closest_cre_r = lineart_chain_get_closest_cre(ld,
ba_r,
ec,
eci_r,
@@ -936,10 +936,10 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
closest_cre->picked = 1;
closest_cre->ec->picked = 1;
if (closest_cre->is_left) {
- lineart_chain_connect(rb, ec, closest_cre->ec, reverse_main, 0);
+ lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 0);
}
else {
- lineart_chain_connect(rb, ec, closest_cre->ec, reverse_main, 1);
+ lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 1);
}
BLI_remlink(&swap, closest_cre->ec);
eci_l = ec->chain.first;
@@ -969,13 +969,13 @@ float MOD_lineart_chain_compute_length(LineartEdgeChain *ec)
return offset_accum;
}
-void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold)
+void MOD_lineart_chain_discard_short(LineartData *ld, const float threshold)
{
LineartEdgeChain *ec, *next_ec;
- for (ec = rb->chains.first; ec; ec = next_ec) {
+ for (ec = ld->chains.first; ec; ec = next_ec) {
next_ec = ec->next;
if (MOD_lineart_chain_compute_length(ec) < threshold) {
- BLI_remlink(&rb->chains, ec);
+ BLI_remlink(&ld->chains, ec);
}
}
}
@@ -999,9 +999,9 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
}
}
-void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
+void MOD_lineart_smooth_chains(LineartData *ld, float tolerance)
{
- LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
/* Go through the chain two times, once from each direction. */
for (int times = 0; times < 2; times++) {
for (LineartEdgeChainItem *eci = ec->chain.first, *next_eci = eci->next; eci;
@@ -1067,7 +1067,7 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
}
}
-static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBuffer *rb,
+static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartData *ld,
LineartEdgeChainItem *eci_inside,
LineartEdgeChainItem *eci_outside)
{
@@ -1097,7 +1097,7 @@ static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBu
ratiof(eci1->pos[1], eci2->pos[1], isec[1]);
float gratio = eci1->pos[3] * ratio / (ratio * eci1->pos[3] + (1 - ratio) * eci2->pos[3]);
- LineartEdgeChainItem *eci = lineart_mem_acquire(rb->chain_data_pool,
+ LineartEdgeChainItem *eci = lineart_mem_acquire(ld->chain_data_pool,
sizeof(LineartEdgeChainItem));
memcpy(eci, eci1, sizeof(LineartEdgeChainItem));
interp_v3_v3v3(eci->gpos, eci1->gpos, eci2->gpos, gratio);
@@ -1111,16 +1111,16 @@ static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBu
((eci)->pos[0] >= -1.0f && (eci)->pos[0] <= 1.0f && (eci)->pos[1] >= -1.0f && \
(eci)->pos[1] <= 1.0f)
-void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
+void MOD_lineart_chain_clip_at_border(LineartData *ld)
{
LineartEdgeChain *ec;
LineartEdgeChainItem *eci, *next_eci, *prev_eci, *new_eci;
bool is_inside, new_inside;
ListBase swap = {0};
- swap.first = rb->chains.first;
- swap.last = rb->chains.last;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->chains.first = NULL;
while ((ec = BLI_pophead(&swap)) != NULL) {
bool ec_added = false;
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
@@ -1137,9 +1137,9 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
if ((new_inside = LRT_ECI_INSIDE(eci)) != is_inside) {
if (new_inside == false) {
/* Stroke goes out. */
- new_eci = lineart_chain_create_crossing_point(rb, prev_eci, eci);
+ new_eci = lineart_chain_create_crossing_point(ld, prev_eci, eci);
- LineartEdgeChain *new_ec = lineart_mem_acquire(rb->chain_data_pool,
+ LineartEdgeChain *new_ec = lineart_mem_acquire(ld->chain_data_pool,
sizeof(LineartEdgeChain));
memcpy(new_ec, ec, sizeof(LineartEdgeChain));
new_ec->chain.first = next_eci;
@@ -1147,7 +1147,7 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
prev_eci->next = NULL;
ec->chain.last = prev_eci;
BLI_addtail(&ec->chain, new_eci);
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
ec_added = true;
ec = new_ec;
@@ -1156,7 +1156,7 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
continue;
}
/* Stroke comes in. */
- new_eci = lineart_chain_create_crossing_point(rb, eci, prev_eci);
+ new_eci = lineart_chain_create_crossing_point(ld, eci, prev_eci);
ec->chain.first = eci;
eci->prev = NULL;
@@ -1172,25 +1172,25 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
}
if ((!ec_added) && is_inside) {
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
}
}
}
-void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad)
+void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad)
{
LineartEdgeChain *ec, *new_ec;
LineartEdgeChainItem *eci, *next_eci, *prev_eci;
ListBase swap = {0};
- swap.first = rb->chains.first;
- swap.last = rb->chains.last;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->chains.first = NULL;
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
for (eci = first_eci->next; eci; eci = next_eci) {
next_eci = eci->next;
@@ -1203,7 +1203,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
break; /* No need to split at the last point anyway. */
}
if (angle < angle_threshold_rad) {
- new_ec = lineart_chain_create(rb);
+ new_ec = lineart_chain_create(ld);
new_ec->chain.first = eci;
new_ec->chain.last = ec->chain.last;
ec->chain.last = eci->prev;
@@ -1211,7 +1211,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
eci->prev = 0;
/* End the previous one. */
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
eci->pos,
eci->gpos,
@@ -1232,40 +1232,37 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
}
}
-void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
- float dist,
- bool use_custom_camera)
+void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool use_custom_camera)
{
float dir[3];
float cam[3];
float view[3];
float view_clamp[3];
- copy_v3fl_v3db(cam, rb->camera_pos);
- copy_v3fl_v3db(view, rb->view_vector);
if (use_custom_camera) {
- copy_v3fl_v3db(cam, rb->camera_pos);
+ copy_v3fl_v3db(cam, ld->conf.camera_pos);
}
else {
- copy_v3fl_v3db(cam, rb->active_camera_pos);
+ copy_v3fl_v3db(cam, ld->conf.active_camera_pos);
}
- if (rb->cam_is_persp) {
- LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ if (ld->conf.cam_is_persp) {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
sub_v3_v3v3(dir, cam, eci->gpos);
float orig_len = len_v3(dir);
normalize_v3(dir);
- mul_v3_fl(dir, MIN2(dist, orig_len - rb->near_clip));
+ mul_v3_fl(dir, MIN2(dist, orig_len - ld->conf.near_clip));
add_v3_v3(eci->gpos, dir);
}
}
}
else {
- LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ copy_v3fl_v3db(view, ld->conf.view_vector);
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
sub_v3_v3v3(dir, cam, eci->gpos);
- float len_lim = dot_v3v3(view, dir) - rb->near_clip;
+ float len_lim = dot_v3v3(view, dir) - ld->conf.near_clip;
normalize_v3_v3(view_clamp, view);
mul_v3_fl(view_clamp, MIN2(dist, len_lim));
add_v3_v3(eci->gpos, view_clamp);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index aae439c62a2..c08bf3e0fe9 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -46,16 +46,41 @@
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
-#include "bmesh.h"
-#include "bmesh_class.h"
-#include "bmesh_tools.h"
-
#include "lineart_intern.h"
-static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer *rb,
- LineartEdge *e);
+typedef struct LineartIsecSingle {
+ float v1[3], v2[3];
+ LineartTriangle *tri1, *tri2;
+} LineartIsecSingle;
+
+typedef struct LineartIsecThread {
+ int thread_id;
+
+ /* Scheduled work range. */
+ LineartElementLinkNode *pending_from;
+ LineartElementLinkNode *pending_to;
+ int index_from;
+ int index_to;
+
+ /* Thread intersection result data. */
+ LineartIsecSingle *array;
+ int current;
+ int max;
+ int count_test;
-static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb,
+ /* For individual thread reference.*/
+ LineartData *ld;
+} LineartIsecThread;
+
+typedef struct LineartIsecData {
+ LineartData *ld;
+ LineartIsecThread *threads;
+ int thread_count;
+} LineartIsecData;
+
+static LineartBoundingArea *lineart_edge_first_bounding_area(LineartData *ld, LineartEdge *e);
+
+static void lineart_bounding_area_link_edge(LineartData *ld,
LineartBoundingArea *root_ba,
LineartEdge *e);
@@ -69,20 +94,8 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
double *next_x,
double *next_y);
-static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
- LineartEdge *e,
- int *rowbegin,
- int *rowend,
- int *colbegin,
- int *colend);
-
-static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
- LineartBoundingArea *root_ba,
- LineartTriangle *tri,
- double *LRUB,
- int recursive,
- int recursive_level,
- bool do_intersection);
+static bool lineart_get_edge_bounding_areas(
+ LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend);
static bool lineart_triangle_edge_image_space_occlusion(SpinLock *spl,
const LineartTriangle *tri,
@@ -99,52 +112,65 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *spl,
static void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e);
+static void lineart_bounding_area_link_triangle(LineartData *ld,
+ LineartBoundingArea *root_ba,
+ LineartTriangle *tri,
+ double *LRUB,
+ int recursive,
+ int recursive_level,
+ bool do_intersection,
+ struct LineartIsecThread *th);
+
+static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive);
+
+static void lineart_free_bounding_area_memories(LineartData *ld);
+
static LineartCache *lineart_init_cache(void);
-static void lineart_discard_segment(LineartRenderBuffer *rb, LineartEdgeSegment *es)
+static void lineart_discard_segment(LineartData *ld, LineartEdgeSegment *es)
{
- BLI_spin_lock(&rb->lock_cuts);
+ BLI_spin_lock(&ld->lock_cuts);
memset(es, 0, sizeof(LineartEdgeSegment));
/* Storing the node for potentially reuse the memory for new segment data.
* Line Art data is not freed after all calculations are done. */
- BLI_addtail(&rb->wasted_cuts, es);
+ BLI_addtail(&ld->wasted_cuts, es);
- BLI_spin_unlock(&rb->lock_cuts);
+ BLI_spin_unlock(&ld->lock_cuts);
}
-static LineartEdgeSegment *lineart_give_segment(LineartRenderBuffer *rb)
+static LineartEdgeSegment *lineart_give_segment(LineartData *ld)
{
- BLI_spin_lock(&rb->lock_cuts);
+ BLI_spin_lock(&ld->lock_cuts);
/* See if there is any already allocated memory we can reuse. */
- if (rb->wasted_cuts.first) {
- LineartEdgeSegment *es = (LineartEdgeSegment *)BLI_pophead(&rb->wasted_cuts);
- BLI_spin_unlock(&rb->lock_cuts);
+ if (ld->wasted_cuts.first) {
+ LineartEdgeSegment *es = (LineartEdgeSegment *)BLI_pophead(&ld->wasted_cuts);
+ BLI_spin_unlock(&ld->lock_cuts);
memset(es, 0, sizeof(LineartEdgeSegment));
return es;
}
- BLI_spin_unlock(&rb->lock_cuts);
+ BLI_spin_unlock(&ld->lock_cuts);
/* Otherwise allocate some new memory. */
- return (LineartEdgeSegment *)lineart_mem_acquire_thread(&rb->render_data_pool,
+ return (LineartEdgeSegment *)lineart_mem_acquire_thread(&ld->render_data_pool,
sizeof(LineartEdgeSegment));
}
/**
* Cuts the edge in image space and mark occlusion level for each segment.
*/
-static void lineart_edge_cut(LineartRenderBuffer *rb,
+static void lineart_edge_cut(LineartData *ld,
LineartEdge *e,
double start,
double end,
uchar material_mask_bits,
uchar mat_occlusion)
{
- LineartEdgeSegment *es, *ies, *next_es, *prev_es;
+ LineartEdgeSegment *seg, *i_seg, *next_seg, *prev_seg;
LineartEdgeSegment *cut_start_before = 0, *cut_end_before = 0;
- LineartEdgeSegment *ns = 0, *ns2 = 0;
+ LineartEdgeSegment *new_seg1 = 0, *new_seg2 = 0;
int untouched = 0;
/* If for some reason the occlusion function may give a result that has zero length, or reversed
@@ -171,132 +197,136 @@ static void lineart_edge_cut(LineartRenderBuffer *rb,
/* Begin looking for starting position of the segment. */
/* Not using a list iteration macro because of it more clear when using for loops to iterate
* through the segments. */
- for (es = e->segments.first; es; es = es->next) {
- if (LRT_DOUBLE_CLOSE_ENOUGH(es->at, start)) {
- cut_start_before = es;
- ns = cut_start_before;
+ for (seg = e->segments.first; seg; seg = seg->next) {
+ if (LRT_DOUBLE_CLOSE_ENOUGH(seg->at, start)) {
+ cut_start_before = seg;
+ new_seg1 = cut_start_before;
break;
}
- if (es->next == NULL) {
+ if (seg->next == NULL) {
break;
}
- ies = es->next;
- if (ies->at > start + 1e-09 && start > es->at) {
- cut_start_before = ies;
- ns = lineart_give_segment(rb);
+ i_seg = seg->next;
+ if (i_seg->at > start + 1e-09 && start > seg->at) {
+ cut_start_before = i_seg;
+ new_seg1 = lineart_give_segment(ld);
break;
}
}
if (!cut_start_before && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
untouched = 1;
}
- for (es = cut_start_before; es; es = es->next) {
+ for (seg = cut_start_before; seg; seg = seg->next) {
/* We tried to cut at existing cutting point (e.g. where the line's occluded by a triangle
* strip). */
- if (LRT_DOUBLE_CLOSE_ENOUGH(es->at, end)) {
- cut_end_before = es;
- ns2 = cut_end_before;
+ if (LRT_DOUBLE_CLOSE_ENOUGH(seg->at, end)) {
+ cut_end_before = seg;
+ new_seg2 = cut_end_before;
break;
}
/* This check is to prevent `es->at == 1.0` (where we don't need to cut because we are at the
* end point). */
- if (!es->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
- cut_end_before = es;
- ns2 = cut_end_before;
+ if (!seg->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
+ cut_end_before = seg;
+ new_seg2 = cut_end_before;
untouched = 1;
break;
}
/* When an actual cut is needed in the line. */
- if (es->at > end) {
- cut_end_before = es;
- ns2 = lineart_give_segment(rb);
+ if (seg->at > end) {
+ cut_end_before = seg;
+ new_seg2 = lineart_give_segment(ld);
break;
}
}
/* When we still can't find any existing cut in the line, we allocate new ones. */
- if (ns == NULL) {
- ns = lineart_give_segment(rb);
+ if (new_seg1 == NULL) {
+ new_seg1 = lineart_give_segment(ld);
}
- if (ns2 == NULL) {
+ if (new_seg2 == NULL) {
if (untouched) {
- ns2 = ns;
- cut_end_before = ns2;
+ new_seg2 = new_seg1;
+ cut_end_before = new_seg2;
}
else {
- ns2 = lineart_give_segment(rb);
+ new_seg2 = lineart_give_segment(ld);
}
}
if (cut_start_before) {
- if (cut_start_before != ns) {
+ if (cut_start_before != new_seg1) {
/* Insert cutting points for when a new cut is needed. */
- ies = cut_start_before->prev ? cut_start_before->prev : NULL;
- ns->occlusion = ies ? ies->occlusion : 0;
- ns->material_mask_bits = ies->material_mask_bits;
- BLI_insertlinkbefore(&e->segments, cut_start_before, ns);
+ i_seg = cut_start_before->prev ? cut_start_before->prev : NULL;
+ if (i_seg) {
+ new_seg1->occlusion = i_seg->occlusion;
+ new_seg1->material_mask_bits = i_seg->material_mask_bits;
+ }
+ BLI_insertlinkbefore(&e->segments, cut_start_before, new_seg1);
}
/* Otherwise we already found a existing cutting point, no need to insert a new one. */
}
else {
/* We have yet to reach a existing cutting point even after we searched the whole line, so we
* append the new cut to the end. */
- ies = e->segments.last;
- ns->occlusion = ies->occlusion;
- ns->material_mask_bits = ies->material_mask_bits;
- BLI_addtail(&e->segments, ns);
+ i_seg = e->segments.last;
+ new_seg1->occlusion = i_seg->occlusion;
+ new_seg1->material_mask_bits = i_seg->material_mask_bits;
+ BLI_addtail(&e->segments, new_seg1);
}
if (cut_end_before) {
/* The same manipulation as on "cut_start_before". */
- if (cut_end_before != ns2) {
- ies = cut_end_before->prev ? cut_end_before->prev : NULL;
- ns2->occlusion = ies ? ies->occlusion : 0;
- ns2->material_mask_bits = ies ? ies->material_mask_bits : 0;
- BLI_insertlinkbefore(&e->segments, cut_end_before, ns2);
+ if (cut_end_before != new_seg2) {
+ i_seg = cut_end_before->prev ? cut_end_before->prev : NULL;
+ if (i_seg) {
+ new_seg2->occlusion = i_seg->occlusion;
+ new_seg2->material_mask_bits = i_seg->material_mask_bits;
+ }
+ BLI_insertlinkbefore(&e->segments, cut_end_before, new_seg2);
}
}
else {
- ies = e->segments.last;
- ns2->occlusion = ies->occlusion;
- ns2->material_mask_bits = ies->material_mask_bits;
- BLI_addtail(&e->segments, ns2);
+ i_seg = e->segments.last;
+ new_seg2->occlusion = i_seg->occlusion;
+ new_seg2->material_mask_bits = i_seg->material_mask_bits;
+ BLI_addtail(&e->segments, new_seg2);
}
/* If we touched the cut list, we assign the new cut position based on new cut position,
* this way we accommodate precision lost due to multiple cut inserts. */
- ns->at = start;
+ new_seg1->at = start;
if (!untouched) {
- ns2->at = end;
+ new_seg2->at = end;
}
else {
/* For the convenience of the loop below. */
- ns2 = ns2->next;
+ new_seg2 = new_seg2->next;
}
/* Register 1 level of occlusion for all touched segments. */
- for (es = ns; es && es != ns2; es = es->next) {
- es->occlusion += mat_occlusion;
- es->material_mask_bits |= material_mask_bits;
+ for (seg = new_seg1; seg && seg != new_seg2; seg = seg->next) {
+ seg->occlusion += mat_occlusion;
+ seg->material_mask_bits |= material_mask_bits;
}
/* Reduce adjacent cutting points of the same level, which saves memory. */
- char min_occ = 127;
- prev_es = NULL;
- for (es = e->segments.first; es; es = next_es) {
- next_es = es->next;
-
- if (prev_es && prev_es->occlusion == es->occlusion &&
- prev_es->material_mask_bits == es->material_mask_bits) {
- BLI_remlink(&e->segments, es);
+ int8_t min_occ = 127;
+ prev_seg = NULL;
+ for (seg = e->segments.first; seg; seg = next_seg) {
+ next_seg = seg->next;
+
+ if (prev_seg && prev_seg->occlusion == seg->occlusion &&
+ prev_seg->material_mask_bits == seg->material_mask_bits) {
+ BLI_remlink(&e->segments, seg);
/* This puts the node back to the render buffer, if more cut happens, these unused nodes get
* picked first. */
- lineart_discard_segment(rb, es);
+ lineart_discard_segment(ld, seg);
continue;
}
- min_occ = MIN2(min_occ, es->occlusion);
+ min_occ = MIN2(min_occ, seg->occlusion);
- prev_es = es;
+ prev_seg = seg;
}
e->min_occ = min_occ;
}
@@ -312,29 +342,14 @@ BLI_INLINE bool lineart_occlusion_is_adjacent_intersection(LineartEdge *e, Linea
(v2->base.flag && v2->intersecting_with == tri));
}
-static void lineart_bounding_area_triangle_add(LineartRenderBuffer *rb,
- LineartBoundingArea *ba,
- LineartTriangle *tri)
-{ /* In case of too many triangles concentrating in one point, do not add anymore, these triangles
- * will be either narrower than a single pixel, or will still be added into the list of other
- * less dense areas. */
- if (ba->triangle_count >= 65535) {
- return;
- }
- if (ba->triangle_count >= ba->max_triangle_count) {
- LineartTriangle **new_array = lineart_mem_acquire(
- &rb->render_data_pool, sizeof(LineartTriangle *) * ba->max_triangle_count * 2);
- memcpy(new_array, ba->linked_triangles, sizeof(LineartTriangle *) * ba->max_triangle_count);
- ba->max_triangle_count *= 2;
- ba->linked_triangles = new_array;
- }
- ba->linked_triangles[ba->triangle_count] = tri;
- ba->triangle_count++;
+static void lineart_bounding_area_triangle_reallocate(LineartBoundingArea *ba)
+{
+ ba->max_triangle_count *= 2;
+ ba->linked_triangles = MEM_recallocN(ba->linked_triangles,
+ sizeof(LineartTriangle *) * ba->max_triangle_count);
}
-static void lineart_bounding_area_line_add(LineartRenderBuffer *rb,
- LineartBoundingArea *ba,
- LineartEdge *e)
+static void lineart_bounding_area_line_add(LineartBoundingArea *ba, LineartEdge *e)
{
/* In case of too many lines concentrating in one point, do not add anymore, these lines will
* be either shorter than a single pixel, or will still be added into the list of other less
@@ -343,20 +358,21 @@ static void lineart_bounding_area_line_add(LineartRenderBuffer *rb,
return;
}
if (ba->line_count >= ba->max_line_count) {
- LineartEdge **new_array = lineart_mem_acquire(&rb->render_data_pool,
- sizeof(LineartEdge *) * ba->max_line_count * 2);
+ LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * ba->max_line_count * 2,
+ "new ba_line_array");
memcpy(new_array, ba->linked_lines, sizeof(LineartEdge *) * ba->max_line_count);
ba->max_line_count *= 2;
+ MEM_freeN(ba->linked_lines);
ba->linked_lines = new_array;
}
ba->linked_lines[ba->line_count] = e;
ba->line_count++;
}
-static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge *e, int thread_id)
+static void lineart_occlusion_single_line(LineartData *ld, LineartEdge *e, int thread_id)
{
double x = e->v1->fbcoord[0], y = e->v1->fbcoord[1];
- LineartBoundingArea *ba = lineart_edge_first_bounding_area(rb, e);
+ LineartBoundingArea *ba = lineart_edge_first_bounding_area(ld, e);
LineartBoundingArea *nba = ba;
LineartTriangleThread *tri;
@@ -385,20 +401,20 @@ static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge *
continue;
}
tri->testing_e[thread_id] = e;
- if (lineart_triangle_edge_image_space_occlusion(&rb->lock_task,
+ if (lineart_triangle_edge_image_space_occlusion(&ld->lock_task,
(const LineartTriangle *)tri,
e,
- rb->camera_pos,
- rb->cam_is_persp,
- rb->allow_overlapping_edges,
- rb->view_projection,
- rb->view_vector,
- rb->shift_x,
- rb->shift_y,
+ ld->conf.camera_pos,
+ ld->conf.cam_is_persp,
+ ld->conf.allow_overlapping_edges,
+ ld->conf.view_projection,
+ ld->conf.view_vector,
+ ld->conf.shift_x,
+ ld->conf.shift_y,
&l,
&r)) {
- lineart_edge_cut(rb, e, l, r, tri->base.material_mask_bits, tri->base.mat_occlusion);
- if (e->min_occ > rb->max_occlusion_level) {
+ lineart_edge_cut(ld, e, l, r, tri->base.material_mask_bits, tri->base.mat_occlusion);
+ if (e->min_occ > ld->conf.max_occlusion_level) {
/* No need to calculate any longer on this line because no level more than set value is
* going to show up in the rendered result. */
return;
@@ -410,24 +426,24 @@ static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge *
}
}
-static int lineart_occlusion_make_task_info(LineartRenderBuffer *rb, LineartRenderTaskInfo *rti)
+static int lineart_occlusion_make_task_info(LineartData *ld, LineartRenderTaskInfo *rti)
{
int res = 0;
int starting_index;
- BLI_spin_lock(&rb->lock_task);
+ BLI_spin_lock(&ld->lock_task);
- starting_index = rb->scheduled_count;
- rb->scheduled_count += LRT_THREAD_EDGE_COUNT;
+ starting_index = ld->scheduled_count;
+ ld->scheduled_count += LRT_THREAD_EDGE_COUNT;
- BLI_spin_unlock(&rb->lock_task);
+ BLI_spin_unlock(&ld->lock_task);
- if (starting_index >= rb->pending_edges.next) {
+ if (starting_index >= ld->pending_edges.next) {
res = 0;
}
else {
- rti->pending_edges.array = &rb->pending_edges.array[starting_index];
- int remaining = rb->pending_edges.next - starting_index;
+ rti->pending_edges.array = &ld->pending_edges.array[starting_index];
+ int remaining = ld->pending_edges.next - starting_index;
rti->pending_edges.max = MIN2(remaining, LRT_THREAD_EDGE_COUNT);
res = 1;
}
@@ -437,13 +453,13 @@ static int lineart_occlusion_make_task_info(LineartRenderBuffer *rb, LineartRend
static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartRenderTaskInfo *rti)
{
- LineartRenderBuffer *rb = rti->rb;
+ LineartData *ld = rti->ld;
LineartEdge *eip;
- while (lineart_occlusion_make_task_info(rb, rti)) {
+ while (lineart_occlusion_make_task_info(ld, rti)) {
for (int i = 0; i < rti->pending_edges.max; i++) {
eip = rti->pending_edges.array[i];
- lineart_occlusion_single_line(rb, eip, rti->thread_id);
+ lineart_occlusion_single_line(ld, eip, rti->thread_id);
}
}
}
@@ -453,9 +469,9 @@ static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartR
* #MOD_lineart_compute_feature_lines function.
* This function handles all occlusion calculation.
*/
-static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
+static void lineart_main_occlusion_begin(LineartData *ld)
{
- int thread_count = rb->thread_count;
+ int thread_count = ld->thread_count;
LineartRenderTaskInfo *rti = MEM_callocN(sizeof(LineartRenderTaskInfo) * thread_count,
"Task Pool");
int i;
@@ -464,7 +480,7 @@ static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
for (i = 0; i < thread_count; i++) {
rti[i].thread_id = i;
- rti[i].rb = rb;
+ rti[i].ld = ld;
BLI_task_pool_push(tp, (TaskRunFunction)lineart_occlusion_worker, &rti[i], 0, NULL);
}
BLI_task_pool_work_and_wait(tp);
@@ -554,6 +570,12 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2]
return 0;
}
+enum LineartPointTri {
+ LRT_OUTSIDE_TRIANGLE = 0,
+ LRT_ON_TRIANGLE = 1,
+ LRT_INSIDE_TRIANGLE = 2,
+};
+
/**
* Same algorithm as lineart_point_inside_triangle(), but returns differently:
* 0-outside 1-on the edge 2-inside.
@@ -564,7 +586,7 @@ static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[
double r;
if (lineart_point_on_line_segment(v, v0, v1) || lineart_point_on_line_segment(v, v1, v2) ||
lineart_point_on_line_segment(v, v2, v0)) {
- return 1;
+ return LRT_ON_TRIANGLE;
}
cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
@@ -572,28 +594,28 @@ static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[
cl = (v1[0] - v[0]) * (v2[1] - v[1]) - (v1[1] - v[1]) * (v2[0] - v[0]);
if ((r = c * cl) < 0) {
- return 0;
+ return LRT_OUTSIDE_TRIANGLE;
}
c = cl;
cl = (v2[0] - v[0]) * (v0[1] - v[1]) - (v2[1] - v[1]) * (v0[0] - v[0]);
if ((r = c * cl) < 0) {
- return 0;
+ return LRT_OUTSIDE_TRIANGLE;
}
c = cl;
cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
if ((r = c * cl) < 0) {
- return 0;
+ return LRT_OUTSIDE_TRIANGLE;
}
if (r == 0) {
- return 1;
+ return LRT_ON_TRIANGLE;
}
- return 2;
+ return LRT_INSIDE_TRIANGLE;
}
/**
@@ -641,17 +663,17 @@ static bool lineart_point_inside_triangle3d(double v[3], double v0[3], double v1
* The following `lineart_memory_get_XXX_space` functions are for allocating new memory for some
* modified geometries in the culling stage.
*/
-static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartRenderBuffer *rb)
+static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartData *ld)
{
LineartElementLinkNode *eln;
/* We don't need to allocate a whole bunch of triangles because the amount of clipped triangles
* are relatively small. */
- LineartTriangle *render_triangles = lineart_mem_acquire(&rb->render_data_pool,
- 64 * rb->triangle_size);
+ LineartTriangle *render_triangles = lineart_mem_acquire(&ld->render_data_pool,
+ 64 * ld->sizeof_triangle);
- eln = lineart_list_append_pointer_pool_sized(&rb->triangle_buffer_pointers,
- &rb->render_data_pool,
+ eln = lineart_list_append_pointer_pool_sized(&ld->geom.triangle_buffer_pointers,
+ &ld->render_data_pool,
render_triangles,
sizeof(LineartElementLinkNode));
eln->element_count = 64;
@@ -660,15 +682,15 @@ static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartRenderBu
return eln;
}
-static LineartElementLinkNode *lineart_memory_get_vert_space(LineartRenderBuffer *rb)
+static LineartElementLinkNode *lineart_memory_get_vert_space(LineartData *ld)
{
LineartElementLinkNode *eln;
- LineartVert *render_vertices = lineart_mem_acquire(&rb->render_data_pool,
+ LineartVert *render_vertices = lineart_mem_acquire(&ld->render_data_pool,
sizeof(LineartVert) * 64);
- eln = lineart_list_append_pointer_pool_sized(&rb->vertex_buffer_pointers,
- &rb->render_data_pool,
+ eln = lineart_list_append_pointer_pool_sized(&ld->geom.vertex_buffer_pointers,
+ &ld->render_data_pool,
render_vertices,
sizeof(LineartElementLinkNode));
eln->element_count = 64;
@@ -677,18 +699,18 @@ static LineartElementLinkNode *lineart_memory_get_vert_space(LineartRenderBuffer
return eln;
}
-static LineartElementLinkNode *lineart_memory_get_edge_space(LineartRenderBuffer *rb)
+static LineartElementLinkNode *lineart_memory_get_edge_space(LineartData *ld)
{
LineartElementLinkNode *eln;
- LineartEdge *render_edges = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdge) * 64);
+ LineartEdge *render_edges = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdge) * 64);
- eln = lineart_list_append_pointer_pool_sized(&rb->line_buffer_pointers,
- &rb->render_data_pool,
+ eln = lineart_list_append_pointer_pool_sized(&ld->geom.line_buffer_pointers,
+ &ld->render_data_pool,
render_edges,
sizeof(LineartElementLinkNode));
eln->element_count = 64;
- eln->crease_threshold = rb->crease_threshold;
+ eln->crease_threshold = ld->conf.crease_threshold;
eln->flags |= LRT_ELEMENT_IS_ADDITIONAL;
return eln;
@@ -699,6 +721,7 @@ static void lineart_triangle_post(LineartTriangle *tri, LineartTriangle *orig)
/* Just re-assign normal and set cull flag. */
copy_v3_v3_db(tri->gn, orig->gn);
tri->flags = LRT_CULL_GENERATED;
+ tri->intersection_mask = orig->intersection_mask;
tri->material_mask_bits = orig->material_mask_bits;
tri->mat_occlusion = orig->mat_occlusion;
}
@@ -729,7 +752,7 @@ static void lineart_discard_duplicated_edges(LineartEdge *old_e)
* Does near-plane cut on 1 triangle only. When cutting with far-plane, the camera vectors gets
* reversed by the caller so don't need to implement one in a different direction.
*/
-static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
+static void lineart_triangle_cull_single(LineartData *ld,
LineartTriangle *tri,
int in0,
int in1,
@@ -746,7 +769,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
LineartElementLinkNode *e_eln,
LineartElementLinkNode *t_eln)
{
- double vv1[3], vv2[3], dot1, dot2;
+ double span_v1[3], span_v2[3], dot_v1, dot_v2;
double a;
int v_count = *r_v_count;
int e_count = *r_e_count;
@@ -755,7 +778,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
LineartEdge *new_e, *e, *old_e;
LineartEdgeSegment *es;
- LineartTriangleAdjacent *ta;
+ LineartTriangleAdjacent *tri_adj;
if (tri->flags & (LRT_CULL_USED | LRT_CULL_GENERATED | LRT_CULL_DISCARD)) {
return;
@@ -763,11 +786,12 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
/* See definition of tri->intersecting_verts and the usage in
* lineart_geometry_object_load() for details. */
- ta = (void *)tri->intersecting_verts;
+ tri_adj = (void *)tri->intersecting_verts;
LineartVert *vt = &((LineartVert *)v_eln->pointer)[v_count];
- LineartTriangle *tri1 = (void *)(((uchar *)t_eln->pointer) + rb->triangle_size * t_count);
- LineartTriangle *tri2 = (void *)(((uchar *)t_eln->pointer) + rb->triangle_size * (t_count + 1));
+ LineartTriangle *tri1 = (void *)(((uchar *)t_eln->pointer) + ld->sizeof_triangle * t_count);
+ LineartTriangle *tri2 = (void *)(((uchar *)t_eln->pointer) +
+ ld->sizeof_triangle * (t_count + 1));
new_e = &((LineartEdge *)e_eln->pointer)[e_count];
/* Init `edge` to the last `edge` entry. */
@@ -777,12 +801,12 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
new_e = &((LineartEdge *)e_eln->pointer)[e_count]; \
e_count++; \
e = new_e; \
- es = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeSegment)); \
+ es = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdgeSegment)); \
BLI_addtail(&e->segments, es);
#define SELECT_EDGE(e_num, v1_link, v2_link, new_tri) \
- if (ta->e[e_num]) { \
- old_e = ta->e[e_num]; \
+ if (tri_adj->e[e_num]) { \
+ old_e = tri_adj->e[e_num]; \
new_flag = old_e->flags; \
old_e->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
lineart_discard_duplicated_edges(old_e); \
@@ -795,28 +819,28 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
e->object_ref = ob; \
e->t1 = ((old_e->t1 == tri) ? (new_tri) : (old_e->t1)); \
e->t2 = ((old_e->t2 == tri) ? (new_tri) : (old_e->t2)); \
- lineart_add_edge_to_array(&rb->pending_edges, e); \
+ lineart_add_edge_to_array(&ld->pending_edges, e); \
}
#define RELINK_EDGE(e_num, new_tri) \
- if (ta->e[e_num]) { \
- old_e = ta->e[e_num]; \
+ if (tri_adj->e[e_num]) { \
+ old_e = tri_adj->e[e_num]; \
old_e->t1 = ((old_e->t1 == tri) ? (new_tri) : (old_e->t1)); \
old_e->t2 = ((old_e->t2 == tri) ? (new_tri) : (old_e->t2)); \
}
#define REMOVE_TRIANGLE_EDGE \
- if (ta->e[0]) { \
- ta->e[0]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
- lineart_discard_duplicated_edges(ta->e[0]); \
+ if (tri_adj->e[0]) { \
+ tri_adj->e[0]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ lineart_discard_duplicated_edges(tri_adj->e[0]); \
} \
- if (ta->e[1]) { \
- ta->e[1]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
- lineart_discard_duplicated_edges(ta->e[1]); \
+ if (tri_adj->e[1]) { \
+ tri_adj->e[1]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ lineart_discard_duplicated_edges(tri_adj->e[1]); \
} \
- if (ta->e[2]) { \
- ta->e[2]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
- lineart_discard_duplicated_edges(ta->e[2]); \
+ if (tri_adj->e[2]) { \
+ tri_adj->e[2]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ lineart_discard_duplicated_edges(tri_adj->e[2]); \
}
switch (in0 + in1 + in2) {
@@ -856,22 +880,22 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
if (!in0) {
/* Cut point for line 2---|-----0. */
- sub_v3_v3v3_db(vv1, tri->v[0]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[0]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
/* Assign it to a new point. */
interp_v3_v3v3_db(vt[0].gloc, tri->v[0]->gloc, tri->v[2]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[2]->index;
/* Cut point for line 1---|-----0. */
- sub_v3_v3v3_db(vv1, tri->v[0]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[0]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
/* Assign it to another new point. */
interp_v3_v3v3_db(vt[1].gloc, tri->v[0]->gloc, tri->v[1]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
@@ -881,7 +905,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
/* NOTE: inverting `e->v1/v2` (left/right point) doesn't matter as long as
* `tri->edge` and `tri->v` has the same sequence. and the winding direction
@@ -909,20 +933,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
t_count += 1;
}
else if (!in2) {
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[2]->gloc, tri->v[0]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[0]->index;
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[2]->gloc, tri->v[1]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
vt[1].index = tri->v[1]->index;
@@ -930,7 +954,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[0];
e->v2 = &vt[1];
@@ -950,20 +974,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
t_count += 1;
}
else if (!in1) {
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[1]->gloc, tri->v[2]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[2]->index;
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[1]->gloc, tri->v[0]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
vt[1].index = tri->v[0]->index;
@@ -971,7 +995,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1021,22 +1045,22 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
*/
if (in0) {
/* Cut point for line 0---|------1. */
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot2 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v2 / (dot_v1 + dot_v2);
/* Assign to a new point. */
interp_v3_v3v3_db(vt[0].gloc, tri->v[0]->gloc, tri->v[1]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[0]->index;
/* Cut point for line 0---|------2. */
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot2 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v2 / (dot_v1 + dot_v2);
/* Assign to other new point. */
interp_v3_v3v3_db(vt[1].gloc, tri->v[0]->gloc, tri->v[2]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
@@ -1046,7 +1070,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1077,20 +1101,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
}
else if (in1) {
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[1]->gloc, tri->v[2]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[1]->index;
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[1]->gloc, tri->v[0]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
vt[1].index = tri->v[1]->index;
@@ -1098,7 +1122,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1126,20 +1150,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
}
else if (in2) {
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[2]->gloc, tri->v[0]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[2]->index;
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[2]->gloc, tri->v[1]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
vt[1].index = tri->v[2]->index;
@@ -1147,7 +1171,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1191,22 +1215,22 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
* new topology that represents the trimmed triangle. (which then became a triangle or a square
* formed by two triangles)
*/
-static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
+static void lineart_main_cull_triangles(LineartData *ld, bool clip_far)
{
LineartTriangle *tri;
LineartElementLinkNode *v_eln, *t_eln, *e_eln;
- double(*vp)[4] = rb->view_projection;
+ double(*vp)[4] = ld->conf.view_projection;
int i;
int v_count = 0, t_count = 0, e_count = 0;
Object *ob;
- bool allow_boundaries = rb->allow_boundaries;
+ bool allow_boundaries = ld->conf.allow_boundaries;
double cam_pos[3];
- double clip_start = rb->near_clip, clip_end = rb->far_clip;
+ double clip_start = ld->conf.near_clip, clip_end = ld->conf.far_clip;
double view_dir[3], clip_advance[3];
- copy_v3_v3_db(view_dir, rb->view_vector);
- copy_v3_v3_db(clip_advance, rb->view_vector);
- copy_v3_v3_db(cam_pos, rb->camera_pos);
+ copy_v3_v3_db(view_dir, ld->conf.view_vector);
+ copy_v3_v3_db(clip_advance, ld->conf.view_vector);
+ copy_v3_v3_db(cam_pos, ld->conf.camera_pos);
if (clip_far) {
/* Move starting point to end plane. */
@@ -1222,25 +1246,25 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
add_v3_v3_db(cam_pos, clip_advance);
}
- v_eln = lineart_memory_get_vert_space(rb);
- t_eln = lineart_memory_get_triangle_space(rb);
- e_eln = lineart_memory_get_edge_space(rb);
+ v_eln = lineart_memory_get_vert_space(ld);
+ t_eln = lineart_memory_get_triangle_space(ld);
+ e_eln = lineart_memory_get_edge_space(ld);
/* Additional memory space for storing generated points and triangles. */
#define LRT_CULL_ENSURE_MEMORY \
if (v_count > 60) { \
v_eln->element_count = v_count; \
- v_eln = lineart_memory_get_vert_space(rb); \
+ v_eln = lineart_memory_get_vert_space(ld); \
v_count = 0; \
} \
if (t_count > 60) { \
t_eln->element_count = t_count; \
- t_eln = lineart_memory_get_triangle_space(rb); \
+ t_eln = lineart_memory_get_triangle_space(ld); \
t_count = 0; \
} \
if (e_count > 60) { \
e_eln->element_count = e_count; \
- e_eln = lineart_memory_get_edge_space(rb); \
+ e_eln = lineart_memory_get_edge_space(ld); \
e_count = 0; \
}
@@ -1275,21 +1299,21 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
int use_w = 3;
int in0 = 0, in1 = 0, in2 = 0;
- if (!rb->cam_is_persp) {
+ if (!ld->conf.cam_is_persp) {
clip_start = -1;
clip_end = 1;
use_w = 2;
}
/* Then go through all the other triangles. */
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) {
if (eln->flags & LRT_ELEMENT_IS_ADDITIONAL) {
continue;
}
ob = eln->object_ref;
for (i = 0; i < eln->element_count; i++) {
/* Select the triangle in the array. */
- tri = (void *)(((uchar *)eln->pointer) + rb->triangle_size * i);
+ tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * i);
if (tri->flags & LRT_CULL_DISCARD) {
continue;
@@ -1297,7 +1321,7 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
LRT_CULL_DECIDE_INSIDE
LRT_CULL_ENSURE_MEMORY
- lineart_triangle_cull_single(rb,
+ lineart_triangle_cull_single(ld,
tri,
in0,
in1,
@@ -1326,33 +1350,33 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
* Adjacent data is only used during the initial stages of computing.
* So we can free it using this function when it is not needed anymore.
*/
-static void lineart_main_free_adjacent_data(LineartRenderBuffer *rb)
+static void lineart_main_free_adjacent_data(LineartData *ld)
{
- LinkData *ld;
- while ((ld = BLI_pophead(&rb->triangle_adjacent_pointers)) != NULL) {
- MEM_freeN(ld->data);
+ LinkData *link;
+ while ((link = BLI_pophead(&ld->geom.triangle_adjacent_pointers)) != NULL) {
+ MEM_freeN(link->data);
}
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) {
LineartTriangle *tri = eln->pointer;
int i;
for (i = 0; i < eln->element_count; i++) {
/* See definition of tri->intersecting_verts and the usage in
* lineart_geometry_object_load() for detailed. */
tri->intersecting_verts = NULL;
- tri = (LineartTriangle *)(((uchar *)tri) + rb->triangle_size);
+ tri = (LineartTriangle *)(((uchar *)tri) + ld->sizeof_triangle);
}
}
}
-static void lineart_main_perspective_division(LineartRenderBuffer *rb)
+static void lineart_main_perspective_division(LineartData *ld)
{
LineartVert *vt;
int i;
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->vertex_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.vertex_buffer_pointers) {
vt = eln->pointer;
for (i = 0; i < eln->element_count; i++) {
- if (rb->cam_is_persp) {
+ if (ld->conf.cam_is_persp) {
/* Do not divide Z, we use Z to back transform cut points in later chaining process. */
vt[i].fbcoord[0] /= vt[i].fbcoord[3];
vt[i].fbcoord[1] /= vt[i].fbcoord[3];
@@ -1363,13 +1387,13 @@ static void lineart_main_perspective_division(LineartRenderBuffer *rb)
// `vt[i].fbcoord[2] = -2 * vt[i].fbcoord[2] / (far - near) - (far + near) / (far - near);
}
/* Shifting is always needed. */
- vt[i].fbcoord[0] -= rb->shift_x * 2;
- vt[i].fbcoord[1] -= rb->shift_y * 2;
+ vt[i].fbcoord[0] -= ld->conf.shift_x * 2;
+ vt[i].fbcoord[1] -= ld->conf.shift_y * 2;
}
}
}
-static void lineart_main_discard_out_of_frame_edges(LineartRenderBuffer *rb)
+static void lineart_main_discard_out_of_frame_edges(LineartData *ld)
{
LineartEdge *e;
int i;
@@ -1377,7 +1401,7 @@ static void lineart_main_discard_out_of_frame_edges(LineartRenderBuffer *rb)
#define LRT_VERT_OUT_OF_BOUND(v) \
(v && (v->fbcoord[0] < -1 || v->fbcoord[0] > 1 || v->fbcoord[1] < -1 || v->fbcoord[1] > 1))
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->line_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.line_buffer_pointers) {
e = (LineartEdge *)eln->pointer;
for (i = 0; i < eln->element_count; i++) {
if ((LRT_VERT_OUT_OF_BOUND(e[i].v1) && LRT_VERT_OUT_OF_BOUND(e[i].v2))) {
@@ -1414,14 +1438,22 @@ static void lineart_mvert_transform_task(void *__restrict userdata,
v->index = i;
}
-#define LRT_EDGE_FLAG_TYPE_MAX_BITS 6
+static const int LRT_MESH_EDGE_TYPES[] = {
+ LRT_EDGE_FLAG_EDGE_MARK,
+ LRT_EDGE_FLAG_CONTOUR,
+ LRT_EDGE_FLAG_CREASE,
+ LRT_EDGE_FLAG_MATERIAL,
+ LRT_EDGE_FLAG_LOOSE,
+};
-static int lineart_edge_type_duplication_count(char eflag)
+#define LRT_MESH_EDGE_TYPES_COUNT 5
+
+static int lineart_edge_type_duplication_count(int eflag)
{
int count = 0;
/* See eLineartEdgeFlag for details. */
- for (int i = 0; i < LRT_EDGE_FLAG_TYPE_MAX_BITS; i++) {
- if (eflag & (1 << i)) {
+ for (int i = 0; i < LRT_MESH_EDGE_TYPES_COUNT; i++) {
+ if (eflag & LRT_MESH_EDGE_TYPES[i]) {
count++;
}
}
@@ -1432,17 +1464,17 @@ static int lineart_edge_type_duplication_count(char eflag)
* Because we have a variable size for #LineartTriangle, we need an access helper.
* See #LineartTriangleThread for more info.
*/
-static LineartTriangle *lineart_triangle_from_index(LineartRenderBuffer *rb,
+static LineartTriangle *lineart_triangle_from_index(LineartData *ld,
LineartTriangle *rt_array,
int index)
{
- char *b = (char *)rt_array;
- b += (index * rb->triangle_size);
+ int8_t *b = (int8_t *)rt_array;
+ b += (index * ld->sizeof_triangle);
return (LineartTriangle *)b;
}
typedef struct EdgeFeatData {
- LineartRenderBuffer *rb;
+ LineartData *ld;
Mesh *me;
const MLoopTri *mlooptri;
LineartTriangle *tri_array;
@@ -1488,7 +1520,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
}
bool face_mark_filtered = false;
- bool enable_face_mark = (e_feat_data->use_freestyle_face && e_feat_data->rb->filter_face_mark);
+ bool enable_face_mark = (e_feat_data->use_freestyle_face &&
+ e_feat_data->ld->conf.filter_face_mark);
bool only_contour = false;
if (enable_face_mark) {
FreestyleFace *ff1, *ff2;
@@ -1505,7 +1538,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
* path is simper when it's assuming both ff1 and ff2 not NULL. */
ff2 = ff1;
}
- if (e_feat_data->rb->filter_face_mark_boundaries ^ e_feat_data->rb->filter_face_mark_invert) {
+ if (e_feat_data->ld->conf.filter_face_mark_boundaries ^
+ e_feat_data->ld->conf.filter_face_mark_invert) {
if ((ff1->flag & FREESTYLE_FACE_MARK) || (ff2->flag & FREESTYLE_FACE_MARK)) {
face_mark_filtered = true;
}
@@ -1515,12 +1549,12 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
face_mark_filtered = true;
}
}
- if (e_feat_data->rb->filter_face_mark_invert) {
+ if (e_feat_data->ld->conf.filter_face_mark_invert) {
face_mark_filtered = !face_mark_filtered;
}
if (!face_mark_filtered) {
edge_nabr[i].flags = LRT_EDGE_FLAG_INHIBIT;
- if (e_feat_data->rb->filter_face_mark_keep_contour) {
+ if (e_feat_data->ld->conf.filter_face_mark_keep_contour) {
only_contour = true;
}
}
@@ -1539,50 +1573,50 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
LineartTriangle *tri1, *tri2;
LineartVert *vert;
- LineartRenderBuffer *rb = e_feat_data->rb;
+ LineartData *ld = e_feat_data->ld;
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, e_feat_data->tri_array, f1);
- tri2 = lineart_triangle_from_index(rb, e_feat_data->tri_array, f2);
+ tri1 = lineart_triangle_from_index(ld, e_feat_data->tri_array, f1);
+ tri2 = lineart_triangle_from_index(ld, e_feat_data->tri_array, f2);
vert = &e_feat_data->v_array[edge_nabr[i].v1];
double view_vector_persp[3];
double *view_vector = view_vector_persp;
- double dot_1 = 0, dot_2 = 0;
+ double dot_v1 = 0, dot_v2 = 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, vert->gloc);
+ if (ld->conf.use_contour || ld->conf.use_back_face_culling || material_back_face) {
+ if (ld->conf.cam_is_persp) {
+ sub_v3_v3v3_db(view_vector, ld->conf.camera_pos, vert->gloc);
}
else {
- view_vector = rb->view_vector;
+ view_vector = ld->conf.view_vector;
}
- dot_1 = dot_v3v3_db(view_vector, tri1->gn);
- dot_2 = dot_v3v3_db(view_vector, tri2->gn);
+ dot_v1 = dot_v3v3_db(view_vector, tri1->gn);
+ dot_v2 = dot_v3v3_db(view_vector, tri2->gn);
- if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
+ if ((result = dot_v1 * dot_v2) <= 0 && (dot_v1 + dot_v2)) {
edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
}
- if (rb->use_back_face_culling) {
- if (dot_1 < 0) {
+ if (ld->conf.use_back_face_culling) {
+ if (dot_v1 < 0) {
tri1->flags |= LRT_CULL_DISCARD;
}
- if (dot_2 < 0) {
+ if (dot_v2 < 0) {
tri2->flags |= LRT_CULL_DISCARD;
}
}
if (material_back_face) {
- if (tri1->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_1 < 0) {
+ if (tri1->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_v1 < 0) {
tri1->flags |= LRT_CULL_DISCARD;
}
- if (tri2->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_2 < 0) {
+ if (tri2->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_v2 < 0) {
tri2->flags |= LRT_CULL_DISCARD;
}
}
@@ -1590,9 +1624,9 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
if (!only_contour) {
- if (rb->use_crease) {
+ if (ld->conf.use_crease) {
bool do_crease = true;
- if (!rb->force_crease && !e_feat_data->use_auto_smooth &&
+ if (!ld->conf.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;
@@ -1605,7 +1639,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
int mat1 = me->mpoly[mlooptri[f1].poly].mat_nr;
int mat2 = me->mpoly[mlooptri[f2].poly].mat_nr;
- if (rb->use_material && mat1 != mat2) {
+ if (ld->conf.use_material && mat1 != mat2) {
edge_flag_result |= LRT_EDGE_FLAG_MATERIAL;
}
}
@@ -1621,11 +1655,11 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
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)) {
+ if (ld->conf.use_crease && ld->conf.sharp_as_crease && (medge->flag & ME_SHARP)) {
edge_flag_result |= LRT_EDGE_FLAG_CREASE;
}
- if (rb->use_edge_marks && e_feat_data->use_freestyle_edge) {
+ if (ld->conf.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]];
@@ -1641,7 +1675,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
/* 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 ?
+ reduce_data->feat_edges += e_feat_data->ld->conf.allow_duplicated_types ?
lineart_edge_type_duplication_count(edge_flag_result) :
1;
}
@@ -1679,6 +1713,7 @@ static void lineart_join_loose_edge_arr(LooseEdgeData *loose_data, LooseEdgeData
sizeof(MEdge *) * to_be_joined->loose_count);
loose_data->loose_count += to_be_joined->loose_count;
MEM_freeN(to_be_joined->loose_array);
+ to_be_joined->loose_array = NULL;
}
static void lineart_add_loose_edge(LooseEdgeData *loose_data, MEdge *e)
@@ -1766,17 +1801,17 @@ static void lineart_finalize_object_edge_array(LineartPendingEdges *pe, LineartO
}
static void lineart_triangle_adjacent_assign(LineartTriangle *tri,
- LineartTriangleAdjacent *ta,
+ LineartTriangleAdjacent *tri_adj,
LineartEdge *e)
{
if (lineart_edge_match(tri, e, 0, 1)) {
- ta->e[0] = e;
+ tri_adj->e[0] = e;
}
else if (lineart_edge_match(tri, e, 1, 2)) {
- ta->e[1] = e;
+ tri_adj->e[1] = e;
}
else if (lineart_edge_match(tri, e, 2, 0)) {
- ta->e[2] = e;
+ tri_adj->e[2] = e;
}
}
@@ -1862,7 +1897,7 @@ static void lineart_edge_neighbor_init_task(void *__restrict userdata,
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);
+ SWAP(uint32_t, adj_e->v1, adj_e->v2);
}
edge_nabr->e = -1;
@@ -1908,7 +1943,7 @@ static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edge
return edge_nabr;
}
-static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRenderBuffer *re_buf)
+static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartData *la_data)
{
LineartElementLinkNode *elem_link_node;
LineartVert *la_v_arr;
@@ -1942,19 +1977,20 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
/* 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. */
- la_v_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ la_v_arr = lineart_mem_acquire_thread(&la_data->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);
+ la_tri_arr = lineart_mem_acquire_thread(&la_data->render_data_pool,
+ tot_tri * la_data->sizeof_triangle);
Object *orig_ob = ob_info->original_ob;
- 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);
+ BLI_spin_lock(&la_data->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(
+ &la_data->geom.vertex_buffer_pointers,
+ &la_data->render_data_pool,
+ la_v_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&la_data->lock_task);
elem_link_node->element_count = me->totvert;
elem_link_node->object_ref = orig_ob;
@@ -1970,7 +2006,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
use_auto_smooth = true;
}
else {
- crease_angle = re_buf->crease_threshold;
+ crease_angle = la_data->conf.crease_threshold;
}
/* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates
@@ -1979,12 +2015,13 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
elem_link_node->flags |= LRT_ELEMENT_BORDER_ONLY;
}
- 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);
+ BLI_spin_lock(&la_data->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(
+ &la_data->geom.triangle_buffer_pointers,
+ &la_data->render_data_pool,
+ la_tri_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&la_data->lock_task);
int usage = ob_info->usage;
@@ -1996,10 +2033,10 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
LineartTriangleAdjacent *tri_adj = MEM_callocN(sizeof(LineartTriangleAdjacent) * tot_tri,
"LineartTriangleAdjacent");
/* Link is minimal so we use pool anyway. */
- BLI_spin_lock(&re_buf->lock_task);
+ BLI_spin_lock(&la_data->lock_task);
lineart_list_append_pointer_pool_thread(
- &re_buf->triangle_adjacent_pointers, &re_buf->render_data_pool, tri_adj);
- BLI_spin_unlock(&re_buf->lock_task);
+ &la_data->geom.triangle_adjacent_pointers, &la_data->render_data_pool, tri_adj);
+ BLI_spin_unlock(&la_data->lock_task);
/* Convert all vertices to lineart verts. */
TaskParallelSettings vert_settings;
@@ -2028,10 +2065,10 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
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.lineart_triangle_size = la_data->sizeof_triangle;
tri_data.tri_adj = tri_adj;
- unsigned int total_edges = tot_tri * 3;
+ uint32_t total_edges = tot_tri * 3;
BLI_task_parallel_range(0, tot_tri, &tri_data, lineart_load_tri_task, &tri_settings);
@@ -2049,7 +2086,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
edge_feat_settings.func_reduce = feat_data_sum_reduce;
EdgeFeatData edge_feat_data = {0};
- edge_feat_data.rb = re_buf;
+ edge_feat_data.ld = la_data;
edge_feat_data.me = me;
edge_feat_data.mlooptri = mlooptri;
edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges);
@@ -2075,7 +2112,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
&edge_feat_settings);
LooseEdgeData loose_data = {0};
- if (re_buf->use_loose) {
+ if (la_data->conf.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;
@@ -2091,20 +2128,21 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
int allocate_la_e = edge_reduce.feat_edges + loose_data.loose_count;
- la_edge_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ la_edge_arr = lineart_mem_acquire_thread(&la_data->render_data_pool,
sizeof(LineartEdge) * allocate_la_e);
- la_seg_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ la_seg_arr = lineart_mem_acquire_thread(&la_data->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);
+ BLI_spin_lock(&la_data->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(
+ &la_data->geom.line_buffer_pointers,
+ &la_data->render_data_pool,
+ la_edge_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&la_data->lock_task);
elem_link_node->element_count = allocate_la_e;
elem_link_node->object_ref = orig_ob;
- // Start of the edge/seg arr
+ /* Start of the edge/seg arr */
LineartEdge *la_edge;
LineartEdgeSegment *la_seg;
la_edge = la_edge_arr;
@@ -2125,8 +2163,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
LineartEdge *edge_added = NULL;
/* See eLineartEdgeFlag for details. */
- for (int flag_bit = 0; flag_bit < LRT_EDGE_FLAG_TYPE_MAX_BITS; flag_bit++) {
- char use_type = 1 << flag_bit;
+ for (int flag_bit = 0; flag_bit < LRT_MESH_EDGE_TYPES_COUNT; flag_bit++) {
+ int use_type = LRT_MESH_EDGE_TYPES[flag_bit];
if (!(use_type & edge_nabr->flags)) {
continue;
}
@@ -2134,13 +2172,13 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
la_edge->v1 = &la_v_arr[edge_nabr->v1];
la_edge->v2 = &la_v_arr[edge_nabr->v2];
int findex = i / 3;
- la_edge->t1 = lineart_triangle_from_index(re_buf, la_tri_arr, findex);
+ la_edge->t1 = lineart_triangle_from_index(la_data, 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);
+ la_edge->t2 = lineart_triangle_from_index(la_data, la_tri_arr, findex);
if (!edge_added) {
lineart_triangle_adjacent_assign(la_edge->t2, &tri_adj[findex], la_edge);
}
@@ -2162,7 +2200,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
la_edge++;
la_seg++;
- if (!re_buf->allow_duplicated_types) {
+ if (!la_data->conf.allow_duplicated_types) {
break;
}
}
@@ -2196,10 +2234,7 @@ static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool),
LineartObjectLoadTaskInfo *olti)
{
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);
- }
+ lineart_geometry_object_load(obi, olti->ld);
}
}
@@ -2277,7 +2312,7 @@ static void lineart_geometry_load_assign_thread(LineartObjectLoadTaskInfo *olti_
int this_face_count)
{
LineartObjectLoadTaskInfo *use_olti = olti_list;
- long unsigned int min_face = use_olti->total_faces;
+ uint64_t min_face = use_olti->total_faces;
for (int i = 0; i < thread_count; i++) {
if (olti_list[i].total_faces < min_face) {
min_face = olti_list[i].total_faces;
@@ -2333,7 +2368,7 @@ static bool lineart_geometry_check_visible(double (*model_view_proj)[4],
return true;
}
-static void lineart_object_load_single_instance(LineartRenderBuffer *rb,
+static void lineart_object_load_single_instance(LineartData *ld,
Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -2343,7 +2378,7 @@ static void lineart_object_load_single_instance(LineartRenderBuffer *rb,
LineartObjectLoadTaskInfo *olti,
int thread_count)
{
- LineartObjectInfo *obi = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartObjectInfo));
+ LineartObjectInfo *obi = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartObjectInfo));
obi->usage = lineart_usage_check(scene->master_collection, ob, is_render);
obi->override_intersection_mask = lineart_intersection_mask_check(scene->master_collection, ob);
Mesh *use_mesh;
@@ -2354,8 +2389,8 @@ static void lineart_object_load_single_instance(LineartRenderBuffer *rb,
/* Prepare the matrix used for transforming this specific object (instance). This has to be
* done before mesh boundbox check because the function needs that. */
- mul_m4db_m4db_m4fl_uniq(obi->model_view_proj, rb->view_projection, use_mat);
- mul_m4db_m4db_m4fl_uniq(obi->model_view, rb->view, use_mat);
+ mul_m4db_m4db_m4fl_uniq(obi->model_view_proj, ld->conf.view_projection, use_mat);
+ mul_m4db_m4db_m4fl_uniq(obi->model_view, ld->conf.view, use_mat);
if (!ELEM(ob->type, OB_MESH, OB_MBALL, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
return;
@@ -2377,7 +2412,8 @@ static void lineart_object_load_single_instance(LineartRenderBuffer *rb,
return;
}
- if (!lineart_geometry_check_visible(obi->model_view_proj, rb->shift_x, rb->shift_y, use_mesh)) {
+ if (!lineart_geometry_check_visible(
+ obi->model_view_proj, ld->conf.shift_x, ld->conf.shift_y, use_mesh)) {
return;
}
@@ -2400,15 +2436,15 @@ static void lineart_main_load_geometries(
Depsgraph *depsgraph,
Scene *scene,
Object *camera /* Still use camera arg for convenience. */,
- LineartRenderBuffer *rb,
+ LineartData *ld,
bool allow_duplicates)
{
double proj[4][4], view[4][4], result[4][4];
float inv[4][4];
Camera *cam = camera->data;
float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
- int fit = BKE_camera_sensor_fit(cam->sensor_fit, rb->w, rb->h);
- double asp = ((double)rb->w / (double)rb->h);
+ int fit = BKE_camera_sensor_fit(cam->sensor_fit, ld->w, ld->h);
+ double asp = ((double)ld->w / (double)ld->h);
int bound_box_discard_count = 0;
@@ -2419,7 +2455,7 @@ static void lineart_main_load_geometries(
if (fit == CAMERA_SENSOR_FIT_HOR && asp < 1) {
sensor /= asp;
}
- const double fov = focallength_to_fov(cam->lens / (1 + rb->overscan), sensor);
+ const double fov = focallength_to_fov(cam->lens / (1 + ld->conf.overscan), sensor);
lineart_matrix_perspective_44d(proj, fov, asp, cam->clip_start, cam->clip_end);
}
else if (cam->type == CAM_ORTHO) {
@@ -2427,29 +2463,27 @@ static void lineart_main_load_geometries(
lineart_matrix_ortho_44d(proj, -w, w, -w / asp, w / asp, cam->clip_start, cam->clip_end);
}
- double t_start;
-
- if (G.debug_value == 4000) {
- t_start = PIL_check_seconds_timer();
- }
-
- invert_m4_m4(inv, rb->cam_obmat);
+ invert_m4_m4(inv, ld->conf.cam_obmat);
mul_m4db_m4db_m4fl_uniq(result, proj, inv);
copy_m4_m4_db(proj, result);
- copy_m4_m4_db(rb->view_projection, proj);
+ copy_m4_m4_db(ld->conf.view_projection, proj);
unit_m4_db(view);
- copy_m4_m4_db(rb->view, view);
+ copy_m4_m4_db(ld->conf.view, view);
- BLI_listbase_clear(&rb->triangle_buffer_pointers);
- BLI_listbase_clear(&rb->vertex_buffer_pointers);
+ BLI_listbase_clear(&ld->geom.triangle_buffer_pointers);
+ BLI_listbase_clear(&ld->geom.vertex_buffer_pointers);
- int thread_count = rb->thread_count;
+ double t_start;
+ if (G.debug_value == 4000) {
+ t_start = PIL_check_seconds_timer();
+ }
- /* This memory is in render buffer memory pool. so we don't need to free those after loading.
- */
+ int thread_count = ld->thread_count;
+
+ /* This memory is in render buffer memory pool. So we don't need to free those after loading. */
LineartObjectLoadTaskInfo *olti = lineart_mem_acquire(
- &rb->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count);
+ &ld->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count);
eEvaluationMode eval_mode = DEG_get_mode(depsgraph);
bool is_render = eval_mode == DAG_EVAL_RENDER;
@@ -2462,8 +2496,8 @@ static void lineart_main_load_geometries(
flags |= DEG_ITER_OBJECT_FLAG_DUPLI;
}
- /* XXX(Yiming): Temporary solution, this iterator is technially unsafe to use *during* depsgraph
- * evaluation, see https://developer.blender.org/D14997 for detailed explainations. */
+ /* XXX(@Yiming): Temporary solution, this iterator is technically unsafe to use *during*
+ * depsgraph evaluation, see D14997 for detailed explanations. */
DEG_OBJECT_ITER_BEGIN (depsgraph, ob, flags) {
Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob);
@@ -2479,7 +2513,7 @@ static void lineart_main_load_geometries(
if (BKE_object_visibility(eval_ob, eval_mode) & OB_VISIBLE_SELF) {
lineart_object_load_single_instance(
- rb, depsgraph, scene, eval_ob, eval_ob, eval_ob->obmat, is_render, olti, thread_count);
+ ld, depsgraph, scene, eval_ob, eval_ob, eval_ob->obmat, is_render, olti, thread_count);
}
}
DEG_OBJECT_ITER_END;
@@ -2490,7 +2524,7 @@ static void lineart_main_load_geometries(
printf("thread count: %d\n", thread_count);
}
for (int i = 0; i < thread_count; i++) {
- olti[i].rb = rb;
+ olti[i].ld = ld;
olti[i].thread_id = i;
BLI_task_pool_push(tp, (TaskRunFunction)lineart_object_load_worker, &olti[i], 0, NULL);
}
@@ -2510,7 +2544,7 @@ static void lineart_main_load_geometries(
edge_count += obi->pending_edges.next;
}
}
- lineart_finalize_object_edge_array_reserve(&rb->pending_edges, edge_count);
+ lineart_finalize_object_edge_array_reserve(&ld->pending_edges, edge_count);
for (int i = 0; i < thread_count; i++) {
for (LineartObjectInfo *obi = olti[i].pending; obi; obi = obi->next) {
@@ -2528,7 +2562,7 @@ static void lineart_main_load_geometries(
* same numeric index to come close together. */
obi->global_i_offset = global_i;
global_i += v_count;
- lineart_finalize_object_edge_array(&rb->pending_edges, obi);
+ lineart_finalize_object_edge_array(&ld->pending_edges, obi);
}
}
@@ -2622,6 +2656,9 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
(num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : -1))); \
}
+#define LRT_ISEC(index) (index == 0 ? isec_e1 : (index == 1 ? isec_e2 : isec_e3))
+#define LRT_PARALLEL(index) (index == 0 ? para_e1 : (index == 1 ? para_e2 : para_e3))
+
/**
* This is the main function to calculate
* the occlusion status between 1(one) triangle and 1(one) line.
@@ -2635,7 +2672,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
* extruding from one of the triangle's point. To get the information using one math process can
* solve this problem.
*
- * 2) Currently using discrete a/b/c/pa/pb/pc/is[3] values for storing
+ * 2) Currently using discrete a/b/c/para_e1/para_e2/para_e3/is[3] values for storing
* intersection/edge_aligned/intersection_order info, which isn't optimal, needs a better
* representation (likely a struct) for readability and clarity of code path.
*
@@ -2657,18 +2694,20 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
double *from,
double *to)
{
- double is[3] = {0};
- int order[3];
- int LCross = -1, RCross = -1;
- int a, b, c; /* Crossing info. */
- bool pa, pb, pc; /* Parallel info. */
- int st_l = 0, st_r = 0;
-
- double Lv[3];
- double Rv[3];
- double vd4[4];
- double Cv[3];
- double dot_l, dot_r, dot_la, dot_ra;
+ double cross_ratios[3] = {0};
+ int cross_order[3];
+ int cross_v1 = -1, cross_v2 = -1;
+ /* If the edge intersects with the triangle edges (including extensions). */
+ int isec_e1, isec_e2, isec_e3;
+ /* If edge is parallel to one of the edges in the triangle. */
+ bool para_e1, para_e2, para_e3;
+ enum LineartPointTri state_v1 = 0, state_v2 = 0;
+
+ double dir_v1[3];
+ double dir_v2[3];
+ double view_vector[4];
+ double dir_cam[3];
+ double dot_v1, dot_v2, dot_v1a, dot_v2a;
double dot_f;
double gloc[4], trans[4];
double cut = -1;
@@ -2691,31 +2730,25 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
}
/* Check if the line visually crosses one of the edge in the triangle. */
- a = lineart_intersect_seg_seg(LFBC, RFBC, FBC0, FBC1, &is[0], &pa);
- b = lineart_intersect_seg_seg(LFBC, RFBC, FBC1, FBC2, &is[1], &pb);
- c = lineart_intersect_seg_seg(LFBC, RFBC, FBC2, FBC0, &is[2], &pc);
+ isec_e1 = lineart_intersect_seg_seg(LFBC, RFBC, FBC0, FBC1, &cross_ratios[0], &para_e1);
+ isec_e2 = lineart_intersect_seg_seg(LFBC, RFBC, FBC1, FBC2, &cross_ratios[1], &para_e2);
+ isec_e3 = lineart_intersect_seg_seg(LFBC, RFBC, FBC2, FBC0, &cross_ratios[2], &para_e3);
/* Sort the intersection distance. */
- INTERSECT_SORT_MIN_TO_MAX_3(is[0], is[1], is[2], order);
+ INTERSECT_SORT_MIN_TO_MAX_3(cross_ratios[0], cross_ratios[1], cross_ratios[2], cross_order);
- sub_v3_v3v3_db(Lv, e->v1->gloc, tri->v[0]->gloc);
- sub_v3_v3v3_db(Rv, e->v2->gloc, tri->v[0]->gloc);
+ sub_v3_v3v3_db(dir_v1, e->v1->gloc, tri->v[0]->gloc);
+ sub_v3_v3v3_db(dir_v2, e->v2->gloc, tri->v[0]->gloc);
- copy_v3_v3_db(Cv, camera_dir);
-
- if (override_cam_is_persp) {
- copy_v3_v3_db(vd4, override_camera_loc);
- }
- else {
- copy_v4_v4_db(vd4, override_camera_loc);
- }
+ copy_v3_v3_db(dir_cam, camera_dir);
+ copy_v3_v3_db(view_vector, override_camera_loc);
if (override_cam_is_persp) {
- sub_v3_v3v3_db(Cv, vd4, tri->v[0]->gloc);
+ sub_v3_v3v3_db(dir_cam, view_vector, tri->v[0]->gloc);
}
- dot_l = dot_v3v3_db(Lv, tri->gn);
- dot_r = dot_v3v3_db(Rv, tri->gn);
- dot_f = dot_v3v3_db(Cv, tri->gn);
+ dot_v1 = dot_v3v3_db(dir_v1, tri->gn);
+ dot_v2 = dot_v3v3_db(dir_v2, tri->gn);
+ dot_f = dot_v3v3_db(dir_cam, tri->gn);
/* NOTE(Yiming): When we don't use `dot_f==0` here, it's theoretically possible that _some_
* faces in perspective mode would get erroneously caught in this condition where they really
@@ -2726,40 +2759,39 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
return false;
}
+ /* Whether two end points are inside/on_the_edge/outside of the triangle. */
+ state_v1 = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2);
+ state_v2 = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2);
+
/* If the edge doesn't visually cross any edge of the triangle... */
- if (!a && !b && !c) {
+ if (!isec_e1 && !isec_e2 && !isec_e3) {
/* And if both end point from the edge is outside of the triangle... */
- if (!(st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2)) &&
- !(st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2))) {
+ if ((!state_v1) && (!state_v2)) {
return 0; /* We don't have any occlusion. */
}
}
- /* Whether two end points are inside/on_the_edge/outside of the triangle. */
- st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2);
- st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2);
-
/* Determine the cut position. */
- dot_la = fabs(dot_l);
- if (dot_la < DBL_EPSILON) {
- dot_la = 0;
- dot_l = 0;
+ dot_v1a = fabs(dot_v1);
+ if (dot_v1a < DBL_EPSILON) {
+ dot_v1a = 0;
+ dot_v1 = 0;
}
- dot_ra = fabs(dot_r);
- if (dot_ra < DBL_EPSILON) {
- dot_ra = 0;
- dot_r = 0;
+ dot_v2a = fabs(dot_v2);
+ if (dot_v2a < DBL_EPSILON) {
+ dot_v2a = 0;
+ dot_v2 = 0;
}
- if (dot_l - dot_r == 0) {
+ if (dot_v1 - dot_v2 == 0) {
cut = 100000;
}
- else if (dot_l * dot_r <= 0) {
- cut = dot_la / fabs(dot_l - dot_r);
+ else if (dot_v1 * dot_v2 <= 0) {
+ cut = dot_v1a / fabs(dot_v1 - dot_v2);
}
else {
- cut = fabs(dot_r + dot_l) / fabs(dot_l - dot_r);
- cut = dot_ra > dot_la ? 1 - cut : cut;
+ cut = fabs(dot_v2 + dot_v1) / fabs(dot_v1 - dot_v2);
+ cut = dot_v2a > dot_v1a ? 1 - cut : cut;
}
/* Transform the cut from geometry space to image space. */
@@ -2780,7 +2812,7 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
}
#define LRT_GUARD_NOT_FOUND \
- if (LCross < 0 || RCross < 0) { \
+ if (cross_v1 < 0 || cross_v2 < 0) { \
return false; \
}
@@ -2788,95 +2820,97 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
* indicates triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision
* tolerance. */
- if (st_l == 2) {
+ if (state_v1 == LRT_INSIDE_TRIANGLE) {
/* Left side is in the triangle. */
- if (st_r == 2) {
+ if (state_v2 == LRT_INSIDE_TRIANGLE) {
/* | l---r | */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 1) {
+ else if (state_v2 == LRT_ON_TRIANGLE) {
/* | l------r| */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 0) {
+ else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
/* | l-------|------r */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 0, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 0, cross_v2);
}
}
- else if (st_l == 1) {
+ else if (state_v1 == LRT_ON_TRIANGLE) {
/* Left side is on some edge of the triangle. */
- if (st_r == 2) {
+ if (state_v2 == LRT_INSIDE_TRIANGLE) {
/* |l------r | */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 1) {
+ else if (state_v2 == LRT_ON_TRIANGLE) {
/* |l---------r| */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 0) {
+ else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
/* |l----------|-------r (crossing the triangle) [OR]
* r---------|l | (not crossing the triangle) */
- INTERSECT_JUST_GREATER(is, order, DBL_TRIANGLE_LIM, RCross);
- if (RCross >= 0 && LRT_ABC(RCross) && is[RCross] > (DBL_TRIANGLE_LIM)) {
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v2);
+ if (cross_v2 >= 0 && LRT_ISEC(cross_v2) && cross_ratios[cross_v2] > (DBL_TRIANGLE_LIM)) {
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
}
else {
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, RCross);
- if (RCross > 0) {
- INTERSECT_JUST_SMALLER(is, order, is[RCross], LCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v2);
+ if (cross_v2 > 0) {
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, cross_ratios[cross_v2], cross_v1);
}
}
LRT_GUARD_NOT_FOUND
/* We could have the edge being completely parallel to the triangle where there isn't a
* viable occlusion result. */
- if ((LRT_PABC(LCross) && !LRT_ABC(LCross)) || (LRT_PABC(RCross) && !LRT_ABC(RCross))) {
+ if ((LRT_PARALLEL(cross_v1) && !LRT_ISEC(cross_v1)) ||
+ (LRT_PARALLEL(cross_v2) && !LRT_ISEC(cross_v2))) {
return false;
}
}
}
- else if (st_l == 0) {
+ else if (state_v1 == LRT_OUTSIDE_TRIANGLE) {
/* Left side is outside of the triangle. */
- if (st_r == 2) {
+ if (state_v2 == LRT_INSIDE_TRIANGLE) {
/* l---|---r | */
- INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 1) {
+ else if (state_v2 == LRT_ON_TRIANGLE) {
/* |r----------|-------l (crossing the triangle) [OR]
* l---------|r | (not crossing the triangle) */
- INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
- if (LCross >= 0 && LRT_ABC(LCross) && is[LCross] < (1 - DBL_TRIANGLE_LIM)) {
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
+ if (cross_v1 >= 0 && LRT_ISEC(cross_v1) && cross_ratios[cross_v1] < (1 - DBL_TRIANGLE_LIM)) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
else {
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
- if (LCross > 0) {
- INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
+ if (cross_v1 > 0) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
}
}
LRT_GUARD_NOT_FOUND
/* The same logic applies as above case. */
- if ((LRT_PABC(LCross) && !LRT_ABC(LCross)) || (LRT_PABC(RCross) && !LRT_ABC(RCross))) {
+ if ((LRT_PARALLEL(cross_v1) && !LRT_ISEC(cross_v1)) ||
+ (LRT_PARALLEL(cross_v2) && !LRT_ISEC(cross_v2))) {
return false;
}
}
- else if (st_r == 0) {
+ else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
/* l---|----|----r (crossing the triangle) [OR]
* l----r | | (not crossing the triangle) */
- INTERSECT_JUST_GREATER(is, order, -DBL_TRIANGLE_LIM, LCross);
- if (LCross >= 0 && LRT_ABC(LCross)) {
- INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, -DBL_TRIANGLE_LIM, cross_v1);
+ if (cross_v1 >= 0 && LRT_ISEC(cross_v1)) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
}
else {
- if (LCross >= 0) {
- INTERSECT_JUST_GREATER(is, order, is[LCross], LCross);
- if (LCross >= 0) {
- INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ if (cross_v1 >= 0) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v1);
+ if (cross_v1 >= 0) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
}
}
}
@@ -2885,28 +2919,28 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
LRT_GUARD_NOT_FOUND
- double LF = dot_l * dot_f, RF = dot_r * dot_f;
+ double dot_1f = dot_v1 * dot_f, dot_2f = dot_v2 * dot_f;
/* Determine the start and end point of image space cut on a line. */
- if (LF <= 0 && RF <= 0 && (dot_l || dot_r)) {
- *from = MAX2(0, is[LCross]);
- *to = MIN2(1, is[RCross]);
+ if (dot_1f <= 0 && dot_2f <= 0 && (dot_v1 || dot_v2)) {
+ *from = MAX2(0, cross_ratios[cross_v1]);
+ *to = MIN2(1, cross_ratios[cross_v2]);
if (*from >= *to) {
return false;
}
return true;
}
- if (LF >= 0 && RF <= 0 && (dot_l || dot_r)) {
- *from = MAX2(cut, is[LCross]);
- *to = MIN2(1, is[RCross]);
+ if (dot_1f >= 0 && dot_2f <= 0 && (dot_v1 || dot_v2)) {
+ *from = MAX2(cut, cross_ratios[cross_v1]);
+ *to = MIN2(1, cross_ratios[cross_v2]);
if (*from >= *to) {
return false;
}
return true;
}
- if (LF <= 0 && RF >= 0 && (dot_l || dot_r)) {
- *from = MAX2(0, is[LCross]);
- *to = MIN2(cut, is[RCross]);
+ if (dot_1f <= 0 && dot_2f >= 0 && (dot_v1 || dot_v2)) {
+ *from = MAX2(0, cross_ratios[cross_v1]);
+ *to = MIN2(cut, cross_ratios[cross_v2]);
if (*from >= *to) {
return false;
}
@@ -2920,6 +2954,8 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
#undef INTERSECT_SORT_MIN_TO_MAX_3
#undef INTERSECT_JUST_GREATER
#undef INTERSECT_JUST_SMALLER
+#undef LRT_ISEC
+#undef LRT_PARALLEL
/**
* At this stage of the computation we don't have triangle adjacent info anymore,
@@ -3001,272 +3037,239 @@ static LineartVert *lineart_triangle_share_point(const LineartTriangle *l,
return NULL;
}
-/**
- * To save time and prevent overlapping lines when computing intersection lines.
- */
-static bool lineart_vert_already_intersected_2v(LineartVertIntersection *vt,
- LineartVertIntersection *v1,
- LineartVertIntersection *v2)
-{
- return ((vt->isec1 == v1->base.index && vt->isec2 == v2->base.index) ||
- (vt->isec2 == v2->base.index && vt->isec1 == v1->base.index));
-}
-
-static void lineart_vert_set_intersection_2v(LineartVert *vt, LineartVert *v1, LineartVert *v2)
+static bool lineart_triangle_2v_intersection_math(
+ LineartVert *v1, LineartVert *v2, LineartTriangle *tri, double *last, double *rv)
{
- LineartVertIntersection *irv = (LineartVertIntersection *)vt;
- irv->isec1 = v1->index;
- irv->isec2 = v2->index;
-}
-
-/**
- * This tests a triangle against a virtual line represented by `v1---v2`.
- * The vertices returned after repeated calls to this function
- * is then used to create a triangle/triangle intersection line.
- */
-static LineartVert *lineart_triangle_2v_intersection_test(LineartRenderBuffer *rb,
- LineartVert *v1,
- LineartVert *v2,
- LineartTriangle *tri,
- LineartTriangle *testing,
- LineartVert *last)
-{
- double Lv[3];
- double Rv[3];
- double dot_l, dot_r;
- LineartVert *result;
+ /* Direction vectors for the edge verts. We will check if the verts are on the same side of the
+ * triangle or not. */
+ double dir_v1[3], dir_v2[3];
+ double dot_v1, dot_v2;
double gloc[3];
- LineartVert *l = v1, *r = v2;
-
- for (LinkNode *ln = (void *)testing->intersecting_verts; ln; ln = ln->next) {
- LineartVertIntersection *vt = ln->link;
- if (vt->intersecting_with == tri &&
- lineart_vert_already_intersected_2v(
- vt, (LineartVertIntersection *)l, (LineartVertIntersection *)r)) {
- return (LineartVert *)vt;
- }
- }
- sub_v3_v3v3_db(Lv, l->gloc, testing->v[0]->gloc);
- sub_v3_v3v3_db(Rv, r->gloc, testing->v[0]->gloc);
+ sub_v3_v3v3_db(dir_v1, v1->gloc, tri->v[0]->gloc);
+ sub_v3_v3v3_db(dir_v2, v2->gloc, tri->v[0]->gloc);
- dot_l = dot_v3v3_db(Lv, testing->gn);
- dot_r = dot_v3v3_db(Rv, testing->gn);
+ dot_v1 = dot_v3v3_db(dir_v1, tri->gn);
+ dot_v2 = dot_v3v3_db(dir_v2, tri->gn);
- if (dot_l * dot_r > 0 || (!dot_l && !dot_r)) {
- return 0;
+ if (dot_v1 * dot_v2 > 0 || (!dot_v1 && !dot_v2)) {
+ return false;
}
- dot_l = fabs(dot_l);
- dot_r = fabs(dot_r);
+ dot_v1 = fabs(dot_v1);
+ dot_v2 = fabs(dot_v2);
- interp_v3_v3v3_db(gloc, l->gloc, r->gloc, dot_l / (dot_l + dot_r));
+ interp_v3_v3v3_db(gloc, v1->gloc, v2->gloc, dot_v1 / (dot_v1 + dot_v2));
- /* Due to precision issue, we might end up with the same point as the one we already detected.
- */
- if (last && LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[0], gloc[0]) &&
- LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[1], gloc[1]) &&
- LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[2], gloc[2])) {
- return NULL;
+ /* Due to precision issue, we might end up with the same point as the one we already detected. */
+ if (last && LRT_DOUBLE_CLOSE_ENOUGH(last[0], gloc[0]) &&
+ LRT_DOUBLE_CLOSE_ENOUGH(last[1], gloc[1]) && LRT_DOUBLE_CLOSE_ENOUGH(last[2], gloc[2])) {
+ return false;
}
if (!(lineart_point_inside_triangle3d(
- gloc, testing->v[0]->gloc, testing->v[1]->gloc, testing->v[2]->gloc))) {
- return NULL;
+ gloc, tri->v[0]->gloc, tri->v[1]->gloc, tri->v[2]->gloc))) {
+ return false;
}
- /* This is an intersection vert, the size is bigger than LineartVert,
- * allocated separately. */
- result = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartVertIntersection));
-
- /* Indicate the data structure difference. */
- result->flag = LRT_VERT_HAS_INTERSECTION_DATA;
+ copy_v3_v3_db(rv, gloc);
- copy_v3_v3_db(result->gloc, gloc);
-
- lineart_prepend_pool(&testing->intersecting_verts, &rb->render_data_pool, result);
-
- return result;
+ return true;
}
-/**
- * Test if two triangles intersect. Generates one intersection line if the check succeeds.
- */
-static LineartEdge *lineart_triangle_intersect(LineartRenderBuffer *rb,
- LineartTriangle *tri,
- LineartTriangle *testing)
+static bool lineart_triangle_intersect_math(LineartTriangle *tri,
+ LineartTriangle *t2,
+ double *v1,
+ double *v2)
{
- LineartVert *v1 = 0, *v2 = 0;
- LineartVert **next = &v1;
- LineartEdge *result;
- LineartVert *E0T = 0;
- LineartVert *E1T = 0;
- LineartVert *E2T = 0;
- LineartVert *TE0 = 0;
- LineartVert *TE1 = 0;
- LineartVert *TE2 = 0;
+ double *next = v1, *last = NULL;
LineartVert *sv1, *sv2;
- double cl[3];
- double ZMin, ZMax;
- ZMax = rb->far_clip;
- ZMin = rb->near_clip;
- copy_v3_v3_db(cl, rb->camera_pos);
- LineartVert *share = lineart_triangle_share_point(testing, tri);
+ LineartVert *share = lineart_triangle_share_point(t2, tri);
if (share) {
/* If triangles have sharing points like `abc` and `acd`, then we only need to detect `bc`
* against `acd` or `cd` against `abc`. */
- LineartVert *new_share;
lineart_triangle_get_other_verts(tri, share, &sv1, &sv2);
- v1 = new_share = lineart_mem_acquire(&rb->render_data_pool, (sizeof(LineartVertIntersection)));
-
- new_share->flag = LRT_VERT_HAS_INTERSECTION_DATA;
-
- copy_v3_v3_db(new_share->gloc, share->gloc);
-
- v2 = lineart_triangle_2v_intersection_test(rb, sv1, sv2, tri, testing, 0);
+ copy_v3_v3_db(v1, share->gloc);
- if (v2 == NULL) {
- lineart_triangle_get_other_verts(testing, share, &sv1, &sv2);
- v2 = lineart_triangle_2v_intersection_test(rb, sv1, sv2, testing, tri, 0);
- if (v2 == NULL) {
- return 0;
+ if (!lineart_triangle_2v_intersection_math(sv1, sv2, t2, 0, v2)) {
+ lineart_triangle_get_other_verts(t2, share, &sv1, &sv2);
+ if (lineart_triangle_2v_intersection_math(sv1, sv2, tri, 0, v2)) {
+ return true;
}
- lineart_prepend_pool(&testing->intersecting_verts, &rb->render_data_pool, new_share);
- }
- else {
- lineart_prepend_pool(&tri->intersecting_verts, &rb->render_data_pool, new_share);
}
}
else {
/* If not sharing any points, then we need to try all the possibilities. */
- E0T = lineart_triangle_2v_intersection_test(rb, tri->v[0], tri->v[1], tri, testing, 0);
- if (E0T && (!(*next))) {
- (*next) = E0T;
- lineart_vert_set_intersection_2v((*next), tri->v[0], tri->v[1]);
- next = &v2;
- }
- E1T = lineart_triangle_2v_intersection_test(rb, tri->v[1], tri->v[2], tri, testing, v1);
- if (E1T && (!(*next))) {
- (*next) = E1T;
- lineart_vert_set_intersection_2v((*next), tri->v[1], tri->v[2]);
- next = &v2;
- }
- if (!(*next)) {
- E2T = lineart_triangle_2v_intersection_test(rb, tri->v[2], tri->v[0], tri, testing, v1);
- }
- if (E2T && (!(*next))) {
- (*next) = E2T;
- lineart_vert_set_intersection_2v((*next), tri->v[2], tri->v[0]);
- next = &v2;
+ if (lineart_triangle_2v_intersection_math(tri->v[0], tri->v[1], t2, 0, v1)) {
+ next = v2;
+ last = v1;
}
- if (!(*next)) {
- TE0 = lineart_triangle_2v_intersection_test(
- rb, testing->v[0], testing->v[1], testing, tri, v1);
- }
- if (TE0 && (!(*next))) {
- (*next) = TE0;
- lineart_vert_set_intersection_2v((*next), testing->v[0], testing->v[1]);
- next = &v2;
+ if (lineart_triangle_2v_intersection_math(tri->v[1], tri->v[2], t2, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (!(*next)) {
- TE1 = lineart_triangle_2v_intersection_test(
- rb, testing->v[1], testing->v[2], testing, tri, v1);
+ if (lineart_triangle_2v_intersection_math(tri->v[2], tri->v[0], t2, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (TE1 && (!(*next))) {
- (*next) = TE1;
- lineart_vert_set_intersection_2v((*next), testing->v[1], testing->v[2]);
- next = &v2;
+
+ if (lineart_triangle_2v_intersection_math(t2->v[0], t2->v[1], tri, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (!(*next)) {
- TE2 = lineart_triangle_2v_intersection_test(
- rb, testing->v[2], testing->v[0], testing, tri, v1);
+ if (lineart_triangle_2v_intersection_math(t2->v[1], t2->v[2], tri, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (TE2 && (!(*next))) {
- (*next) = TE2;
- lineart_vert_set_intersection_2v((*next), testing->v[2], testing->v[0]);
- next = &v2;
+ if (lineart_triangle_2v_intersection_math(t2->v[2], t2->v[0], tri, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
+ }
+ return false;
+}
- if (!(*next)) {
- return 0;
- }
+static void lineart_add_isec_thread(LineartIsecThread *th,
+ const double *v1,
+ const double *v2,
+ LineartTriangle *tri1,
+ LineartTriangle *tri2)
+{
+ if (th->current == th->max) {
+
+ LineartIsecSingle *new_array = MEM_mallocN(sizeof(LineartIsecSingle) * th->max * 2,
+ "LineartIsecSingle");
+ memcpy(new_array, th->array, sizeof(LineartIsecSingle) * th->max);
+ th->max *= 2;
+ MEM_freeN(th->array);
+ th->array = new_array;
+ }
+ LineartIsecSingle *isec_single = &th->array[th->current];
+ copy_v3fl_v3db(isec_single->v1, v1);
+ copy_v3fl_v3db(isec_single->v2, v2);
+ isec_single->tri1 = tri1;
+ isec_single->tri2 = tri2;
+ th->current++;
+}
+
+#define LRT_ISECT_TRIANGLE_PER_THREAD 4096
+
+static bool lineart_schedule_new_triangle_task(LineartIsecThread *th)
+{
+ LineartData *ld = th->ld;
+ int remaining = LRT_ISECT_TRIANGLE_PER_THREAD;
+
+ BLI_spin_lock(&ld->lock_task);
+ LineartElementLinkNode *eln = ld->isect_scheduled_up_to;
+
+ if (!eln) {
+ BLI_spin_unlock(&ld->lock_task);
+ return false;
}
- /* The intersection line has been generated only in geometry space, so we need to transform
- * them as well. */
- mul_v4_m4v3_db(v1->fbcoord, rb->view_projection, v1->gloc);
- mul_v4_m4v3_db(v2->fbcoord, rb->view_projection, v2->gloc);
- if (rb->cam_is_persp) {
- mul_v3db_db(v1->fbcoord, (1 / v1->fbcoord[3]));
- mul_v3db_db(v2->fbcoord, (1 / v2->fbcoord[3]));
+ th->pending_from = eln;
+ th->index_from = ld->isect_scheduled_up_to_index;
+
+ while (remaining > 0 && eln) {
+ int remaining_this_eln = eln->element_count - ld->isect_scheduled_up_to_index;
+ int added_count = MIN2(remaining, remaining_this_eln);
+ remaining -= added_count;
+ if (remaining || added_count == remaining_this_eln) {
+ eln = eln->next;
+ ld->isect_scheduled_up_to = eln;
+ ld->isect_scheduled_up_to_index = 0;
+ }
+ else {
+ ld->isect_scheduled_up_to_index += added_count;
+ }
}
- v1->fbcoord[0] -= rb->shift_x * 2;
- v1->fbcoord[1] -= rb->shift_y * 2;
- v2->fbcoord[0] -= rb->shift_x * 2;
- v2->fbcoord[1] -= rb->shift_y * 2;
- /* This z transformation is not the same as the rest of the part, because the data don't go
- * through normal perspective division calls in the pipeline, but this way the 3D result and
- * occlusion on the generated line is correct, and we don't really use 2D for viewport stroke
- * generation anyway. */
- v1->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v1->fbcoord[2]) * (ZMax - ZMin));
- v2->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v2->fbcoord[2]) * (ZMax - ZMin));
+ th->pending_to = eln ? eln : ld->geom.triangle_buffer_pointers.last;
+ th->index_to = ld->isect_scheduled_up_to_index;
- ((LineartVertIntersection *)v1)->intersecting_with = tri;
- ((LineartVertIntersection *)v2)->intersecting_with = testing;
+ BLI_spin_unlock(&ld->lock_task);
- result = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdge));
- result->v1 = v1;
- result->v2 = v2;
- result->t1 = tri;
- result->t2 = testing;
+ return true;
+}
- LineartEdgeSegment *es = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeSegment));
- BLI_addtail(&result->segments, es);
- /* Don't need to OR flags right now, just a type mark. */
- result->flags = LRT_EDGE_FLAG_INTERSECTION;
- result->intersection_mask = (tri->intersection_mask | testing->intersection_mask);
+/* This function initializes two things:
+ * 1) Triangle array scheduling info, for each worker thread to get its chunk from the scheduler.
+ * 2) Per-thread intersection result array. Does not store actual #LineartEdge, these results will
+ * be finalized by #lineart_create_edges_from_isec_data
+ */
+static void lineart_init_isec_thread(LineartIsecData *d, LineartData *ld, int thread_count)
+{
+ d->threads = MEM_callocN(sizeof(LineartIsecThread) * thread_count, "LineartIsecThread arr");
+ d->ld = ld;
+ d->thread_count = thread_count;
- lineart_add_edge_to_array(&rb->pending_edges, result);
+ ld->isect_scheduled_up_to = ld->geom.triangle_buffer_pointers.first;
+ ld->isect_scheduled_up_to_index = 0;
- return result;
+ for (int i = 0; i < thread_count; i++) {
+ LineartIsecThread *it = &d->threads[i];
+ it->array = MEM_mallocN(sizeof(LineartIsecSingle) * 100, "LineartIsecSingle arr");
+ it->max = 100;
+ it->current = 0;
+ it->thread_id = i;
+ it->ld = ld;
+ }
}
-static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb,
- LineartTriangle *tri,
- LineartBoundingArea *ba)
+static void lineart_destroy_isec_thread(LineartIsecData *d)
{
- /* Testing_triangle->testing[0] is used to store pairing triangle reference.
- * See definition of LineartTriangleThread for more info. */
- LineartTriangle *testing_triangle;
- LineartTriangleThread *tt;
+ for (int i = 0; i < d->thread_count; i++) {
+ LineartIsecThread *it = &d->threads[i];
+ MEM_freeN(it->array);
+ }
+ MEM_freeN(d->threads);
+}
- double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc;
+static void lineart_triangle_intersect_in_bounding_area(LineartTriangle *tri,
+ LineartBoundingArea *ba,
+ LineartIsecThread *th,
+ int up_to)
+{
+ BLI_assert(th != NULL);
- /* 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]);
- lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[2]);
- lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[3]);
+ if (!th) {
return;
}
- /* If this _is_ the smallest subdiv bounding area, then do the intersections there. */
- for (int i = 0; i < ba->triangle_count; i++) {
- testing_triangle = ba->linked_triangles[i];
- tt = (LineartTriangleThread *)testing_triangle;
+ double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc;
+
+ /* If this _is_ the smallest subdivision bounding area, then do the intersections there. */
+ for (int i = 0; i < up_to; i++) {
+ /* Testing_triangle->testing[0] is used to store pairing triangle reference.
+ * See definition of LineartTriangleThread for more info. */
+ LineartTriangle *testing_triangle = ba->linked_triangles[i];
+ LineartTriangleThread *tt = (LineartTriangleThread *)testing_triangle;
- if (testing_triangle == tri || tt->testing_e[0] == (LineartEdge *)tri) {
+ if (testing_triangle == tri || tt->testing_e[th->thread_id] == (LineartEdge *)tri) {
continue;
}
- tt->testing_e[0] = (LineartEdge *)tri;
+ tt->testing_e[th->thread_id] = (LineartEdge *)tri;
if ((testing_triangle->flags & LRT_TRIANGLE_NO_INTERSECTION) ||
((testing_triangle->flags & LRT_TRIANGLE_INTERSECTION_ONLY) &&
@@ -3289,21 +3292,25 @@ static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb,
}
/* If we do need to compute intersection, then finally do it. */
- lineart_triangle_intersect(rb, tri, testing_triangle);
+
+ double iv1[3], iv2[3];
+ if (lineart_triangle_intersect_math(tri, testing_triangle, iv1, iv2)) {
+ lineart_add_isec_thread(th, iv1, iv2, tri, testing_triangle);
+ }
}
}
/**
* The calculated view vector will point towards the far-plane from the camera position.
*/
-static void lineart_main_get_view_vector(LineartRenderBuffer *rb)
+static void lineart_main_get_view_vector(LineartData *ld)
{
float direction[3] = {0, 0, 1};
float trans[3];
float inv[4][4];
float obmat_no_scale[4][4];
- copy_m4_m4(obmat_no_scale, rb->cam_obmat);
+ copy_m4_m4(obmat_no_scale, ld->conf.cam_obmat);
normalize_v3(obmat_no_scale[0]);
normalize_v3(obmat_no_scale[1]);
@@ -3311,43 +3318,45 @@ static void lineart_main_get_view_vector(LineartRenderBuffer *rb)
invert_m4_m4(inv, obmat_no_scale);
transpose_m4(inv);
mul_v3_mat3_m4v3(trans, inv, direction);
- copy_m4_m4(rb->cam_obmat, obmat_no_scale);
- copy_v3db_v3fl(rb->view_vector, trans);
+ copy_m4_m4(ld->conf.cam_obmat, obmat_no_scale);
+ copy_v3db_v3fl(ld->conf.view_vector, trans);
}
-static void lineart_destroy_render_data(LineartRenderBuffer *rb)
+static void lineart_destroy_render_data(LineartData *ld)
{
- if (rb == NULL) {
+ if (ld == NULL) {
return;
}
- BLI_listbase_clear(&rb->chains);
- BLI_listbase_clear(&rb->wasted_cuts);
+ BLI_listbase_clear(&ld->chains);
+ BLI_listbase_clear(&ld->wasted_cuts);
- BLI_listbase_clear(&rb->vertex_buffer_pointers);
- BLI_listbase_clear(&rb->line_buffer_pointers);
- BLI_listbase_clear(&rb->triangle_buffer_pointers);
+ BLI_listbase_clear(&ld->geom.vertex_buffer_pointers);
+ BLI_listbase_clear(&ld->geom.line_buffer_pointers);
+ BLI_listbase_clear(&ld->geom.triangle_buffer_pointers);
- BLI_spin_end(&rb->lock_task);
- BLI_spin_end(&rb->lock_cuts);
- BLI_spin_end(&rb->render_data_pool.lock_mem);
+ BLI_spin_end(&ld->lock_task);
+ BLI_spin_end(&ld->lock_cuts);
+ BLI_spin_end(&ld->render_data_pool.lock_mem);
- if (rb->pending_edges.array) {
- MEM_freeN(rb->pending_edges.array);
+ if (ld->pending_edges.array) {
+ MEM_freeN(ld->pending_edges.array);
}
- lineart_mem_destroy(&rb->render_data_pool);
+ lineart_free_bounding_area_memories(ld);
+
+ lineart_mem_destroy(&ld->render_data_pool);
}
void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd)
{
- LineartRenderBuffer *rb = lmd->render_buffer_ptr;
+ LineartData *ld = lmd->la_data_ptr;
- lineart_destroy_render_data(rb);
+ lineart_destroy_render_data(ld);
- if (rb) {
- MEM_freeN(rb);
- lmd->render_buffer_ptr = NULL;
+ if (ld) {
+ MEM_freeN(ld);
+ lmd->la_data_ptr = NULL;
}
if (G.debug_value == 4000) {
@@ -3371,16 +3380,16 @@ void MOD_lineart_clear_cache(struct LineartCache **lc)
(*lc) = NULL;
}
-static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
- LineartGpencilModifierData *lmd,
- Object *camera,
- Object *active_camera,
- LineartCache *lc)
+static LineartData *lineart_create_render_buffer(Scene *scene,
+ LineartGpencilModifierData *lmd,
+ Object *camera,
+ Object *active_camera,
+ LineartCache *lc)
{
- LineartRenderBuffer *rb = MEM_callocN(sizeof(LineartRenderBuffer), "Line Art render buffer");
+ LineartData *ld = MEM_callocN(sizeof(LineartData), "Line Art render buffer");
lmd->cache = lc;
- lmd->render_buffer_ptr = rb;
+ lmd->la_data_ptr = ld;
lc->rb_edge_types = lmd->edge_types_override;
if (!scene || !camera || !lc) {
@@ -3394,98 +3403,98 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
clipping_offset = 0.0001;
}
- copy_v3db_v3fl(rb->camera_pos, camera->obmat[3]);
+ copy_v3db_v3fl(ld->conf.camera_pos, camera->obmat[3]);
if (active_camera) {
- copy_v3db_v3fl(rb->active_camera_pos, active_camera->obmat[3]);
+ copy_v3db_v3fl(ld->conf.active_camera_pos, active_camera->obmat[3]);
}
- copy_m4_m4(rb->cam_obmat, camera->obmat);
- rb->cam_is_persp = (c->type == CAM_PERSP);
- rb->near_clip = c->clip_start + clipping_offset;
- rb->far_clip = c->clip_end - clipping_offset;
- rb->w = scene->r.xsch;
- rb->h = scene->r.ysch;
+ copy_m4_m4(ld->conf.cam_obmat, camera->obmat);
+
+ ld->conf.cam_is_persp = (c->type == CAM_PERSP);
+ ld->conf.near_clip = c->clip_start + clipping_offset;
+ ld->conf.far_clip = c->clip_end - clipping_offset;
+ ld->w = scene->r.xsch;
+ ld->h = scene->r.ysch;
- if (rb->cam_is_persp) {
- rb->tile_recursive_level = LRT_TILE_RECURSIVE_PERSPECTIVE;
+ if (ld->conf.cam_is_persp) {
+ ld->qtree.recursive_level = LRT_TILE_RECURSIVE_PERSPECTIVE;
}
else {
- rb->tile_recursive_level = LRT_TILE_RECURSIVE_ORTHO;
+ ld->qtree.recursive_level = LRT_TILE_RECURSIVE_ORTHO;
}
- double asp = ((double)rb->w / (double)rb->h);
- int fit = BKE_camera_sensor_fit(c->sensor_fit, rb->w, rb->h);
- rb->shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp;
- rb->shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp;
+ double asp = ((double)ld->w / (double)ld->h);
+ int fit = BKE_camera_sensor_fit(c->sensor_fit, ld->w, ld->h);
+ ld->conf.shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp;
+ ld->conf.shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp;
- rb->overscan = lmd->overscan;
+ ld->conf.overscan = lmd->overscan;
- rb->shift_x /= (1 + rb->overscan);
- rb->shift_y /= (1 + rb->overscan);
+ ld->conf.shift_x /= (1 + ld->conf.overscan);
+ ld->conf.shift_y /= (1 + ld->conf.overscan);
- rb->crease_threshold = cos(M_PI - lmd->crease_threshold);
- rb->chaining_image_threshold = lmd->chaining_image_threshold;
- rb->angle_splitting_threshold = lmd->angle_splitting_threshold;
- rb->chain_smooth_tolerance = lmd->chain_smooth_tolerance;
+ ld->conf.crease_threshold = cos(M_PI - lmd->crease_threshold);
+ ld->conf.chaining_image_threshold = lmd->chaining_image_threshold;
+ ld->conf.angle_splitting_threshold = lmd->angle_splitting_threshold;
+ ld->conf.chain_smooth_tolerance = lmd->chain_smooth_tolerance;
- 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->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;
- rb->use_image_boundary_trimming = (lmd->calculation_flags & LRT_USE_IMAGE_BOUNDARY_TRIMMING) !=
- 0;
+ ld->conf.fuzzy_intersections = (lmd->calculation_flags & LRT_INTERSECTION_AS_CONTOUR) != 0;
+ ld->conf.fuzzy_everything = (lmd->calculation_flags & LRT_EVERYTHING_AS_CONTOUR) != 0;
+ ld->conf.allow_boundaries = (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) != 0;
+ ld->conf.use_loose_as_contour = (lmd->calculation_flags & LRT_LOOSE_AS_CONTOUR) != 0;
+ ld->conf.use_loose_edge_chain = (lmd->calculation_flags & LRT_CHAIN_LOOSE_EDGES) != 0;
+ ld->conf.use_geometry_space_chain = (lmd->calculation_flags & LRT_CHAIN_GEOMETRY_SPACE) != 0;
+ ld->conf.use_image_boundary_trimming = (lmd->calculation_flags &
+ LRT_USE_IMAGE_BOUNDARY_TRIMMING) != 0;
/* See lineart_edge_from_triangle() for how this option may impact performance. */
- rb->allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0;
+ ld->conf.allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0;
- rb->allow_duplicated_types = (lmd->calculation_flags & LRT_ALLOW_OVERLAP_EDGE_TYPES) != 0;
+ ld->conf.allow_duplicated_types = (lmd->calculation_flags & LRT_ALLOW_OVERLAP_EDGE_TYPES) != 0;
- rb->force_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SMOOTH_SURFACES) != 0;
- rb->sharp_as_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SHARP_EDGES) != 0;
+ ld->conf.force_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SMOOTH_SURFACES) != 0;
+ ld->conf.sharp_as_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SHARP_EDGES) != 0;
- rb->chain_preserve_details = (lmd->calculation_flags & LRT_CHAIN_PRESERVE_DETAILS) != 0;
+ ld->conf.chain_preserve_details = (lmd->calculation_flags & LRT_CHAIN_PRESERVE_DETAILS) != 0;
/* This is used to limit calculation to a certain level to save time, lines who have higher
* occlusion levels will get ignored. */
- rb->max_occlusion_level = lmd->level_end_override;
+ ld->conf.max_occlusion_level = lmd->level_end_override;
- rb->use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0;
+ ld->conf.use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0;
int16_t edge_types = lmd->edge_types_override;
- rb->use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
- rb->use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0;
- rb->use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0;
- rb->use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0;
- rb->use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0;
- rb->use_loose = (edge_types & LRT_EDGE_FLAG_LOOSE) != 0;
+ ld->conf.use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
+ ld->conf.use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0;
+ ld->conf.use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0;
+ ld->conf.use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0;
+ ld->conf.use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0;
+ ld->conf.use_loose = (edge_types & LRT_EDGE_FLAG_LOOSE) != 0;
- rb->filter_face_mark_invert = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_INVERT) != 0;
- rb->filter_face_mark = (lmd->calculation_flags & LRT_FILTER_FACE_MARK) != 0;
- rb->filter_face_mark_boundaries = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_BOUNDARIES) !=
- 0;
- rb->filter_face_mark_keep_contour = (lmd->calculation_flags &
- LRT_FILTER_FACE_MARK_KEEP_CONTOUR) != 0;
+ ld->conf.filter_face_mark_invert = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_INVERT) != 0;
+ ld->conf.filter_face_mark = (lmd->calculation_flags & LRT_FILTER_FACE_MARK) != 0;
+ ld->conf.filter_face_mark_boundaries = (lmd->calculation_flags &
+ LRT_FILTER_FACE_MARK_BOUNDARIES) != 0;
+ ld->conf.filter_face_mark_keep_contour = (lmd->calculation_flags &
+ LRT_FILTER_FACE_MARK_KEEP_CONTOUR) != 0;
- rb->chain_data_pool = &lc->chain_data_pool;
+ ld->chain_data_pool = &lc->chain_data_pool;
- BLI_spin_init(&rb->lock_task);
- BLI_spin_init(&rb->lock_cuts);
- BLI_spin_init(&rb->render_data_pool.lock_mem);
+ BLI_spin_init(&ld->lock_task);
+ BLI_spin_init(&ld->lock_cuts);
+ BLI_spin_init(&ld->render_data_pool.lock_mem);
- return rb;
+ ld->thread_count = BKE_render_num_threads(&scene->r);
+
+ return ld;
}
-static int lineart_triangle_size_get(const Scene *scene, LineartRenderBuffer *rb)
+static int lineart_triangle_size_get(LineartData *ld)
{
- if (rb->thread_count == 0) {
- rb->thread_count = BKE_render_num_threads(&scene->r);
- }
- return sizeof(LineartTriangle) + (sizeof(LineartEdge *) * (rb->thread_count));
+ return sizeof(LineartTriangle) + (sizeof(LineartEdge *) * (ld->thread_count));
}
-static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
+static void lineart_main_bounding_area_make_initial(LineartData *ld)
{
/* Initial tile split is defined as 4 (subdivided as 4*4), increasing the value allows the
* algorithm to build the acceleration structure for bigger scenes a little faster but not as
@@ -3495,24 +3504,32 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
int row, col;
LineartBoundingArea *ba;
+ /* Always make sure the shortest side has at least LRT_BA_ROWS tiles. */
+ if (ld->w > ld->h) {
+ sp_w = sp_h * ld->w / ld->h;
+ }
+ else {
+ sp_h = sp_w * ld->h / ld->w;
+ }
+
/* Because NDC (Normalized Device Coordinates) range is (-1,1),
* so the span for each initial tile is double of that in the (0,1) range. */
double span_w = (double)1 / sp_w * 2.0;
double span_h = (double)1 / sp_h * 2.0;
- rb->tile_count_x = sp_w;
- rb->tile_count_y = sp_h;
- rb->width_per_tile = span_w;
- rb->height_per_tile = span_h;
+ ld->qtree.count_x = sp_w;
+ ld->qtree.count_y = sp_h;
+ ld->qtree.tile_width = span_w;
+ ld->qtree.tile_height = span_h;
- rb->bounding_area_count = sp_w * sp_h;
- rb->initial_bounding_areas = lineart_mem_acquire(
- &rb->render_data_pool, sizeof(LineartBoundingArea) * rb->bounding_area_count);
+ ld->qtree.tile_count = sp_w * sp_h;
+ ld->qtree.initials = lineart_mem_acquire(&ld->render_data_pool,
+ sizeof(LineartBoundingArea) * ld->qtree.tile_count);
/* Initialize tiles. */
for (row = 0; row < sp_h; row++) {
for (col = 0; col < sp_w; col++) {
- ba = &rb->initial_bounding_areas[row * LRT_BA_ROWS + col];
+ ba = &ld->qtree.initials[row * ld->qtree.count_x + col];
/* Set the four direction limits. */
ba->l = span_w * col - 1.0;
@@ -3526,34 +3543,12 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
/* Init linked_triangles array. */
ba->max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT;
ba->max_line_count = LRT_TILE_EDGE_COUNT_INITIAL;
- ba->linked_triangles = lineart_mem_acquire(
- &rb->render_data_pool, sizeof(LineartTriangle *) * ba->max_triangle_count);
- ba->linked_lines = lineart_mem_acquire(&rb->render_data_pool,
- sizeof(LineartEdge *) * ba->max_line_count);
+ ba->linked_triangles = MEM_callocN(sizeof(LineartTriangle *) * ba->max_triangle_count,
+ "ba_linked_triangles");
+ ba->linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba->max_line_count,
+ "ba_linked_lines");
- /* Link adjacent ones. */
- if (row) {
- lineart_list_append_pointer_pool(
- &ba->up,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[(row - 1) * LRT_BA_ROWS + col]);
- }
- if (col) {
- lineart_list_append_pointer_pool(&ba->lp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[row * LRT_BA_ROWS + col - 1]);
- }
- if (row != sp_h - 1) {
- lineart_list_append_pointer_pool(
- &ba->bp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[(row + 1) * LRT_BA_ROWS + col]);
- }
- if (col != sp_w - 1) {
- lineart_list_append_pointer_pool(&ba->rp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[row * LRT_BA_ROWS + col + 1]);
- }
+ BLI_spin_init(&ba->lock);
}
}
}
@@ -3561,11 +3556,11 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
/**
* Re-link adjacent tiles after one gets subdivided.
*/
-static void lineart_bounding_areas_connect_new(LineartRenderBuffer *rb, LineartBoundingArea *root)
+static void lineart_bounding_areas_connect_new(LineartData *ld, LineartBoundingArea *root)
{
LineartBoundingArea *ba = root->child, *tba;
LinkData *lip2, *next_lip;
- LineartStaticMemPool *mph = &rb->render_data_pool;
+ LineartStaticMemPool *mph = &ld->render_data_pool;
/* Inter-connection with newly created 4 child bounding areas. */
lineart_list_append_pointer_pool(&ba[1].rp, mph, &ba[0]);
@@ -3701,17 +3696,59 @@ static void lineart_bounding_areas_connect_new(LineartRenderBuffer *rb, LineartB
BLI_listbase_clear(&root->bp);
}
+static void lineart_bounding_areas_connect_recursive(LineartData *ld, LineartBoundingArea *root)
+{
+ if (root->child) {
+ lineart_bounding_areas_connect_new(ld, root);
+ for (int i = 0; i < 4; i++) {
+ lineart_bounding_areas_connect_recursive(ld, &root->child[i]);
+ }
+ }
+}
+
+static void lineart_main_bounding_areas_connect_post(LineartData *ld)
+{
+ int total_tile_initial = ld->qtree.count_x * ld->qtree.count_y;
+ int tiles_per_row = ld->qtree.count_x;
+
+ for (int row = 0; row < ld->qtree.count_y; row++) {
+ for (int col = 0; col < ld->qtree.count_x; col++) {
+ LineartBoundingArea *ba = &ld->qtree.initials[row * tiles_per_row + col];
+ /* Link adjacent ones. */
+ if (row) {
+ lineart_list_append_pointer_pool(
+ &ba->up, &ld->render_data_pool, &ld->qtree.initials[(row - 1) * tiles_per_row + col]);
+ }
+ if (col) {
+ lineart_list_append_pointer_pool(
+ &ba->lp, &ld->render_data_pool, &ld->qtree.initials[row * tiles_per_row + col - 1]);
+ }
+ if (row != ld->qtree.count_y - 1) {
+ lineart_list_append_pointer_pool(
+ &ba->bp, &ld->render_data_pool, &ld->qtree.initials[(row + 1) * tiles_per_row + col]);
+ }
+ if (col != ld->qtree.count_x - 1) {
+ lineart_list_append_pointer_pool(
+ &ba->rp, &ld->render_data_pool, &ld->qtree.initials[row * tiles_per_row + col + 1]);
+ }
+ }
+ }
+ for (int i = 0; i < total_tile_initial; i++) {
+ lineart_bounding_areas_connect_recursive(ld, &ld->qtree.initials[i]);
+ }
+}
+
/**
- * Subdivide a tile after one tile contains too many triangles.
+ * Subdivide a tile after one tile contains too many triangles, then re-link triangles into all the
+ * child tiles.
*/
-static void lineart_bounding_area_split(LineartRenderBuffer *rb,
+static void lineart_bounding_area_split(LineartData *ld,
LineartBoundingArea *root,
int recursive_level)
{
- LineartBoundingArea *ba = lineart_mem_acquire(&rb->render_data_pool,
- sizeof(LineartBoundingArea) * 4);
- LineartTriangle *tri;
+ LineartBoundingArea *ba = lineart_mem_acquire_thread(&ld->render_data_pool,
+ sizeof(LineartBoundingArea) * 4);
ba[0].l = root->cx;
ba[0].r = root->r;
ba[0].u = root->u;
@@ -3740,51 +3777,55 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb,
ba[3].cx = (ba[3].l + ba[3].r) / 2;
ba[3].cy = (ba[3].u + ba[3].b) / 2;
- root->child = ba;
-
- lineart_bounding_areas_connect_new(rb, root);
-
- /* Init linked_triangles array. */
+ /* Init linked_triangles array and locks. */
for (int i = 0; i < 4; i++) {
ba[i].max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT;
ba[i].max_line_count = LRT_TILE_EDGE_COUNT_INITIAL;
- ba[i].linked_triangles = lineart_mem_acquire(
- &rb->render_data_pool, sizeof(LineartTriangle *) * LRT_TILE_SPLITTING_TRIANGLE_LIMIT);
- ba[i].linked_lines = lineart_mem_acquire(&rb->render_data_pool,
- sizeof(LineartEdge *) * LRT_TILE_EDGE_COUNT_INITIAL);
+ ba[i].linked_triangles = MEM_callocN(sizeof(LineartTriangle *) * ba[i].max_triangle_count,
+ "ba_linked_triangles");
+ ba[i].linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba[i].max_line_count,
+ "ba_linked_lines");
+ BLI_spin_init(&ba[i].lock);
}
for (int i = 0; i < root->triangle_count; i++) {
- tri = root->linked_triangles[i];
- LineartBoundingArea *cba = root->child;
+ LineartTriangle *tri = root->linked_triangles[i];
+
double b[4];
b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
b[2] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
- if (LRT_BOUND_AREA_CROSSES(b, &cba[0].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[0], tri, b, 0, recursive_level + 1, false);
+
+ /* Re-link triangles into child tiles, not doing intersection lines during this because this
+ * batch of triangles are all tested with each other for intersections. */
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[0].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[0], tri, b, 0, recursive_level + 1, false, NULL);
}
- if (LRT_BOUND_AREA_CROSSES(b, &cba[1].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[1], tri, b, 0, recursive_level + 1, false);
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[1].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[1], tri, b, 0, recursive_level + 1, false, NULL);
}
- if (LRT_BOUND_AREA_CROSSES(b, &cba[2].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[2], tri, b, 0, recursive_level + 1, false);
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[2].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[2], tri, b, 0, recursive_level + 1, false, NULL);
}
- if (LRT_BOUND_AREA_CROSSES(b, &cba[3].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[3], tri, b, 0, recursive_level + 1, false);
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[3].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[3], tri, b, 0, recursive_level + 1, false, NULL);
}
}
- rb->bounding_area_count += 3;
+ /* At this point the child tiles are fully initialized and it's safe for new triangles to be
+ * inserted, so assign root->child for #lineart_bounding_area_link_triangle to use. */
+ root->child = ba;
+
+ ld->qtree.tile_count += 3;
}
-static bool lineart_bounding_area_edge_intersect(LineartRenderBuffer *UNUSED(fb),
+static bool lineart_bounding_area_edge_intersect(LineartData *UNUSED(fb),
const double l[2],
const double r[2],
LineartBoundingArea *ba)
{
- double vx, vy;
+ double dx, dy;
double converted[4];
double c1, c;
@@ -3795,25 +3836,25 @@ static bool lineart_bounding_area_edge_intersect(LineartRenderBuffer *UNUSED(fb)
return false;
}
- vx = l[0] - r[0];
- vy = l[1] - r[1];
+ dx = l[0] - r[0];
+ dy = l[1] - r[1];
- c1 = vx * (converted[2] - l[1]) - vy * (converted[0] - l[0]);
+ c1 = dx * (converted[2] - l[1]) - dy * (converted[0] - l[0]);
c = c1;
- c1 = vx * (converted[2] - l[1]) - vy * (converted[1] - l[0]);
+ c1 = dx * (converted[2] - l[1]) - dy * (converted[1] - l[0]);
if (c1 * c <= 0) {
return true;
}
c = c1;
- c1 = vx * (converted[3] - l[1]) - vy * (converted[0] - l[0]);
+ c1 = dx * (converted[3] - l[1]) - dy * (converted[0] - l[0]);
if (c1 * c <= 0) {
return true;
}
c = c1;
- c1 = vx * (converted[3] - l[1]) - vy * (converted[1] - l[0]);
+ c1 = dx * (converted[3] - l[1]) - dy * (converted[1] - l[0]);
if (c1 * c <= 0) {
return true;
}
@@ -3822,7 +3863,7 @@ static bool lineart_bounding_area_edge_intersect(LineartRenderBuffer *UNUSED(fb)
return false;
}
-static bool lineart_bounding_area_triangle_intersect(LineartRenderBuffer *fb,
+static bool lineart_bounding_area_triangle_intersect(LineartData *fb,
LineartTriangle *tri,
LineartBoundingArea *ba)
{
@@ -3857,36 +3898,36 @@ static bool lineart_bounding_area_triangle_intersect(LineartRenderBuffer *fb,
}
/**
- * 1) Link triangles with bounding areas for later occlusion test.
- * 2) Test triangles with existing(added previously) triangles for intersection lines.
+ * This function does two things:
+ *
+ * 1) Builds a quad-tree under ld->InitialBoundingAreas to achieve good geometry separation for
+ * fast overlapping test between triangles and lines. This acceleration structure makes the
+ * occlusion stage much faster.
+ *
+ * 2) Test triangles with other triangles that are previously linked into each tile
+ * (#LineartBoundingArea) for intersection lines. When splitting the tile into 4 children and
+ * re-linking triangles into the child tiles, intersections are inhibited so we don't get
+ * duplicated intersection lines.
+ *
*/
-static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
+static void lineart_bounding_area_link_triangle(LineartData *ld,
LineartBoundingArea *root_ba,
LineartTriangle *tri,
double *LRUB,
int recursive,
int recursive_level,
- bool do_intersection)
+ bool do_intersection,
+ struct LineartIsecThread *th)
{
- if (!lineart_bounding_area_triangle_intersect(rb, tri, root_ba)) {
+ if (!lineart_bounding_area_triangle_intersect(ld, tri, root_ba)) {
return;
}
- if (root_ba->child == NULL) {
- lineart_bounding_area_triangle_add(rb, root_ba, tri);
- /* If splitting doesn't improve triangle separation, then shouldn't allow splitting anymore.
- * Here we use recursive limit. This is especially useful in orthographic render,
- * where a lot of faces could easily line up perfectly in image space,
- * which can not be separated by simply slicing the image tile. */
- if (root_ba->triangle_count >= LRT_TILE_SPLITTING_TRIANGLE_LIMIT && recursive &&
- recursive_level < rb->tile_recursive_level) {
- lineart_bounding_area_split(rb, root_ba, recursive_level);
- }
- if (recursive && do_intersection && rb->use_intersections) {
- lineart_triangle_intersect_in_bounding_area(rb, tri, root_ba);
- }
- }
- else {
- LineartBoundingArea *ba = root_ba->child;
+
+ LineartBoundingArea *old_ba = root_ba;
+
+ if (old_ba->child) {
+ /* If old_ba->child is not NULL, then tile splitting is fully finished, safe to directly insert
+ * into child tiles. */
double *B1 = LRUB;
double b[4];
if (!LRUB) {
@@ -3896,48 +3937,109 @@ static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
B1 = b;
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[0].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[0], tri, B1, recursive, recursive_level + 1, do_intersection);
+ for (int iba = 0; iba < 4; iba++) {
+ if (LRT_BOUND_AREA_CROSSES(B1, &old_ba->child[iba].l)) {
+ lineart_bounding_area_link_triangle(
+ ld, &old_ba->child[iba], tri, B1, recursive, recursive_level + 1, do_intersection, th);
+ }
+ }
+ return;
+ }
+
+ /* When splitting tiles, triangles are relinked into new tiles by a single thread, #th is NULL
+ * in that situation. */
+ if (th) {
+ BLI_spin_lock(&old_ba->lock);
+ }
+
+ /* If there are still space left in this tile for insertion. */
+ if (old_ba->triangle_count < old_ba->max_triangle_count) {
+ const uint32_t old_tri_count = old_ba->triangle_count;
+
+ old_ba->linked_triangles[old_ba->triangle_count++] = tri;
+
+ /* Do intersections in place. */
+ if (do_intersection && ld->conf.use_intersections) {
+ lineart_triangle_intersect_in_bounding_area(tri, old_ba, th, old_tri_count);
+ }
+
+ if (th) {
+ BLI_spin_unlock(&old_ba->lock);
+ }
+ }
+ else { /* We need to wait for either splitting or array extension to be done. */
+
+ if (recursive_level < ld->qtree.recursive_level) {
+ if (!old_ba->child) {
+ /* old_ba->child==NULL, means we are the thread that's doing the splitting. */
+ lineart_bounding_area_split(ld, old_ba, recursive_level);
+ } /* Otherwise other thread has completed the splitting process. */
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[1].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[1], tri, B1, recursive, recursive_level + 1, do_intersection);
+ else {
+ if (old_ba->triangle_count == old_ba->max_triangle_count) {
+ /* Means we are the thread that's doing the extension. */
+ lineart_bounding_area_triangle_reallocate(old_ba);
+ } /* Otherwise other thread has completed the extending the array. */
+ }
+
+ /* Unlock before going into recursive call. */
+ if (th) {
+ BLI_spin_unlock(&old_ba->lock);
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[2].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[2], tri, B1, recursive, recursive_level + 1, do_intersection);
+
+ /* Of course we still have our own triangle needs to be added. */
+ lineart_bounding_area_link_triangle(
+ ld, root_ba, tri, LRUB, recursive, recursive_level, do_intersection, th);
+ }
+}
+
+static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive)
+{
+ BLI_spin_end(&ba->lock);
+ if (ba->linked_lines) {
+ MEM_freeN(ba->linked_lines);
+ }
+ if (ba->linked_triangles) {
+ MEM_freeN(ba->linked_triangles);
+ }
+ if (recursive && ba->child) {
+ for (int i = 0; i < 4; i++) {
+ lineart_free_bounding_area_memory(&ba->child[i], recursive);
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[3].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[3], tri, B1, recursive, recursive_level + 1, do_intersection);
+ }
+}
+static void lineart_free_bounding_area_memories(LineartData *ld)
+{
+ for (int i = 0; i < ld->qtree.count_y; i++) {
+ for (int j = 0; j < ld->qtree.count_x; j++) {
+ lineart_free_bounding_area_memory(&ld->qtree.initials[i * ld->qtree.count_x + j], true);
}
}
}
-static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb,
+static void lineart_bounding_area_link_edge(LineartData *ld,
LineartBoundingArea *root_ba,
LineartEdge *e)
{
if (root_ba->child == NULL) {
- lineart_bounding_area_line_add(rb, root_ba, e);
+ lineart_bounding_area_line_add(root_ba, e);
}
else {
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[0])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[0], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[0])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[0], e);
}
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[1])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[1], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[1])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[1], e);
}
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[2])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[2], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[2])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[2], e);
}
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[3])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[3], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[3])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[3], e);
}
}
}
@@ -3945,16 +4047,16 @@ static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb,
/**
* Link lines to their respective bounding areas.
*/
-static void lineart_main_link_lines(LineartRenderBuffer *rb)
+static void lineart_main_link_lines(LineartData *ld)
{
LRT_ITER_ALL_LINES_BEGIN
{
int r1, r2, c1, c2, row, col;
- if (lineart_get_edge_bounding_areas(rb, e, &r1, &r2, &c1, &c2)) {
+ if (lineart_get_edge_bounding_areas(ld, e, &r1, &r2, &c1, &c2)) {
for (row = r1; row != r2 + 1; row++) {
for (col = c1; col != c2 + 1; col++) {
lineart_bounding_area_link_edge(
- rb, &rb->initial_bounding_areas[row * LRT_BA_ROWS + col], e);
+ ld, &ld->qtree.initials[row * ld->qtree.count_x + col], e);
}
}
}
@@ -3962,14 +4064,10 @@ static void lineart_main_link_lines(LineartRenderBuffer *rb)
LRT_ITER_ALL_LINES_END
}
-static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb,
- LineartTriangle *tri,
- int *rowbegin,
- int *rowend,
- int *colbegin,
- int *colend)
+static bool lineart_get_triangle_bounding_areas(
+ LineartData *ld, LineartTriangle *tri, int *rowbegin, int *rowend, int *colbegin, int *colend)
{
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
double b[4];
if (!tri->v[0] || !tri->v[1] || !tri->v[2]) {
@@ -3987,14 +4085,14 @@ static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb,
(*colbegin) = (int)((b[0] + 1.0) / sp_w);
(*colend) = (int)((b[1] + 1.0) / sp_w);
- (*rowend) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1;
- (*rowbegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1;
+ (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1;
+ (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1;
- if ((*colend) >= rb->tile_count_x) {
- (*colend) = rb->tile_count_x - 1;
+ if ((*colend) >= ld->qtree.count_x) {
+ (*colend) = ld->qtree.count_x - 1;
}
- if ((*rowend) >= rb->tile_count_y) {
- (*rowend) = rb->tile_count_y - 1;
+ if ((*rowend) >= ld->qtree.count_y) {
+ (*rowend) = ld->qtree.count_y - 1;
}
if ((*colbegin) < 0) {
(*colbegin) = 0;
@@ -4006,14 +4104,10 @@ static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb,
return true;
}
-static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
- LineartEdge *e,
- int *rowbegin,
- int *rowend,
- int *colbegin,
- int *colend)
+static bool lineart_get_edge_bounding_areas(
+ LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend)
{
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
double b[4];
if (!e->v1 || !e->v2) {
@@ -4035,31 +4129,29 @@ static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
(*colbegin) = (int)((b[0] + 1.0) / sp_w);
(*colend) = (int)((b[1] + 1.0) / sp_w);
- (*rowend) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1;
- (*rowbegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1;
+ (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1;
+ (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1;
/* It's possible that the line stretches too much out to the side, resulting negative value. */
if ((*rowend) < (*rowbegin)) {
- (*rowend) = rb->tile_count_y - 1;
+ (*rowend) = ld->qtree.count_y - 1;
}
if ((*colend) < (*colbegin)) {
- (*colend) = rb->tile_count_x - 1;
+ (*colend) = ld->qtree.count_x - 1;
}
- CLAMP((*colbegin), 0, rb->tile_count_x - 1);
- CLAMP((*rowbegin), 0, rb->tile_count_y - 1);
- CLAMP((*colend), 0, rb->tile_count_x - 1);
- CLAMP((*rowend), 0, rb->tile_count_y - 1);
+ CLAMP((*colbegin), 0, ld->qtree.count_x - 1);
+ CLAMP((*rowbegin), 0, ld->qtree.count_y - 1);
+ CLAMP((*colend), 0, ld->qtree.count_x - 1);
+ CLAMP((*rowend), 0, ld->qtree.count_y - 1);
return true;
}
-LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
- double x,
- double y)
+LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartData *ld, double x, double y)
{
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
int col, row;
if (x > 1 || x < -1 || y > 1 || y < -1) {
@@ -4067,13 +4159,13 @@ LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *r
}
col = (int)((x + 1.0) / sp_w);
- row = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1;
+ row = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1;
- if (col >= rb->tile_count_x) {
- col = rb->tile_count_x - 1;
+ if (col >= ld->qtree.count_x) {
+ col = ld->qtree.count_x - 1;
}
- if (row >= rb->tile_count_y) {
- row = rb->tile_count_y - 1;
+ if (row >= ld->qtree.count_y) {
+ row = ld->qtree.count_y - 1;
}
if (col < 0) {
col = 0;
@@ -4082,29 +4174,29 @@ LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *r
row = 0;
}
- return &rb->initial_bounding_areas[row * LRT_BA_ROWS + col];
+ return &ld->qtree.initials[row * ld->qtree.count_x + col];
}
-static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
+static LineartBoundingArea *lineart_get_bounding_area(LineartData *ld, double x, double y)
{
LineartBoundingArea *iba;
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
int c = (int)((x + 1.0) / sp_w);
- int r = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1;
+ int r = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1;
if (r < 0) {
r = 0;
}
if (c < 0) {
c = 0;
}
- if (r >= rb->tile_count_y) {
- r = rb->tile_count_y - 1;
+ if (r >= ld->qtree.count_y) {
+ r = ld->qtree.count_y - 1;
}
- if (c >= rb->tile_count_x) {
- c = rb->tile_count_x - 1;
+ if (c >= ld->qtree.count_x) {
+ c = ld->qtree.count_x - 1;
}
- iba = &rb->initial_bounding_areas[r * LRT_BA_ROWS + c];
+ iba = &ld->qtree.initials[r * ld->qtree.count_x + c];
while (iba->child) {
if (x > iba->cx) {
if (y > iba->cy) {
@@ -4126,54 +4218,148 @@ static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, d
return iba;
}
-LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
+LineartBoundingArea *MOD_lineart_get_bounding_area(LineartData *ld, double x, double y)
{
LineartBoundingArea *ba;
- if ((ba = MOD_lineart_get_parent_bounding_area(rb, x, y)) != NULL) {
- return lineart_get_bounding_area(rb, x, y);
+ if ((ba = MOD_lineart_get_parent_bounding_area(ld, x, y)) != NULL) {
+ return lineart_get_bounding_area(ld, x, y);
}
return NULL;
}
+static void lineart_add_triangles_worker(TaskPool *__restrict UNUSED(pool), LineartIsecThread *th)
+{
+ LineartData *ld = th->ld;
+ int _dir_control = 0;
+ while (lineart_schedule_new_triangle_task(th)) {
+ for (LineartElementLinkNode *eln = th->pending_from; eln != th->pending_to->next;
+ eln = eln->next) {
+ int index_start = eln == th->pending_from ? th->index_from : 0;
+ int index_end = eln == th->pending_to ? th->index_to : eln->element_count;
+ LineartTriangle *tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * index_start);
+ for (int ei = index_start; ei < index_end; ei++) {
+ int x1, x2, y1, y2;
+ int r, co;
+ if ((tri->flags & LRT_CULL_USED) || (tri->flags & LRT_CULL_DISCARD)) {
+ tri = (void *)(((uchar *)tri) + ld->sizeof_triangle);
+ continue;
+ }
+ if (lineart_get_triangle_bounding_areas(ld, tri, &y1, &y2, &x1, &x2)) {
+ _dir_control++;
+ for (co = x1; co <= x2; co++) {
+ for (r = y1; r <= y2; r++) {
+ lineart_bounding_area_link_triangle(ld,
+ &ld->qtree.initials[r * ld->qtree.count_x + co],
+ tri,
+ 0,
+ 1,
+ 0,
+ (!(tri->flags & LRT_TRIANGLE_NO_INTERSECTION)),
+ th);
+ }
+ }
+ } /* Else throw away. */
+ tri = (void *)(((uchar *)tri) + ld->sizeof_triangle);
+ }
+ }
+ }
+}
+
+static void lineart_create_edges_from_isec_data(LineartIsecData *d)
+{
+ LineartData *ld = d->ld;
+ double ZMax = ld->conf.far_clip;
+ double ZMin = ld->conf.near_clip;
+
+ for (int i = 0; i < d->thread_count; i++) {
+ LineartIsecThread *th = &d->threads[i];
+ if (G.debug_value == 4000) {
+ printf("Thread %d isec generated %d lines.\n", i, th->current);
+ }
+ if (!th->current) {
+ continue;
+ }
+ /* We don't care about removing duplicated vert in this method, chaining can handle that,
+ * and it saves us from using locks and look up tables. */
+ LineartVertIntersection *v = lineart_mem_acquire(
+ &ld->render_data_pool, sizeof(LineartVertIntersection) * th->current * 2);
+ LineartEdge *e = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdge) * th->current);
+ LineartEdgeSegment *es = lineart_mem_acquire(&ld->render_data_pool,
+ sizeof(LineartEdgeSegment) * th->current);
+ for (int j = 0; j < th->current; j++) {
+ LineartVertIntersection *v1i = v;
+ LineartVertIntersection *v2i = v + 1;
+ LineartIsecSingle *is = &th->array[j];
+ v1i->intersecting_with = is->tri1;
+ v2i->intersecting_with = is->tri2;
+ LineartVert *v1 = (LineartVert *)v1i;
+ LineartVert *v2 = (LineartVert *)v2i;
+ v1->flag |= LRT_VERT_HAS_INTERSECTION_DATA;
+ v2->flag |= LRT_VERT_HAS_INTERSECTION_DATA;
+ copy_v3db_v3fl(v1->gloc, is->v1);
+ copy_v3db_v3fl(v2->gloc, is->v2);
+ /* The intersection line has been generated only in geometry space, so we need to transform
+ * them as well. */
+ mul_v4_m4v3_db(v1->fbcoord, ld->conf.view_projection, v1->gloc);
+ mul_v4_m4v3_db(v2->fbcoord, ld->conf.view_projection, v2->gloc);
+ mul_v3db_db(v1->fbcoord, (1 / v1->fbcoord[3]));
+ mul_v3db_db(v2->fbcoord, (1 / v2->fbcoord[3]));
+
+ v1->fbcoord[0] -= ld->conf.shift_x * 2;
+ v1->fbcoord[1] -= ld->conf.shift_y * 2;
+ v2->fbcoord[0] -= ld->conf.shift_x * 2;
+ v2->fbcoord[1] -= ld->conf.shift_y * 2;
+
+ /* This z transformation is not the same as the rest of the part, because the data don't go
+ * through normal perspective division calls in the pipeline, but this way the 3D result and
+ * occlusion on the generated line is correct, and we don't really use 2D for viewport stroke
+ * generation anyway. */
+ v1->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v1->fbcoord[2]) * (ZMax - ZMin));
+ v2->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v2->fbcoord[2]) * (ZMax - ZMin));
+ e->v1 = v1;
+ e->v2 = v2;
+ e->t1 = is->tri1;
+ e->t2 = is->tri2;
+ e->flags = LRT_EDGE_FLAG_INTERSECTION;
+ e->intersection_mask = (is->tri1->intersection_mask | is->tri2->intersection_mask);
+ BLI_addtail(&e->segments, es);
+
+ lineart_add_edge_to_array(&ld->pending_edges, e);
+
+ v += 2;
+ e++;
+ es++;
+ }
+ }
+}
+
/**
- * Sequentially add triangles into render buffer. This also does intersection along the way.
+ * Sequentially add triangles into render buffer, intersection lines between those triangles will
+ * also be computed at the same time.
*/
-static void lineart_main_add_triangles(LineartRenderBuffer *rb)
+static void lineart_main_add_triangles(LineartData *ld)
{
- LineartTriangle *tri;
- int i, lim;
- int x1, x2, y1, y2;
- int r, co;
-
double t_start;
if (G.debug_value == 4000) {
t_start = PIL_check_seconds_timer();
}
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) {
- tri = eln->pointer;
- lim = eln->element_count;
- for (i = 0; i < lim; i++) {
- if ((tri->flags & LRT_CULL_USED) || (tri->flags & LRT_CULL_DISCARD)) {
- tri = (void *)(((uchar *)tri) + rb->triangle_size);
- continue;
- }
- if (lineart_get_triangle_bounding_areas(rb, tri, &y1, &y2, &x1, &x2)) {
- for (co = x1; co <= x2; co++) {
- for (r = y1; r <= y2; r++) {
- lineart_bounding_area_link_triangle(rb,
- &rb->initial_bounding_areas[r * LRT_BA_ROWS + co],
- tri,
- 0,
- 1,
- 0,
- (!(tri->flags & LRT_TRIANGLE_NO_INTERSECTION)));
- }
- }
- } /* Else throw away. */
- tri = (void *)(((uchar *)tri) + rb->triangle_size);
- }
+ /* Initialize per-thread data for thread task scheduling information and storing intersection
+ * results. */
+ LineartIsecData d = {0};
+ lineart_init_isec_thread(&d, ld, ld->thread_count);
+
+ TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
+ for (int i = 0; i < ld->thread_count; i++) {
+ BLI_task_pool_push(tp, (TaskRunFunction)lineart_add_triangles_worker, &d.threads[i], 0, NULL);
}
+ BLI_task_pool_work_and_wait(tp);
+ BLI_task_pool_free(tp);
+
+ /* Create actual lineart edges from intersection results. */
+ lineart_create_edges_from_isec_data(&d);
+
+ lineart_destroy_isec_thread(&d);
if (G.debug_value == 4000) {
double t_elapsed = PIL_check_seconds_timer() - t_start;
@@ -4185,8 +4371,7 @@ static void lineart_main_add_triangles(LineartRenderBuffer *rb)
* This function gets the tile for the point `e->v1`, and later use #lineart_bounding_area_next()
* to get next along the way.
*/
-static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer *rb,
- LineartEdge *e)
+static LineartBoundingArea *lineart_edge_first_bounding_area(LineartData *ld, LineartEdge *e)
{
double data[2] = {e->v1->fbcoord[0], e->v1->fbcoord[1]};
double LU[2] = {-1, 1}, RU[2] = {1, 1}, LB[2] = {-1, -1}, RB[2] = {1, -1};
@@ -4194,7 +4379,7 @@ static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer
bool p_unused;
if (data[0] > -1 && data[0] < 1 && data[1] > -1 && data[1] < 1) {
- return lineart_get_bounding_area(rb, data[0], data[1]);
+ return lineart_get_bounding_area(ld, data[0], data[1]);
}
if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LU, RU, &sr, &p_unused) &&
@@ -4215,7 +4400,7 @@ static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer
}
interp_v2_v2v2_db(data, e->v1->fbcoord, e->v2->fbcoord, r);
- return lineart_get_bounding_area(rb, data[0], data[1]);
+ return lineart_get_bounding_area(ld, data[0], data[1]);
}
/**
@@ -4446,7 +4631,7 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
LineartCache **cached_result,
bool enable_stroke_depth_offset)
{
- LineartRenderBuffer *rb;
+ LineartData *ld;
Scene *scene = DEG_get_evaluated_scene(depsgraph);
int intersections_only = 0; /* Not used right now, but preserve for future. */
Object *use_camera;
@@ -4457,8 +4642,6 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
t_start = PIL_check_seconds_timer();
}
- BKE_scene_camera_switch_update(scene);
-
if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA) {
if (!lmd->source_camera ||
(use_camera = DEG_get_evaluated_object(depsgraph, lmd->source_camera))->type !=
@@ -4467,6 +4650,9 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
}
}
else {
+
+ BKE_scene_camera_switch_update(scene);
+
if (!scene->camera) {
return false;
}
@@ -4476,54 +4662,53 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
LineartCache *lc = lineart_init_cache();
*cached_result = lc;
- rb = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc);
+ ld = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc);
/* Triangle thread testing data size varies depending on the thread count.
* See definition of LineartTriangleThread for details. */
- rb->triangle_size = lineart_triangle_size_get(scene, rb);
-
- /* FIXME(Yiming): See definition of int #LineartRenderBuffer::_source_type for detailed. */
- rb->_source_type = lmd->source_type;
- rb->_source_collection = lmd->source_collection;
- rb->_source_object = lmd->source_object;
+ ld->sizeof_triangle = lineart_triangle_size_get(ld);
/* Get view vector before loading geometries, because we detect feature lines there. */
- lineart_main_get_view_vector(rb);
+ lineart_main_get_view_vector(ld);
lineart_main_load_geometries(
- depsgraph, scene, use_camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
+ depsgraph, scene, use_camera, ld, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
- if (!rb->vertex_buffer_pointers.first) {
+ if (!ld->geom.vertex_buffer_pointers.first) {
/* No geometry loaded, return early. */
return true;
}
/* Initialize the bounding box acceleration structure, it's a lot like BVH in 3D. */
- lineart_main_bounding_area_make_initial(rb);
+ lineart_main_bounding_area_make_initial(ld);
/* We need to get cut into triangles that are crossing near/far plans, only this way can we get
* correct coordinates of those clipped lines. Done in two steps,
* setting clip_far==false for near plane. */
- lineart_main_cull_triangles(rb, false);
+ lineart_main_cull_triangles(ld, false);
/* `clip_far == true` for far plane. */
- lineart_main_cull_triangles(rb, true);
+ lineart_main_cull_triangles(ld, true);
/* At this point triangle adjacent info pointers is no longer needed, free them. */
- lineart_main_free_adjacent_data(rb);
+ lineart_main_free_adjacent_data(ld);
/* Do the perspective division after clipping is done. */
- lineart_main_perspective_division(rb);
+ lineart_main_perspective_division(ld);
- lineart_main_discard_out_of_frame_edges(rb);
+ lineart_main_discard_out_of_frame_edges(ld);
/* Triangle intersections are done here during sequential adding of them. Only after this,
* triangles and lines are all linked with acceleration structure, and the 2D occlusion stage
* can do its job. */
- lineart_main_add_triangles(rb);
+ lineart_main_add_triangles(ld);
+
+ /* Re-link bounding areas because they have been subdivided by worker threads and we need
+ * adjacent info. */
+ lineart_main_bounding_areas_connect_post(ld);
/* Link lines to acceleration structure, this can only be done after perspective division, if
* we do it after triangles being added, the acceleration structure has already been
* subdivided, this way we do less list manipulations. */
- lineart_main_link_lines(rb);
+ lineart_main_link_lines(ld);
/* "intersection_only" is preserved for being called in a standalone fashion.
* If so the data will already be available at the stage. Otherwise we do the occlusion and
@@ -4532,54 +4717,54 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
if (!intersections_only) {
/* Occlusion is work-and-wait. This call will not return before work is completed. */
- lineart_main_occlusion_begin(rb);
+ lineart_main_occlusion_begin(ld);
/* Chaining is all single threaded. See lineart_chain.c
* In this particular call, only lines that are geometrically connected (share the _exact_
* same end point) will be chained together. */
- MOD_lineart_chain_feature_lines(rb);
+ MOD_lineart_chain_feature_lines(ld);
/* We are unable to take care of occlusion if we only connect end points, so here we do a
* spit, where the splitting point could be any cut in e->segments. */
- MOD_lineart_chain_split_for_fixed_occlusion(rb);
+ MOD_lineart_chain_split_for_fixed_occlusion(ld);
/* Then we connect chains based on the _proximity_ of their end points in image space, here's
* the place threshold value gets involved. */
- MOD_lineart_chain_connect(rb);
+ MOD_lineart_chain_connect(ld);
float *t_image = &lmd->chaining_image_threshold;
/* This configuration ensures there won't be accidental lost of short unchained segments. */
- MOD_lineart_chain_discard_short(rb, MIN2(*t_image, 0.001f) - FLT_EPSILON);
+ MOD_lineart_chain_discard_short(ld, MIN2(*t_image, 0.001f) - FLT_EPSILON);
- if (rb->chain_smooth_tolerance > FLT_EPSILON) {
+ if (ld->conf.chain_smooth_tolerance > FLT_EPSILON) {
/* Keeping UI range of 0-1 for ease of read while scaling down the actual value for best
* effective range in image-space (Coordinate only goes from -1 to 1). This value is
* somewhat arbitrary, but works best for the moment. */
- MOD_lineart_smooth_chains(rb, rb->chain_smooth_tolerance / 50);
+ MOD_lineart_smooth_chains(ld, ld->conf.chain_smooth_tolerance / 50);
}
- if (rb->use_image_boundary_trimming) {
- MOD_lineart_chain_clip_at_border(rb);
+ if (ld->conf.use_image_boundary_trimming) {
+ MOD_lineart_chain_clip_at_border(ld);
}
- if (rb->angle_splitting_threshold > FLT_EPSILON) {
- MOD_lineart_chain_split_angle(rb, rb->angle_splitting_threshold);
+ if (ld->conf.angle_splitting_threshold > FLT_EPSILON) {
+ MOD_lineart_chain_split_angle(ld, ld->conf.angle_splitting_threshold);
}
if (enable_stroke_depth_offset && lmd->stroke_depth_offset > FLT_EPSILON) {
MOD_lineart_chain_offset_towards_camera(
- rb, lmd->stroke_depth_offset, lmd->flags & LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA);
+ ld, lmd->stroke_depth_offset, lmd->flags & LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA);
}
/* Finally transfer the result list into cache. */
- memcpy(&lc->chains, &rb->chains, sizeof(ListBase));
+ memcpy(&lc->chains, &ld->chains, sizeof(ListBase));
/* At last, we need to clear flags so we don't confuse GPencil generation calls. */
MOD_lineart_chain_clear_picked_flag(lc);
}
if (G.debug_value == 4000) {
- lineart_count_and_print_render_buffer_memory(rb);
+ lineart_count_and_print_render_buffer_memory(ld);
double t_elapsed = PIL_check_seconds_timer() - t_start;
printf("Line art total time: %lf\n", t_elapsed);
@@ -4588,15 +4773,15 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
return true;
}
-static int UNUSED_FUNCTION(lineart_rb_edge_types)(LineartRenderBuffer *rb)
+static int UNUSED_FUNCTION(lineart_rb_edge_types)(LineartData *ld)
{
int types = 0;
- types |= rb->use_contour ? LRT_EDGE_FLAG_CONTOUR : 0;
- types |= rb->use_crease ? LRT_EDGE_FLAG_CREASE : 0;
- types |= rb->use_material ? LRT_EDGE_FLAG_MATERIAL : 0;
- types |= rb->use_edge_marks ? LRT_EDGE_FLAG_EDGE_MARK : 0;
- types |= rb->use_intersections ? LRT_EDGE_FLAG_INTERSECTION : 0;
- types |= rb->use_loose ? LRT_EDGE_FLAG_LOOSE : 0;
+ types |= ld->conf.use_contour ? LRT_EDGE_FLAG_CONTOUR : 0;
+ types |= ld->conf.use_crease ? LRT_EDGE_FLAG_CREASE : 0;
+ types |= ld->conf.use_material ? LRT_EDGE_FLAG_MATERIAL : 0;
+ types |= ld->conf.use_edge_marks ? LRT_EDGE_FLAG_EDGE_MARK : 0;
+ types |= ld->conf.use_intersections ? LRT_EDGE_FLAG_INTERSECTION : 0;
+ types |= ld->conf.use_loose ? LRT_EDGE_FLAG_LOOSE : 0;
return types;
}
@@ -4615,7 +4800,7 @@ static void lineart_gpencil_generate(LineartCache *cache,
uchar mask_switches,
uchar material_mask_bits,
uchar intersection_mask,
- short thickness,
+ int16_t thickness,
float opacity,
const char *source_vgname,
const char *vgname,
@@ -4774,16 +4959,16 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
Object *ob,
bGPDlayer *gpl,
bGPDframe *gpf,
- char source_type,
+ int8_t source_type,
void *source_reference,
int level_start,
int level_end,
int mat_nr,
- short edge_types,
+ int16_t edge_types,
uchar mask_switches,
uchar material_mask_bits,
uchar intersection_mask,
- short thickness,
+ int16_t thickness,
float opacity,
const char *source_vgname,
const char *vgname,
@@ -4796,7 +4981,7 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
Object *source_object = NULL;
Collection *source_collection = NULL;
- short use_types = 0;
+ int16_t use_types = 0;
if (source_type == LRT_SOURCE_OBJECT) {
if (!source_reference) {
return;
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
index 1a197c8b4b7..5e24061bd78 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
@@ -18,7 +18,7 @@
#include <string.h>
struct LineartEdge;
-struct LineartRenderBuffer;
+struct LineartData;
struct LineartStaticMemPool;
struct LineartStaticMemPoolNode;
@@ -49,7 +49,6 @@ void *lineart_mem_acquire(struct LineartStaticMemPool *smp, size_t size);
void *lineart_mem_acquire_thread(struct LineartStaticMemPool *smp, size_t size);
void lineart_mem_destroy(struct LineartStaticMemPool *smp);
-void lineart_prepend_edge_direct(void **list_head, void *node);
void lineart_prepend_pool(LinkNode **first, struct LineartStaticMemPool *smp, void *link);
void lineart_matrix_ortho_44d(double (*mProjection)[4],
@@ -62,14 +61,14 @@ void lineart_matrix_ortho_44d(double (*mProjection)[4],
void lineart_matrix_perspective_44d(
double (*mProjection)[4], double fFov_rad, double fAspect, double zMin, double zMax);
-int lineart_count_intersection_segment_count(struct LineartRenderBuffer *rb);
+int lineart_count_intersection_segment_count(struct LineartData *ld);
-void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb);
+void lineart_count_and_print_render_buffer_memory(struct LineartData *ld);
#define LRT_ITER_ALL_LINES_BEGIN \
LineartEdge *e; \
- for (int i = 0; i < rb->pending_edges.next; i++) { \
- e = rb->pending_edges.array[i];
+ for (int i = 0; i < ld->pending_edges.next; i++) { \
+ e = ld->pending_edges.array[i];
#define LRT_ITER_ALL_LINES_NEXT ; /* Doesn't do anything now with new array setup. */
@@ -80,9 +79,9 @@ void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb
#define LRT_BOUND_AREA_CROSSES(b1, b2) \
((b1)[0] < (b2)[1] && (b1)[1] > (b2)[0] && (b1)[3] < (b2)[2] && (b1)[2] > (b2)[3])
-/* Initial bounding area row/column count, setting 4 is the simplest way algorithm could function
- * efficiently. */
-#define LRT_BA_ROWS 4
+/* Initial bounding area row/column count, setting 10 is tested to be relatively optimal for the
+ * performance under current algorithm. */
+#define LRT_BA_ROWS 10
#ifdef __cplusplus
extern "C" {
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
index 2b60fc45800..bbf88985e6a 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
@@ -141,8 +141,8 @@ static bool bake_strokes(Object *ob,
if (!is_first) {
MOD_lineart_clear_cache(&local_lc);
}
- /* Restore the original cache pointer so the modifiers below still have access to the
- * "global" cache. */
+ /* Restore the original cache pointer so the modifiers below still have access to the "global"
+ * cache. */
lmd->cache = gpd->runtime.lineart_cache;
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
index 4ea17b25995..95647f2dd75 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
@@ -144,13 +144,6 @@ void lineart_mem_destroy(LineartStaticMemPool *smp)
}
}
-void lineart_prepend_edge_direct(void **list_head, void *node)
-{
- LineartEdge *e_n = (LineartEdge *)node;
- e_n->next = (*list_head);
- (*list_head) = e_n;
-}
-
void lineart_prepend_pool(LinkNode **first, LineartStaticMemPool *smp, void *link)
{
LinkNode *ln = lineart_mem_acquire_thread(smp, sizeof(LinkNode));
@@ -212,13 +205,13 @@ void lineart_matrix_ortho_44d(double (*mProjection)[4],
mProjection[3][3] = 1.0f;
}
-void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
+void lineart_count_and_print_render_buffer_memory(LineartData *ld)
{
size_t total = 0;
size_t sum_this = 0;
size_t count_this = 0;
- LISTBASE_FOREACH (LineartStaticMemPoolNode *, smpn, &rb->render_data_pool.pools) {
+ LISTBASE_FOREACH (LineartStaticMemPoolNode *, smpn, &ld->render_data_pool.pools) {
count_this++;
sum_this += LRT_MEMORY_POOL_1MB;
}
@@ -227,7 +220,7 @@ void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
sum_this = 0;
count_this = 0;
- LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->line_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &ld->geom.line_buffer_pointers) {
count_this++;
sum_this += reln->element_count * sizeof(LineartEdge);
}
@@ -236,9 +229,9 @@ void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
sum_this = 0;
count_this = 0;
- LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->triangle_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &ld->geom.triangle_buffer_pointers) {
count_this++;
- sum_this += reln->element_count * rb->triangle_size;
+ sum_this += reln->element_count * ld->sizeof_triangle;
}
printf(" allocated %zu triangle blocks, total %zu Bytes.\n", count_this, sum_this);
total += sum_this;
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index e78c86ae196..faf68cf2197 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -447,18 +447,18 @@ set(SRC_SHADER_CREATE_INFOS
../draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
../draw/engines/gpencil/shaders/infos/gpencil_info.hh
../draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh
- ../draw/engines/overlay/shaders/infos/antialiasing_info.hh
- ../draw/engines/overlay/shaders/infos/armature_info.hh
- ../draw/engines/overlay/shaders/infos/background_info.hh
- ../draw/engines/overlay/shaders/infos/edit_mode_info.hh
- ../draw/engines/overlay/shaders/infos/extra_info.hh
- ../draw/engines/overlay/shaders/infos/facing_info.hh
- ../draw/engines/overlay/shaders/infos/grid_info.hh
- ../draw/engines/overlay/shaders/infos/outline_info.hh
- ../draw/engines/overlay/shaders/infos/paint_info.hh
- ../draw/engines/overlay/shaders/infos/sculpt_info.hh
- ../draw/engines/overlay/shaders/infos/volume_info.hh
- ../draw/engines/overlay/shaders/infos/wireframe_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_armature_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_background_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_extra_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_facing_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_grid_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_outline_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_paint_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_volume_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh
../draw/engines/select/shaders/infos/select_id_info.hh
../draw/engines/workbench/shaders/infos/workbench_composite_info.hh
../draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index e4a01670558..1fe3b363687 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -10,6 +10,7 @@
#include <stddef.h>
#include "BKE_attribute.h"
+#include "BKE_pbvh.h"
#ifdef __cplusplus
extern "C" {
@@ -20,6 +21,7 @@ struct CCGElem;
struct CCGKey;
struct DMFlagMat;
struct GSet;
+struct TableGSet;
struct MLoop;
struct MLoopCol;
struct MLoopTri;
@@ -29,6 +31,9 @@ struct MVert;
struct Mesh;
struct PBVH;
struct SubdivCCG;
+struct CustomData;
+
+typedef struct PBVHGPUFormat PBVHGPUFormat;
/**
* Buffers for drawing from PBVH grids.
@@ -78,36 +83,46 @@ enum {
};
/**
+ * Creates a vertex buffer (coordinate, normal, color) and,
+ * if smooth shading, an element index buffer.
* Threaded: do not call any functions that use OpenGL calls!
*/
-void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
const struct MVert *mvert,
- const float (*vert_normals)[3],
+ const CustomData *vdata,
+ const CustomData *ldata,
const float *vmask,
- const void *vcol_data,
- int vcol_type,
- eAttrDomain vcol_domain,
const int *sculpt_face_sets,
- int face_sets_color_seed,
- int face_sets_color_default,
- int update_flags);
+ const int face_sets_color_seed,
+ const int face_sets_color_default,
+ const int update_flags,
+ const float (*vert_normals)[3]);
+
+bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type,
+ PBVHGPUFormat *vbo_id,
+ const struct CustomData *vdata,
+ const struct CustomData *ldata,
+ bool active_attrs_only);
/**
* Creates a vertex buffer (coordinate, normal, color) and,
* if smooth shading, an element index buffer.
* Threaded: do not call any functions that use OpenGL calls!
*/
-void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_bmesh_buffers_update(PBVHGPUFormat *vbo_id,
+ struct GPU_PBVH_Buffers *buffers,
struct BMesh *bm,
struct GSet *bm_faces,
struct GSet *bm_unique_verts,
struct GSet *bm_other_verts,
- int update_flags);
+ const int update_flags);
/**
* Threaded: do not call any functions that use OpenGL calls!
*/
-void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
struct SubdivCCG *subdiv_ccg,
struct CCGElem **grids,
const struct DMFlagMat *grid_flag_mats,
@@ -120,7 +135,8 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
int update_flags);
/**
- * Finish update. Not thread safe, must run in OpenGL main thread.
+ * Finish update. Not thread safe, must run in OpenGL main
+ * thread.
*/
void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers);
@@ -133,9 +149,11 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires);
short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers);
-
bool GPU_pbvh_buffers_has_overlays(GPU_PBVH_Buffers *buffers);
+PBVHGPUFormat *GPU_pbvh_make_format(void);
+void GPU_pbvh_free_format(PBVHGPUFormat *vbo_id);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index b045d908438..5bd20b7be98 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -113,7 +113,7 @@ typedef enum eGPUTextureFormat {
GPU_R16F,
GPU_R16, /* Max texture buffer format. */
- /* Special formats texture & renderbuffer */
+ /* Special formats texture & render-buffer. */
GPU_RGB10_A2,
GPU_R11F_G11F_B10F,
GPU_DEPTH32F_STENCIL8,
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 82a9dea114e..f7be2434fbf 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -9,18 +9,23 @@
#include <limits.h>
#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
+#include "BLI_alloca.h"
+#include "BLI_array.h"
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
#include "BLI_hash.h"
#include "BLI_math.h"
#include "BLI_math_color.h"
#include "BLI_math_color_blend.h"
+#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_userdef_types.h"
@@ -28,6 +33,7 @@
#include "BKE_attribute.h"
#include "BKE_ccg.h"
#include "BKE_customdata.h"
+#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
@@ -36,17 +42,12 @@
#include "GPU_batch.h"
#include "GPU_buffers.h"
+#include "DRW_engine.h"
+
#include "gpu_private.h"
#include "bmesh.h"
-/* XXX: the rest of the code in this file is used for optimized PBVH
- * drawing and doesn't interact at all with the buffer code above */
-
-/* -------------------------------------------------------------------- */
-/** \name Private Types
- * \{ */
-
struct GPU_PBVH_Buffers {
GPUIndexBuf *index_buf, *index_buf_fast;
GPUIndexBuf *index_lines_buf, *index_lines_buf_fast;
@@ -88,10 +89,52 @@ struct GPU_PBVH_Buffers {
bool show_overlay;
};
-static struct {
+typedef struct GPUAttrRef {
+ uchar domain, type;
+ ushort cd_offset;
+ int layer_idx;
+} GPUAttrRef;
+
+#define MAX_GPU_ATTR 256
+
+typedef struct PBVHGPUFormat {
GPUVertFormat format;
- uint pos, nor, msk, col, fset;
-} g_vbo_id = {{0}};
+ uint pos, nor, msk, fset;
+ uint col[MAX_GPU_ATTR];
+ uint uv[MAX_GPU_ATTR];
+ int totcol, totuv;
+
+ /* Upload only the active color and UV attributes,
+ * used for workbench mode. */
+ bool active_attrs_only;
+} PBVHGPUFormat;
+
+PBVHGPUFormat *GPU_pbvh_make_format(void)
+{
+ PBVHGPUFormat *vbo_id = MEM_callocN(sizeof(PBVHGPUFormat), "PBVHGPUFormat");
+
+ GPU_pbvh_attribute_names_update(PBVH_FACES, vbo_id, NULL, NULL, false);
+
+ return vbo_id;
+}
+
+void GPU_pbvh_free_format(PBVHGPUFormat *vbo_id)
+{
+ MEM_SAFE_FREE(vbo_id);
+}
+
+static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask,
+ eCustomDataMask type_mask,
+ const CustomData *vdata,
+ const CustomData *edata,
+ const CustomData *ldata,
+ const CustomData *pdata,
+ GPUAttrRef r_cd_attrs[MAX_GPU_ATTR],
+ bool active_only,
+ int active_type,
+ int active_domain,
+ const CustomDataLayer *active_layer,
+ const CustomDataLayer *render_layer);
/** \} */
@@ -101,20 +144,6 @@ static struct {
void gpu_pbvh_init()
{
- /* Initialize vertex buffer (match 'VertexBufferFormat'). */
- if (g_vbo_id.format.attr_len == 0) {
- g_vbo_id.pos = GPU_vertformat_attr_add(
- &g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- g_vbo_id.nor = GPU_vertformat_attr_add(
- &g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
- g_vbo_id.msk = GPU_vertformat_attr_add(
- &g_vbo_id.format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- g_vbo_id.col = GPU_vertformat_attr_add(
- &g_vbo_id.format, "ac", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- g_vbo_id.fset = GPU_vertformat_attr_add(
- &g_vbo_id.format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
}
void gpu_pbvh_exit()
@@ -122,33 +151,37 @@ void gpu_pbvh_exit()
/* Nothing to do. */
}
+static CustomDataLayer *get_active_layer(const CustomData *cdata, int type)
+{
+ int idx = CustomData_get_active_layer_index(cdata, type);
+ return idx != -1 ? cdata->layers + idx : NULL;
+}
+
+static CustomDataLayer *get_render_layer(const CustomData *cdata, int type)
+{
+ int idx = CustomData_get_render_layer_index(cdata, type);
+ return idx != -1 ? cdata->layers + idx : NULL;
+}
+
/* Allocates a non-initialized buffer to be sent to GPU.
* Return is false it indicates that the memory map failed. */
-static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
+static bool gpu_pbvh_vert_buf_data_set(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
+ uint vert_len)
{
/* Keep so we can test #GPU_USAGE_DYNAMIC buffer use.
* Not that format initialization match in both blocks.
* Do this to keep braces balanced - otherwise indentation breaks. */
-#if 0
- if (buffers->vert_buf == NULL) {
- /* Initialize vertex buffer (match 'VertexBufferFormat'). */
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_DYNAMIC);
- GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
- }
- else if (vert_len != buffers->vert_buf->vertex_len) {
- GPU_vertbuf_data_resize(buffers->vert_buf, vert_len);
- }
-#else
+
if (buffers->vert_buf == NULL) {
/* Initialize vertex buffer (match 'VertexBufferFormat'). */
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC);
+ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&vbo_id->format, GPU_USAGE_STATIC);
}
if (GPU_vertbuf_get_data(buffers->vert_buf) == NULL ||
GPU_vertbuf_get_vertex_len(buffers->vert_buf) != vert_len) {
/* Allocate buffer if not allocated yet or size changed. */
GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
}
-#endif
return GPU_vertbuf_get_data(buffers->vert_buf) != NULL;
}
@@ -194,25 +227,62 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt,
sculpt_face_sets[lt->poly] > SCULPT_FACE_SET_NONE);
}
-void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
const MVert *mvert,
- const float (*vert_normals)[3],
+ const CustomData *vdata,
+ const CustomData *ldata,
const float *vmask,
- const void *vcol_data,
- int vcol_type,
- eAttrDomain vcol_domain,
const int *sculpt_face_sets,
int face_sets_color_seed,
int face_sets_color_default,
- int update_flags)
+ int update_flags,
+ const float (*vert_normals)[3])
{
- const MPropCol *vtcol = vcol_type == CD_PROP_COLOR ? vcol_data : NULL;
- const MLoopCol *vcol = vcol_type == CD_PROP_BYTE_COLOR ? vcol_data : NULL;
- const float(*f3col)[3] = vcol_type == CD_PROP_FLOAT3 ? vcol_data : NULL;
+ GPUAttrRef vcol_refs[MAX_GPU_ATTR];
+ GPUAttrRef cd_uvs[MAX_GPU_ATTR];
+
+ Mesh me_query;
+ BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id);
+
+ CustomDataLayer *actcol = BKE_id_attributes_active_color_get(&me_query.id);
+ eAttrDomain actcol_domain = actcol ? BKE_id_attribute_domain(&me_query.id, actcol) :
+ ATTR_DOMAIN_AUTO;
+
+ CustomDataLayer *rendercol = BKE_id_attributes_render_color_get(&me_query.id);
+
+ int totcol;
+
+ if (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) {
+ totcol = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR,
+ CD_MASK_COLOR_ALL,
+ vdata,
+ NULL,
+ ldata,
+ NULL,
+ vcol_refs,
+ vbo_id->active_attrs_only,
+ actcol ? actcol->type : 0,
+ actcol_domain,
+ actcol,
+ rendercol);
+ }
+ else {
+ totcol = 0;
+ }
- const bool color_loops = vcol_domain == ATTR_DOMAIN_CORNER;
- const bool show_vcol = (vtcol || vcol || f3col) &&
- (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+ int totuv = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_CORNER,
+ CD_MASK_MLOOPUV,
+ NULL,
+ NULL,
+ ldata,
+ NULL,
+ cd_uvs,
+ vbo_id->active_attrs_only,
+ CD_MLOOPUV,
+ ATTR_DOMAIN_CORNER,
+ get_active_layer(ldata, CD_MLOOPUV),
+ get_render_layer(ldata, CD_MLOOPUV));
const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_face_sets = sculpt_face_sets &&
@@ -224,25 +294,106 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int totelem = buffers->tot_tri * 3;
/* Build VBO */
- if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) {
+ if (gpu_pbvh_vert_buf_data_set(vbo_id, buffers, totelem)) {
GPUVertBufRaw pos_step = {0};
GPUVertBufRaw nor_step = {0};
GPUVertBufRaw msk_step = {0};
GPUVertBufRaw fset_step = {0};
GPUVertBufRaw col_step = {0};
+ GPUVertBufRaw uv_step = {0};
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.pos, &pos_step);
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.nor, &nor_step);
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.msk, &msk_step);
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.fset, &fset_step);
- if (show_vcol) {
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col, &col_step);
- }
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->pos, &pos_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->nor, &nor_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->msk, &msk_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->fset, &fset_step);
/* calculate normal for each polygon only once */
uint mpoly_prev = UINT_MAX;
short no[3] = {0, 0, 0};
+ if (totuv > 0) {
+ for (int uv_i = 0; uv_i < totuv; uv_i++) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->uv[uv_i], &uv_step);
+
+ GPUAttrRef *ref = cd_uvs + uv_i;
+ CustomDataLayer *layer = ldata->layers + ref->layer_idx;
+ MLoopUV *muv = layer->data;
+
+ for (uint i = 0; i < buffers->face_indices_len; i++) {
+ const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
+
+ if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
+ continue;
+ }
+
+ for (uint j = 0; j < 3; j++) {
+ MLoopUV *muv2 = muv + lt->tri[j];
+
+ memcpy(GPU_vertbuf_raw_step(&uv_step), muv2->uv, sizeof(muv2->uv));
+ }
+ }
+ }
+ }
+
+ for (int col_i = 0; col_i < totcol; col_i++) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->col[col_i], &col_step);
+
+ MPropCol *pcol = NULL;
+ MLoopCol *mcol = NULL;
+
+ GPUAttrRef *ref = vcol_refs + col_i;
+ const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata;
+ CustomDataLayer *layer = cdata->layers + ref->layer_idx;
+
+ bool color_loops = ref->domain == ATTR_DOMAIN_CORNER;
+
+ if (layer->type == CD_PROP_COLOR) {
+ pcol = (MPropCol *)layer->data;
+ }
+ else {
+ mcol = (MLoopCol *)layer->data;
+ }
+
+ for (uint i = 0; i < buffers->face_indices_len; i++) {
+ const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
+ const uint vtri[3] = {
+ buffers->mloop[lt->tri[0]].v,
+ buffers->mloop[lt->tri[1]].v,
+ buffers->mloop[lt->tri[2]].v,
+ };
+
+ if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
+ continue;
+ }
+
+ for (uint j = 0; j < 3; j++) {
+ /* Vertex Colors. */
+ const uint loop_index = lt->tri[j];
+
+ ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
+
+ if (pcol) {
+ MPropCol *pcol2 = pcol + (color_loops ? loop_index : vtri[j]);
+
+ scol[0] = unit_float_to_ushort_clamp(pcol2->color[0]);
+ scol[1] = unit_float_to_ushort_clamp(pcol2->color[1]);
+ scol[2] = unit_float_to_ushort_clamp(pcol2->color[2]);
+ scol[3] = unit_float_to_ushort_clamp(pcol2->color[3]);
+ }
+ else {
+ const MLoopCol *mcol2 = mcol + (color_loops ? loop_index : vtri[j]);
+
+ scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]);
+ scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]);
+ scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->b]);
+ scol[3] = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f));
+ }
+
+ memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
+ }
+ }
+ }
+
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
const uint vtri[3] = {
@@ -296,50 +447,6 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
*(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask;
empty_mask = empty_mask && (cmask == 0);
- /* Vertex Colors. */
- if (show_vcol) {
- ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- if (vtcol) {
- if (color_loops) {
- scol[0] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[0]);
- scol[1] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[1]);
- scol[2] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[2]);
- scol[3] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[3]);
- }
- else {
- scol[0] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[0]);
- scol[1] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[1]);
- scol[2] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[2]);
- scol[3] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[3]);
- }
- memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
- }
- else if (f3col) {
- if (color_loops) {
- scol[0] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][0]);
- scol[1] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][1]);
- scol[2] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][2]);
- scol[3] = USHRT_MAX;
- }
- else {
- scol[0] = unit_float_to_ushort_clamp(f3col[vtri[j]][0]);
- scol[1] = unit_float_to_ushort_clamp(f3col[vtri[j]][1]);
- scol[2] = unit_float_to_ushort_clamp(f3col[vtri[j]][2]);
- scol[3] = USHRT_MAX;
- }
- memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
- }
- else if (vcol) {
- const uint loop_index = lt->tri[j];
- const MLoopCol *mcol = vcol + (color_loops ? loop_index : vtri[j]);
-
- scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
- scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
- scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
- scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f));
- memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
- }
- }
/* Face Sets. */
memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar[3]));
}
@@ -604,7 +711,8 @@ void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
}
}
-void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
SubdivCCG *subdiv_ccg,
CCGElem **grids,
const struct DMFlagMat *grid_flag_mats,
@@ -628,8 +736,6 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
/* Build VBO */
const int has_mask = key->has_mask;
- buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
-
uint vert_per_grid = (buffers->smooth) ? key->grid_area : (square_i(key->grid_size - 1) * 4);
uint vert_count = totgrid * vert_per_grid;
@@ -653,7 +759,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
uint vbo_index_offset = 0;
/* Build VBO */
- if (gpu_pbvh_vert_buf_data_set(buffers, vert_count)) {
+ if (gpu_pbvh_vert_buf_data_set(vbo_id, buffers, vert_count)) {
GPUIndexBufBuilder elb_lines;
if (buffers->index_lines_buf == NULL) {
@@ -683,25 +789,25 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
for (x = 0; x < key->grid_size; x++) {
CCGElem *elem = CCG_grid_elem(key, grid, x, y);
GPU_vertbuf_attr_set(
- buffers->vert_buf, g_vbo_id.pos, vbo_index, CCG_elem_co(key, elem));
+ buffers->vert_buf, vbo_id->pos, vbo_index, CCG_elem_co(key, elem));
short no_short[3];
normal_float_to_short_v3(no_short, CCG_elem_no(key, elem));
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index, no_short);
if (has_mask && show_mask) {
float fmask = *CCG_elem_mask(key, elem);
uchar cmask = (uchar)(fmask * 255);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index, &cmask);
empty_mask = empty_mask && (cmask == 0);
}
if (show_vcol) {
const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index, &vcol);
}
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index, &face_set_color);
vbo_index += 1;
}
@@ -730,37 +836,37 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
normal_quad_v3(fno, co[3], co[2], co[1], co[0]);
normal_float_to_short_v3(no_short, fno);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 0, co[0]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 0, no_short);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 1, co[1]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 1, no_short);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 2, co[2]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 2, no_short);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 3, co[3]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 3, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 0, co[0]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 0, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 1, co[1]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 1, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 2, co[2]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 2, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 3, co[3]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 3, no_short);
if (has_mask && show_mask) {
float fmask = (*CCG_elem_mask(key, elems[0]) + *CCG_elem_mask(key, elems[1]) +
*CCG_elem_mask(key, elems[2]) + *CCG_elem_mask(key, elems[3])) *
0.25f;
uchar cmask = (uchar)(fmask * 255);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 0, &cmask);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 1, &cmask);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 2, &cmask);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 3, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 0, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 1, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 2, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 3, &cmask);
empty_mask = empty_mask && (cmask == 0);
}
const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 0, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 1, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 2, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 3, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 0, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 1, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 2, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 3, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 0, &face_set_color);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 1, &face_set_color);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 2, &face_set_color);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 3, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 0, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 1, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 2, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 3, &face_set_color);
vbo_index += 4;
}
@@ -805,7 +911,8 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hid
* \{ */
/* Output a BMVert into a VertexBufferFormat array at v_index. */
-static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
+static void gpu_bmesh_vert_to_buffer_copy(PBVHGPUFormat *vbo_id,
+ BMVert *v,
GPUVertBuf *vert_buf,
int v_index,
const float fno[3],
@@ -819,27 +926,27 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
BLI_assert(!BM_elem_flag_test(v, BM_ELEM_HIDDEN));
/* Set coord, normal, and mask */
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, v->co);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->pos, v_index, v->co);
short no_short[3];
normal_float_to_short_v3(no_short, fno ? fno : v->no);
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, v_index, no_short);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->nor, v_index, no_short);
if (show_mask) {
float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
uchar cmask = (uchar)(effective_mask * 255);
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, v_index, &cmask);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->msk, v_index, &cmask);
*empty_mask = *empty_mask && (cmask == 0);
}
if (show_vcol) {
const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->col[0], v_index, &vcol);
}
/* Add default face sets color to avoid artifacts. */
const uchar face_set[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.fset, v_index, &face_set);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->fset, v_index, &face_set);
}
/* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */
@@ -896,7 +1003,8 @@ void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
}
}
-void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_bmesh_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
BMesh *bm,
GSet *bm_faces,
GSet *bm_unique_verts,
@@ -935,7 +1043,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
/* Fill vertex buffer */
- if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
+ if (!gpu_pbvh_vert_buf_data_set(vbo_id, buffers, totvert)) {
/* Memory map failed */
return;
}
@@ -965,7 +1073,8 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Add vertex to the vertex buffer each time a new one is encountered */
*idx_p = POINTER_FROM_UINT(v_index);
- gpu_bmesh_vert_to_buffer_copy(v[i],
+ gpu_bmesh_vert_to_buffer_copy(vbo_id,
+ v[i],
buffers->vert_buf,
v_index,
NULL,
@@ -1032,7 +1141,8 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
for (i = 0; i < 3; i++) {
- gpu_bmesh_vert_to_buffer_copy(v[i],
+ gpu_bmesh_vert_to_buffer_copy(vbo_id,
+ v[i],
buffers->vert_buf,
v_index++,
f->no,
@@ -1075,6 +1185,250 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
return buffers;
}
+/**
+ * Builds a list of attributes from a set of domains and a set of
+ * customdata types.
+ *
+ * \param active_only Returns only one item, a GPUAttrRef to active_layer
+ * \param active_layer CustomDataLayer to use for the active layer
+ * \param active_layer CustomDataLayer to use for the render layer
+ */
+static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask,
+ eCustomDataMask type_mask,
+ const CustomData *vdata,
+ const CustomData *edata,
+ const CustomData *ldata,
+ const CustomData *pdata,
+ GPUAttrRef r_cd_attrs[MAX_GPU_ATTR],
+ bool active_only,
+ int active_type,
+ int active_domain,
+ const CustomDataLayer *active_layer,
+ const CustomDataLayer *render_layer)
+{
+ const CustomData *cdata_active = active_domain == ATTR_DOMAIN_POINT ? vdata : ldata;
+
+ if (!cdata_active) {
+ return 0;
+ }
+
+ if (active_only) {
+ int idx = active_layer ? active_layer - cdata_active->layers : -1;
+
+ if (idx >= 0 && idx < cdata_active->totlayer) {
+ r_cd_attrs[0].cd_offset = cdata_active->layers[idx].offset;
+ r_cd_attrs[0].domain = active_domain;
+ r_cd_attrs[0].type = active_type;
+ r_cd_attrs[0].layer_idx = idx;
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ const CustomData *datas[4] = {vdata, edata, pdata, ldata};
+
+ int count = 0;
+ for (eAttrDomain domain = 0; domain < 4; domain++) {
+ const CustomData *cdata = datas[domain];
+
+ if (!cdata || !((1 << domain) & domain_mask)) {
+ continue;
+ }
+
+ CustomDataLayer *cl = cdata->layers;
+
+ for (int i = 0; count < MAX_GPU_ATTR && i < cdata->totlayer; i++, cl++) {
+ if ((CD_TYPE_AS_MASK(cl->type) & type_mask) && !(cl->flag & CD_FLAG_TEMPORARY)) {
+ GPUAttrRef *ref = r_cd_attrs + count;
+
+ ref->cd_offset = cl->offset;
+ ref->type = cl->type;
+ ref->layer_idx = i;
+ ref->domain = domain;
+
+ count++;
+ }
+ }
+ }
+
+ /* ensure render layer is last
+ draw cache code seems to need this
+ */
+
+ for (int i = 0; i < count; i++) {
+ GPUAttrRef *ref = r_cd_attrs + i;
+ const CustomData *cdata = datas[ref->domain];
+
+ if (cdata->layers + ref->layer_idx == render_layer) {
+ SWAP(GPUAttrRef, r_cd_attrs[i], r_cd_attrs[count - 1]);
+ break;
+ }
+ }
+
+ return count;
+}
+
+static bool gpu_pbvh_format_equals(PBVHGPUFormat *a, PBVHGPUFormat *b)
+{
+ bool bad = false;
+
+ bad |= a->active_attrs_only != b->active_attrs_only;
+
+ bad |= a->pos != b->pos;
+ bad |= a->fset != b->fset;
+ bad |= a->msk != b->msk;
+ bad |= a->nor != b->nor;
+
+ for (int i = 0; i < MIN2(a->totuv, b->totuv); i++) {
+ bad |= a->uv[i] != b->uv[i];
+ }
+
+ for (int i = 0; i < MIN2(a->totcol, b->totcol); i++) {
+ bad |= a->col[i] != b->col[i];
+ }
+
+ bad |= a->totuv != b->totuv;
+ bad |= a->totcol != b->totcol;
+
+ return !bad;
+}
+
+bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type,
+ PBVHGPUFormat *vbo_id,
+ const CustomData *vdata,
+ const CustomData *ldata,
+ bool active_attrs_only)
+{
+ const bool active_only = active_attrs_only;
+ PBVHGPUFormat old_format = *vbo_id;
+
+ GPU_vertformat_clear(&vbo_id->format);
+
+ vbo_id->active_attrs_only = active_attrs_only;
+
+ if (vbo_id->format.attr_len == 0) {
+ vbo_id->pos = GPU_vertformat_attr_add(
+ &vbo_id->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ vbo_id->nor = GPU_vertformat_attr_add(
+ &vbo_id->format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
+ vbo_id->msk = GPU_vertformat_attr_add(
+ &vbo_id->format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ vbo_id->totcol = 0;
+ if (pbvh_type == PBVH_FACES) {
+ int ci = 0;
+
+ Mesh me_query;
+
+ BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id);
+
+ CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me_query.id);
+ CustomDataLayer *render_color_layer = BKE_id_attributes_render_color_get(&me_query.id);
+ eAttrDomain active_color_domain = active_color_layer ?
+ BKE_id_attribute_domain(&me_query.id,
+ active_color_layer) :
+ ATTR_DOMAIN_NUM;
+
+ GPUAttrRef vcol_layers[MAX_GPU_ATTR];
+ int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR,
+ CD_MASK_COLOR_ALL,
+ vdata,
+ NULL,
+ ldata,
+ NULL,
+ vcol_layers,
+ active_only,
+ active_color_layer ? active_color_layer->type : -1,
+ active_color_domain,
+ active_color_layer,
+ render_color_layer);
+
+ for (int i = 0; i < totlayer; i++) {
+ GPUAttrRef *ref = vcol_layers + i;
+ const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata;
+
+ const CustomDataLayer *layer = cdata->layers + ref->layer_idx;
+
+ if (vbo_id->totcol < MAX_GPU_ATTR) {
+ vbo_id->col[ci++] = GPU_vertformat_attr_add(
+ &vbo_id->format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ vbo_id->totcol++;
+
+ bool is_render = render_color_layer == layer;
+ bool is_active = active_color_layer == layer;
+
+ DRW_cdlayer_attr_aliases_add(&vbo_id->format, "c", cdata, layer, is_render, is_active);
+ }
+ }
+ }
+
+ /* ensure at least one vertex color layer */
+ if (vbo_id->totcol == 0) {
+ vbo_id->col[0] = GPU_vertformat_attr_add(
+ &vbo_id->format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ vbo_id->totcol = 1;
+
+ GPU_vertformat_alias_add(&vbo_id->format, "ac");
+ }
+
+ vbo_id->fset = GPU_vertformat_attr_add(
+ &vbo_id->format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ vbo_id->totuv = 0;
+ if (pbvh_type == PBVH_FACES && ldata && CustomData_has_layer(ldata, CD_MLOOPUV)) {
+ GPUAttrRef uv_layers[MAX_GPU_ATTR];
+ CustomDataLayer *active = NULL, *render = NULL;
+
+ active = get_active_layer(ldata, CD_MLOOPUV);
+ render = get_render_layer(ldata, CD_MLOOPUV);
+
+ int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_CORNER,
+ CD_MASK_MLOOPUV,
+ NULL,
+ NULL,
+ ldata,
+ NULL,
+ uv_layers,
+ active_only,
+ CD_MLOOPUV,
+ ATTR_DOMAIN_CORNER,
+ active,
+ render);
+
+ vbo_id->totuv = totlayer;
+
+ for (int i = 0; i < totlayer; i++) {
+ GPUAttrRef *ref = uv_layers + i;
+
+ vbo_id->uv[i] = GPU_vertformat_attr_add(
+ &vbo_id->format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ CustomDataLayer *cl = ldata->layers + ref->layer_idx;
+ bool is_active = ref->layer_idx == CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+
+ DRW_cdlayer_attr_aliases_add(&vbo_id->format, "u", ldata, cl, cl == render, is_active);
+
+ /* Apparently the render attribute is 'a' while active is 'au',
+ * at least going by the draw cache extractor code.
+ */
+ if (cl == render) {
+ GPU_vertformat_alias_add(&vbo_id->format, "a");
+ }
+ }
+ }
+ }
+
+ if (!gpu_pbvh_format_equals(&old_format, vbo_id)) {
+ return true;
+ }
+
+ return false;
+}
+
GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires)
{
if (wires) {
diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc
index f1b46f8bf86..a5ba0949a83 100644
--- a/source/blender/gpu/intern/gpu_codegen.cc
+++ b/source/blender/gpu/intern/gpu_codegen.cc
@@ -40,8 +40,8 @@
#include "gpu_shader_create_info.hh"
#include "gpu_shader_dependency_private.h"
-#include <stdarg.h>
-#include <string.h>
+#include <cstdarg>
+#include <cstring>
#include <sstream>
#include <string>
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index 67035853594..daefd57a5b3 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -337,13 +337,27 @@ static void imm_draw_circle_3D(
/* Note(Metal/AMD): For small primitives, line list more efficient than line strip. */
immBegin(GPU_PRIM_LINES, nsegments * 2);
- immVertex3f(pos, x + radius * cosf(0.0f), y + radius * sinf(0.0f), 0.0f);
- for (int i = 1; i < nsegments; i++) {
- float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
- immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f);
- immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f);
+ const float angle = (float)(2 * M_PI) / (float)nsegments;
+ float xprev = cosf(-angle) * radius;
+ float yprev = sinf(-angle) * radius;
+ const float alpha = 2.0f * cosf(angle);
+
+ float xr = radius;
+ float yr = 0;
+
+ for (int i = 0; i < nsegments; i++) {
+ immVertex3f(pos, x + xr, y + yr, 0.0f);
+ if (i) {
+ immVertex3f(pos, x + xr, y + yr, 0.0f);
+ }
+ const float xnext = alpha * xr - xprev;
+ const float ynext = alpha * yr - yprev;
+ xprev = xr;
+ yprev = yr;
+ xr = xnext;
+ yr = ynext;
}
- immVertex3f(pos, x + radius * cosf(0.0f), y + radius * sinf(0.0f), 0.0f);
+ immVertex3f(pos, x + radius, y, 0.0f);
immEnd();
}
else {
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 23028f58059..5d6651c3e3a 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -669,7 +669,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries");
mat->refcount = 1;
#ifndef NDEBUG
- BLI_snprintf(mat->name, sizeof(mat->name), "%s", name);
+ STRNCPY(mat->name, name);
#else
UNUSED_VARS(name);
#endif
@@ -750,6 +750,9 @@ void GPU_material_compile(GPUMaterial *mat)
mat->status = GPU_MAT_SUCCESS;
gpu_node_graph_free_nodes(&mat->graph);
}
+ else {
+ mat->status = GPU_MAT_FAILED;
+ }
}
else {
mat->status = GPU_MAT_FAILED;
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index cac6f7cb38b..3c6a03c56d3 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -347,7 +347,7 @@ static char attr_prefix_get(eCustomDataType type)
static void attr_input_name(GPUMaterialAttribute *attr)
{
- /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
+ /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.cc */
if (attr->type == CD_ORCO) {
/* OPTI: orco is computed from local positions, but only if no modifier is present. */
STRNCPY(attr->input_name, "orco");
diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc
index ea138973c74..6f43b379d31 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.cc
+++ b/source/blender/gpu/intern/gpu_shader_interface.cc
@@ -38,7 +38,7 @@ static void sort_input_list(MutableSpan<ShaderInput> dst)
/* Simple sorting by going through the array and selecting the biggest element each time. */
for (uint i = 0; i < dst.size(); i++) {
- ShaderInput *input_src = &src[0];
+ ShaderInput *input_src = src.data();
for (uint j = 1; j < src.size(); j++) {
if (src[j].name_hash > input_src->name_hash) {
input_src = &src[j];
diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm
index 8bdec962af0..1064091a036 100644
--- a/source/blender/gpu/metal/mtl_backend.mm
+++ b/source/blender/gpu/metal/mtl_backend.mm
@@ -256,7 +256,7 @@ bool MTLBackend::metal_is_supported()
NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
- /* Metal Viewport requires macOS Version 10.15 onwards. */
+ /* Metal Viewport requires macOS Version 10.15 onward. */
bool supported_os_version = version.majorVersion >= 11 ||
(version.majorVersion == 10 ? version.minorVersion >= 15 : false);
if (!supported_os_version) {
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 0c796ddc765..98998e2e902 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -408,7 +408,7 @@ static void detect_workarounds()
/* Certain Intel/AMD based platforms don't clear the viewport textures. Always clearing leads to
* noticeable performance regressions on other platforms as well. */
if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY) ||
- GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
+ GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
GCaps.clear_viewport_workaround = true;
}
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 5a28b8b7318..83b00da0446 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -613,7 +613,7 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
if (info.early_fragment_test_) {
ss << "layout(early_fragment_tests) in;\n";
}
- if (GLEW_VERSION_4_2 || GLEW_ARB_conservative_depth) {
+ if (GLEW_ARB_conservative_depth) {
ss << "layout(" << to_string(info.depth_write_) << ") out float gl_FragDepth;\n";
}
ss << "\n/* Outputs. */\n";
@@ -836,7 +836,7 @@ static char *glsl_patch_default_get()
STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n");
STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n");
}
- if (!GLEW_VERSION_4_2 && GLEW_ARB_conservative_depth) {
+ if (GLEW_ARB_conservative_depth) {
STR_CONCAT(patch, slen, "#extension GL_ARB_conservative_depth : enable\n");
}
if (GPU_shader_image_load_store_support()) {
diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl
index 4962fb01c88..b0da035ef09 100644
--- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl
@@ -5,7 +5,7 @@ void main()
float dist_squared = dot(centered, centered);
const float rad_squared = 0.25;
- // round point with jaggy edges
+ /* Round point with jaggy edges. */
if (dist_squared > rad_squared) {
discard;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
index ff84a0a334c..b1a29833d77 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
@@ -1,6 +1,8 @@
void camera(out vec3 outview, out float outdepth, out float outdist)
{
- outdepth = abs(transform_point(ViewMatrix, g_data.P).z);
- outdist = distance(g_data.P, cameraPos);
- outview = normalize(g_data.P - cameraPos);
+ vec3 vP = transform_point(ViewMatrix, g_data.P);
+ vP.z = -vP.z;
+ outdepth = abs(vP.z);
+ outdist = length(vP);
+ outview = normalize(vP);
}
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 75159e186e9..2f0d2f9b449 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -181,7 +181,6 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
int width,
int height,
const struct ImBuf *ibuf,
- bool compress_as_srgb,
bool store_premultiplied);
void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
int offset_x,
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 16cf0e2125e..1b32bef0a98 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -41,8 +41,7 @@ typedef struct DDSData {
/**
* \ingroup imbuf
- * This is the abstraction of an image. ImBuf is the basic type used for all
- * imbuf operations.
+ * This is the abstraction of an image. ImBuf is the basic type used for all imbuf operations.
*
* Also; add new variables to the end to save pain!
*/
@@ -176,7 +175,7 @@ typedef struct ImBuf {
* avoid problems and use int. - campbell */
int x, y;
- /** Active amount of bits/bitplanes */
+ /** Active amount of bits/bit-planes. */
unsigned char planes;
/** Number of channels in `rect_float` (0 = 4 channel default) */
int channels;
@@ -276,7 +275,7 @@ typedef struct ImBuf {
} ImBuf;
/**
- * \brief userflags: Flags used internally by blender for imagebuffers
+ * \brief userflags: Flags used internally by blender for image-buffers.
*/
enum {
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 6e505746643..9a0a6998fab 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -240,11 +240,10 @@ void imb_loadtiletiff(
/**
* Saves a TIFF file.
*
- * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
- * respectively) are accepted, and interpreted correctly. Note that the TIFF
- * convention is to use pre-multiplied alpha, which can be achieved within
- * Blender by setting "Premul" alpha handling. Other alpha conventions are
- * not strictly correct, but are permitted anyhow.
+ * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA respectively)
+ * are accepted, and interpreted correctly. Note that the TIFF convention is to use
+ * pre-multiplied alpha, which can be achieved within Blender by setting `premul` alpha handling.
+ * Other alpha conventions are not strictly correct, but are permitted anyhow.
*
* \param ibuf: Image buffer.
* \param filepath: Name of the TIFF file to create.
diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c
index 6448d6cd76a..1a99d2a34d9 100644
--- a/source/blender/imbuf/intern/cineon/cineon_dpx.c
+++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c
@@ -121,8 +121,8 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filepath, int use_cineon
}
if (ibuf->rect_float != NULL && bitspersample != 8) {
- /* don't use the float buffer to save 8 bpp picture to prevent color banding
- * (there's no dithering algorithm behind the logImageSetDataRGBA function) */
+ /* Don't use the float buffer to save 8 BPP picture to prevent color banding
+ * (there's no dithering algorithm behind the #logImageSetDataRGBA function). */
fbuf = (float *)MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y,
"fbuf in imb_save_dpx_cineon");
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index d4c9e78a299..33873b5daa7 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -597,7 +597,7 @@ static void colormanage_free_config(void)
while (colorspace) {
ColorSpace *colorspace_next = colorspace->next;
- /* free precomputer processors */
+ /* Free precomputed processors. */
if (colorspace->to_scene_linear) {
OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)colorspace->to_scene_linear);
}
@@ -673,7 +673,7 @@ void colormanagement_init(void)
#ifdef WIN32
{
- /* quite a hack to support loading configuration from path with non-acii symbols */
+ /* Quite a hack to support loading configuration from path with non-ACII symbols. */
char short_name[256];
BLI_get_short_name(short_name, configfile);
@@ -2211,21 +2211,14 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
const int width,
const int height,
const struct ImBuf *ibuf,
- const bool compress_as_srgb,
const bool store_premultiplied)
{
- /* Convert byte buffer for texture storage on the GPU. These have builtin
- * support for converting sRGB to linear, which allows us to store textures
- * without precision or performance loss at minimal memory usage. */
+ /* Byte buffer storage, only for sRGB and data texture since other
+ * color space conversions can't be done on the GPU. */
BLI_assert(ibuf->rect && ibuf->rect_float == NULL);
+ BLI_assert(IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_data(ibuf->rect_colorspace));
- OCIO_ConstCPUProcessorRcPtr *processor = NULL;
- if (compress_as_srgb && ibuf->rect_colorspace &&
- !IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
- processor = colorspace_to_scene_linear_cpu_processor(ibuf->rect_colorspace);
- }
-
- /* TODO(brecht): make this multi-threaded, or at least process in batches. */
const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
@@ -2235,20 +2228,7 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
const unsigned char *in = in_buffer + in_offset * 4;
unsigned char *out = out_buffer + out_offset * 4;
- if (processor != NULL) {
- /* Convert to scene linear, to sRGB and premultiply. */
- for (int x = 0; x < width; x++, in += 4, out += 4) {
- float pixel[4];
- rgba_uchar_to_float(pixel, in);
- OCIO_cpuProcessorApplyRGB(processor, pixel);
- linearrgb_to_srgb_v3_v3(pixel, pixel);
- if (use_premultiply) {
- mul_v3_fl(pixel, pixel[3]);
- }
- rgba_float_to_uchar(out, pixel);
- }
- }
- else if (use_premultiply) {
+ if (use_premultiply) {
/* Premultiply only. */
for (int x = 0; x < width; x++, in += 4, out += 4) {
out[0] = (in[0] * in[3]) >> 8;
@@ -2279,43 +2259,80 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
{
/* Float texture are stored in scene linear color space, with premultiplied
* alpha depending on the image alpha mode. */
- const float *in_buffer = ibuf->rect_float;
- const int in_channels = ibuf->channels;
- const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied;
-
- for (int y = 0; y < height; y++) {
- const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
- const size_t out_offset = y * width;
- const float *in = in_buffer + in_offset * in_channels;
- float *out = out_buffer + out_offset * 4;
-
- if (in_channels == 1) {
- /* Copy single channel. */
- for (int x = 0; x < width; x++, in += 1, out += 4) {
- out[0] = in[0];
- out[1] = in[0];
- out[2] = in[0];
- out[3] = in[0];
+ if (ibuf->rect_float) {
+ /* Float source buffer. */
+ const float *in_buffer = ibuf->rect_float;
+ const int in_channels = ibuf->channels;
+ const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied;
+
+ for (int y = 0; y < height; y++) {
+ const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
+ const size_t out_offset = y * width;
+ const float *in = in_buffer + in_offset * in_channels;
+ float *out = out_buffer + out_offset * 4;
+
+ if (in_channels == 1) {
+ /* Copy single channel. */
+ for (int x = 0; x < width; x++, in += 1, out += 4) {
+ out[0] = in[0];
+ out[1] = in[0];
+ out[2] = in[0];
+ out[3] = in[0];
+ }
}
- }
- else if (in_channels == 3) {
- /* Copy RGB. */
- for (int x = 0; x < width; x++, in += 3, out += 4) {
- out[0] = in[0];
- out[1] = in[1];
- out[2] = in[2];
- out[3] = 1.0f;
+ else if (in_channels == 3) {
+ /* Copy RGB. */
+ for (int x = 0; x < width; x++, in += 3, out += 4) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = 1.0f;
+ }
}
- }
- else if (in_channels == 4) {
- /* Copy or convert RGBA. */
- if (use_unpremultiply) {
- for (int x = 0; x < width; x++, in += 4, out += 4) {
- premul_to_straight_v4_v4(out, in);
+ else if (in_channels == 4) {
+ /* Copy or convert RGBA. */
+ if (use_unpremultiply) {
+ for (int x = 0; x < width; x++, in += 4, out += 4) {
+ premul_to_straight_v4_v4(out, in);
+ }
+ }
+ else {
+ memcpy(out, in, sizeof(float[4]) * width);
}
}
- else {
- memcpy(out, in, sizeof(float[4]) * width);
+ }
+ }
+ else {
+ /* Byte source buffer. */
+ const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
+ const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
+
+ /* TODO(brecht): make this multi-threaded, or at least process in batches. */
+ OCIO_ConstCPUProcessorRcPtr *processor = (ibuf->rect_colorspace) ?
+ colorspace_to_scene_linear_cpu_processor(
+ ibuf->rect_colorspace) :
+ NULL;
+
+ for (int y = 0; y < height; y++) {
+ const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
+ const size_t out_offset = y * width;
+ const unsigned char *in = in_buffer + in_offset * 4;
+ float *out = out_buffer + out_offset * 4;
+
+ /* Convert to scene linear, to sRGB and premultiply. */
+ for (int x = 0; x < width; x++, in += 4, out += 4) {
+ float pixel[4];
+ rgba_uchar_to_float(pixel, in);
+ if (processor) {
+ OCIO_cpuProcessorApplyRGB(processor, pixel);
+ }
+ else {
+ srgb_to_linearrgb_v3_v3(pixel, pixel);
+ }
+ if (use_premultiply) {
+ mul_v3_fl(pixel, pixel[3]);
+ }
+ copy_v4_v4(out, pixel);
}
}
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 54ef5438c23..0414fa1268d 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -174,14 +174,14 @@ class IMMapStream : public Imf::IStream {
imb_mmap_lock();
_mmap_file = BLI_mmap_open(file);
imb_mmap_unlock();
- if (_mmap_file == NULL) {
+ if (_mmap_file == nullptr) {
throw IEX_NAMESPACE::InputExc("BLI_mmap_open failed");
}
close(file);
_exrbuf = (unsigned char *)BLI_mmap_get_pointer(_mmap_file);
}
- ~IMMapStream()
+ ~IMMapStream() override
{
imb_mmap_lock();
BLI_mmap_free(_mmap_file);
@@ -512,7 +512,7 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
/* we store first everything in half array */
std::vector<RGBAZ> pixels(height * width);
- RGBAZ *to = &pixels[0];
+ RGBAZ *to = pixels.data();
int xstride = sizeof(RGBAZ);
int ystride = xstride * width;
@@ -1010,7 +1010,7 @@ void IMB_exrtile_begin_write(
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
try {
data->ofile_stream = new OFileStream(filepath);
- data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
+ data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), headers.data(), headers.size());
}
catch (const std::exception &) {
delete data->mpofile;
@@ -2209,7 +2209,7 @@ struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
if (file->header().hasPreviewImage()) {
const Imf::PreviewImage &preview = file->header().previewImage();
ImBuf *ibuf = IMB_allocFromBuffer(
- (unsigned int *)preview.pixels(), NULL, preview.width(), preview.height(), 4);
+ (unsigned int *)preview.pixels(), nullptr, preview.width(), preview.height(), 4);
delete file;
delete stream;
IMB_flipy(ibuf);
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index 52756891f21..2a0baaf6172 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -702,21 +702,21 @@ int *IMB_stereo3d_from_rect(const ImageFormatData *im_format,
int *rect_left,
int *rect_right)
{
- int *r_rect;
+ int *rect_result;
Stereo3DData s3d_data = {{NULL}};
size_t width, height;
const bool is_float = im_format->depth > 8;
IMB_stereo3d_write_dimensions(
im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
- r_rect = MEM_mallocN(channels * sizeof(int) * width * height, __func__);
+ rect_result = MEM_mallocN(channels * sizeof(int) * width * height, __func__);
imb_stereo3d_data_init(
- &s3d_data, is_float, x, y, channels, rect_left, rect_right, r_rect, NULL, NULL, NULL);
+ &s3d_data, is_float, x, y, channels, rect_left, rect_right, rect_result, NULL, NULL, NULL);
imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
- imb_stereo3d_squeeze_rect(r_rect, &im_format->stereo3d_format, x, y, channels);
+ imb_stereo3d_squeeze_rect(rect_result, &im_format->stereo3d_format, x, y, channels);
- return r_rect;
+ return rect_result;
}
float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format,
@@ -726,21 +726,30 @@ float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format,
float *rectf_left,
float *rectf_right)
{
- float *r_rectf;
+ float *rectf_result;
Stereo3DData s3d_data = {{NULL}};
size_t width, height;
const bool is_float = im_format->depth > 8;
IMB_stereo3d_write_dimensions(
im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
- r_rectf = MEM_mallocN(channels * sizeof(float) * width * height, __func__);
+ rectf_result = MEM_mallocN(channels * sizeof(float) * width * height, __func__);
- imb_stereo3d_data_init(
- &s3d_data, is_float, x, y, channels, NULL, NULL, NULL, rectf_left, rectf_right, r_rectf);
+ imb_stereo3d_data_init(&s3d_data,
+ is_float,
+ x,
+ y,
+ channels,
+ NULL,
+ NULL,
+ NULL,
+ rectf_left,
+ rectf_right,
+ rectf_result);
imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
- imb_stereo3d_squeeze_rectf(r_rectf, &im_format->stereo3d_format, x, y, channels);
+ imb_stereo3d_squeeze_rectf(rectf_result, &im_format->stereo3d_format, x, y, channels);
- return r_rectf;
+ return rectf_result;
}
ImBuf *IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index f2c9c82fa66..6f39009d38d 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -30,7 +30,6 @@
#include "IMB_thumbs.h"
#include <ctype.h>
-#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -514,7 +513,7 @@ void IMB_thumb_delete(const char *filepath, ThumbSize size)
}
}
-ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source)
+ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source)
{
char thumb_path[FILE_MAX];
char thumb_name[40];
@@ -526,7 +525,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source
ImBuf *img = NULL;
char *blen_group = NULL, *blen_id = NULL;
- path = file_path = org_path;
+ path = file_path = filepath;
if (source == THB_SOURCE_BLEND) {
if (BLO_library_path_explode(path, path_buff, &blen_group, &blen_id)) {
if (blen_group) {
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 1372aa31713..2f13ef409e3 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -8,15 +8,15 @@
* Provides TIFF file loading and saving for Blender, via libtiff.
*
* The task of loading is complicated somewhat by the fact that Blender has
- * already loaded the file into a memory buffer. libtiff is not well
+ * already loaded the file into a memory buffer. libtiff is not well
* configured to handle files in memory, so a client wrapper is written to
- * surround the memory and turn it into a virtual file. Currently, reading
- * of TIFF files is done using libtiff's RGBAImage support. This is a
+ * surround the memory and turn it into a virtual file. Currently, reading
+ * of TIFF files is done using libtiff's RGBAImage support. This is a
* high-level routine that loads all images as 32-bit RGBA, handling all the
* required conversions between many different TIFF types internally.
*
* Saving supports RGB, RGBA and BW (gray-scale) images correctly, with
- * 8 bits per channel in all cases. The "deflate" compression algorithm is
+ * 8 bits per channel in all cases. The "deflate" compression algorithm is
* used to compress images.
*/
@@ -151,8 +151,8 @@ static tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n)
/**
* Writes data to an in-memory TIFF file.
*
- * NOTE: The current Blender implementation should not need this function. It
- * is simply a stub.
+ * NOTE: The current Blender implementation should not need this function.
+ * It is simply a stub.
*/
static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n)
{
@@ -176,7 +176,7 @@ static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n)
* error).
*
* \return Resulting offset location within the file, measured in bytes from
- * the beginning of the file. (-1) indicates an error.
+ * the beginning of the file. (-1) indicates an error.
*/
static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
{
@@ -215,8 +215,8 @@ static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
* Closes (virtually) an in-memory TIFF file.
*
* NOTE: All this function actually does is sets the data pointer within the
- * TIFF file to NULL. That should trigger assertion errors if attempts
- * are made to access the file after that point. However, no such
+ * TIFF file to NULL. That should trigger assertion errors if attempts
+ * are made to access the file after that point. However, no such
* attempts should ever be made (in theory).
*
* \param handle: Handle of the TIFF file (pointer to #ImbTIFFMemFile).
@@ -734,7 +734,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
int x, y, from_i, to_i, i;
int compress_mode = COMPRESSION_NONE;
- /* check for a valid number of bytes per pixel. Like the PNG writer,
+ /* check for a valid number of bytes per pixel. Like the PNG writer,
* the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
* to gray, RGB, RGBA respectively. */
samplesperpixel = (uint16_t)((ibuf->planes + 7) >> 3);
@@ -838,7 +838,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
- /* copy pixel data. While copying, we flip the image vertically. */
+ /* copy pixel data. While copying, we flip the image vertically. */
const int channels_in_float = ibuf->channels ? ibuf->channels : 4;
for (x = 0; x < ibuf->x; x++) {
for (y = 0; y < ibuf->y; y++) {
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index edb47c8c7ce..1499c1071e3 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -293,30 +293,37 @@ class Sampler {
NumChannels == 4) {
const float wrapped_u = uv_wrapper.modify_u(source, u);
const float wrapped_v = uv_wrapper.modify_v(source, v);
- bilinear_interpolation_color_fl(source, nullptr, &r_sample[0], wrapped_u, wrapped_v);
+ bilinear_interpolation_color_fl(source, nullptr, r_sample.data(), wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_NEAREST &&
std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
const float wrapped_u = uv_wrapper.modify_u(source, u);
const float wrapped_v = uv_wrapper.modify_v(source, v);
- nearest_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ nearest_interpolation_color_char(source, r_sample.data(), nullptr, wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_BILINEAR &&
std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
const float wrapped_u = uv_wrapper.modify_u(source, u);
const float wrapped_v = uv_wrapper.modify_v(source, v);
- bilinear_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ bilinear_interpolation_color_char(source, r_sample.data(), nullptr, wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) {
if constexpr (std::is_same_v<UVWrapping, WrapRepeatUV>) {
- BLI_bilinear_interpolation_wrap_fl(
- source->rect_float, &r_sample[0], source->x, source->y, NumChannels, u, v, true, true);
+ BLI_bilinear_interpolation_wrap_fl(source->rect_float,
+ r_sample.data(),
+ source->x,
+ source->y,
+ NumChannels,
+ u,
+ v,
+ true,
+ true);
}
else {
const float wrapped_u = uv_wrapper.modify_u(source, u);
const float wrapped_v = uv_wrapper.modify_v(source, v);
BLI_bilinear_interpolation_fl(source->rect_float,
- &r_sample[0],
+ r_sample.data(),
source->x,
source->y,
NumChannels,
@@ -390,11 +397,11 @@ class ChannelConverter {
BLI_STATIC_ASSERT(SourceNumChannels == 4, "Unsigned chars always have 4 channels.");
BLI_STATIC_ASSERT(DestinationNumChannels == 4, "Unsigned chars always have 4 channels.");
- copy_v4_v4_uchar(pixel_pointer.get_pointer(), &sample[0]);
+ copy_v4_v4_uchar(pixel_pointer.get_pointer(), sample.data());
}
else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 4 &&
DestinationNumChannels == 4) {
- copy_v4_v4(pixel_pointer.get_pointer(), &sample[0]);
+ copy_v4_v4(pixel_pointer.get_pointer(), sample.data());
}
else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 3 &&
DestinationNumChannels == 4) {
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 8e004938a89..5feb0ceb515 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -28,17 +28,30 @@ static void imb_gpu_get_format(const ImBuf *ibuf,
eGPUTextureFormat *r_texture_format)
{
const bool float_rect = (ibuf->rect_float != NULL);
- const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
- !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
- high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
-
- *r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
if (float_rect) {
- *r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
+ /* Float. */
+ const bool use_high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
+ *r_data_format = GPU_DATA_FLOAT;
+ *r_texture_format = use_high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
}
else {
- *r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8;
+ if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+ /* Non-color data or scene linear, just store buffer as is. */
+ *r_data_format = GPU_DATA_UBYTE;
+ *r_texture_format = GPU_RGBA8;
+ }
+ else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
+ /* sRGB, store as byte texture that the GPU can decode directly. */
+ *r_data_format = GPU_DATA_UBYTE;
+ *r_texture_format = GPU_SRGB8_A8;
+ }
+ else {
+ /* Other colorspace, store as half float texture to avoid precision loss. */
+ *r_data_format = GPU_DATA_FLOAT;
+ *r_texture_format = GPU_RGBA16F;
+ }
}
}
@@ -74,7 +87,6 @@ static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *
static void *imb_gpu_get_data(const ImBuf *ibuf,
const bool do_rescale,
const int rescale_size[2],
- const bool compress_as_srgb,
const bool store_premultiplied,
bool *r_freedata)
{
@@ -99,14 +111,16 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
}
}
else {
- /* Byte image is in original colorspace from the file. If the file is sRGB
- * scene linear, or non-color data no conversion is needed. Otherwise we
- * compress as scene linear + sRGB transfer function to avoid precision loss
- * in common cases.
+ /* Byte image is in original colorspace from the file, and may need conversion.
*
* We must also convert to premultiplied for correct texture interpolation
* and consistency with float images. */
- if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ /* Non-color data, just store buffer as is. */
+ }
+ else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+ /* sRGB or scene linear, store as byte texture that the GPU can decode directly. */
data_rect = MEM_mallocN(sizeof(uchar[4]) * ibuf->x * ibuf->y, __func__);
*r_freedata = freedata = true;
@@ -120,7 +134,24 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
* zero alpha areas, and appears generally closer to what game engines that we
* want to be compatible with do. */
IMB_colormanagement_imbuf_to_byte_texture(
- (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
+ (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
+ }
+ else {
+ /* Other colorspace, store as float texture to avoid precision loss. */
+ data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
+ *r_freedata = freedata = true;
+
+ if (data_rect == NULL) {
+ return NULL;
+ }
+
+ /* Texture storage of images is defined by the alpha mode of the image. The
+ * downside of this is that there can be artifacts near alpha edges. However,
+ * this allows us to use sRGB texture formats and preserves color values in
+ * zero alpha areas, and appears generally closer to what game engines that we
+ * want to be compatible with do. */
+ IMB_colormanagement_imbuf_to_float_texture(
+ (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
}
}
@@ -181,10 +212,9 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex,
eGPUTextureFormat tex_format;
imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
- const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
bool freebuf = false;
- void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
+ void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf);
/* Update Texture. */
GPU_texture_update_sub(tex, data_format, data, x, y, z, w, h, 1);
@@ -238,7 +268,6 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
eGPUTextureFormat tex_format;
imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
- const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
bool freebuf = false;
/* Create Texture. */
@@ -250,7 +279,7 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
do_rescale = true;
}
BLI_assert(tex != NULL);
- void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
+ void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf);
GPU_texture_update(tex, data_format, data);
GPU_texture_anisotropic_filter(tex, true);
diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt
index b5f2694c2da..8b20b50a181 100644
--- a/source/blender/io/CMakeLists.txt
+++ b/source/blender/io/CMakeLists.txt
@@ -1,8 +1,21 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright 2020 Blender Foundation. All rights reserved.
-add_subdirectory(common)
-add_subdirectory(wavefront_obj)
+if(WITH_IO_WAVEFRONT_OBJ OR WITH_IO_STL OR WITH_IO_GPENCIL OR WITH_ALEMBIC OR WITH_USD)
+ add_subdirectory(common)
+endif()
+
+if(WITH_IO_WAVEFRONT_OBJ)
+ add_subdirectory(wavefront_obj)
+endif()
+
+if(WITH_IO_STL)
+ add_subdirectory(stl)
+endif()
+
+if(WITH_IO_GPENCIL)
+ add_subdirectory(gpencil)
+endif()
if(WITH_ALEMBIC)
add_subdirectory(alembic)
@@ -19,5 +32,3 @@ endif()
if(WITH_USD)
add_subdirectory(usd)
endif()
-
-add_subdirectory(gpencil)
diff --git a/source/blender/io/alembic/exporter/abc_custom_props.cc b/source/blender/io/alembic/exporter/abc_custom_props.cc
index 23a39ca2ee6..c5cc4631e18 100644
--- a/source/blender/io/alembic/exporter/abc_custom_props.cc
+++ b/source/blender/io/alembic/exporter/abc_custom_props.cc
@@ -150,7 +150,7 @@ void CustomPropertiesExporter::write_idparray_of_strings(const IDProperty *idp_a
}
/* Alembic needs a pointer to the first value of the array. */
- const std::string *array_of_strings = &strings[0];
+ const std::string *array_of_strings = strings.data();
set_array_property<OStringArrayProperty, std::string>(
idp_array->name, array_of_strings, strings.size());
}
@@ -204,7 +204,7 @@ void CustomPropertiesExporter::write_idparray_flattened_typed(const IDProperty *
}
set_array_property<ABCPropertyType, BlenderValueType>(
- idp_array->name, &matrix_values[0], matrix_values.size());
+ idp_array->name, matrix_values.data(), matrix_values.size());
}
template<typename ABCPropertyType, typename BlenderValueType>
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index 6e4ec6d23fa..2820a128072 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -257,7 +257,7 @@ void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &
/* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them
* unnormalized, so we need to unnormalize (invert transform) them. */
BKE_mesh_orco_verts_transform(
- mesh, reinterpret_cast<float(*)[3]>(&coords[0]), mesh->totvert, true);
+ mesh, reinterpret_cast<float(*)[3]>(coords.data()), mesh->totvert, true);
if (!config.abc_orco.valid()) {
/* Create the Alembic property and keep a reference so future frames can reuse it. */
diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc
index 0d4e1d04db0..1fb535a57f2 100644
--- a/source/blender/io/alembic/intern/alembic_capi.cc
+++ b/source/blender/io/alembic/intern/alembic_capi.cc
@@ -573,12 +573,10 @@ static void import_endjob(void *user_data)
ImportJobData *data = static_cast<ImportJobData *>(user_data);
- std::vector<AbcObjectReader *>::iterator iter;
-
/* Delete objects on cancellation. */
if (data->was_cancelled) {
- for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
- Object *ob = (*iter)->object();
+ for (AbcObjectReader *reader : data->readers) {
+ Object *ob = reader->object();
/* It's possible that cancellation occurred between the creation of
* the reader and the creation of the Blender object. */
@@ -590,7 +588,6 @@ static void import_endjob(void *user_data)
}
}
else {
- /* Add object to scene. */
Base *base;
LayerCollection *lc;
ViewLayer *view_layer = data->view_layer;
@@ -599,11 +596,17 @@ static void import_endjob(void *user_data)
lc = BKE_layer_collection_get_active(view_layer);
- for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
- Object *ob = (*iter)->object();
-
+ /* Add all objects to the collection (don't do sync for each object). */
+ BKE_layer_collection_resync_forbid();
+ for (AbcObjectReader *reader : data->readers) {
+ Object *ob = reader->object();
BKE_collection_object_add(data->bmain, lc->collection, ob);
-
+ }
+ /* Sync the collection, and do view layer operations. */
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync(data->bmain);
+ for (AbcObjectReader *reader : data->readers) {
+ Object *ob = reader->object();
base = BKE_view_layer_base_find(view_layer, ob);
/* TODO: is setting active needed? */
BKE_view_layer_base_select_and_set_active(view_layer, base);
@@ -625,8 +628,7 @@ static void import_endjob(void *user_data)
}
}
- for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
- AbcObjectReader *reader = *iter;
+ for (AbcObjectReader *reader : data->readers) {
reader->decref();
if (reader->refcount() == 0) {
diff --git a/source/blender/io/avi/AVI_avi.h b/source/blender/io/avi/AVI_avi.h
index e3af171355d..0857b9191b2 100644
--- a/source/blender/io/avi/AVI_avi.h
+++ b/source/blender/io/avi/AVI_avi.h
@@ -235,7 +235,8 @@ AviError AVI_close_compress(AviMovie *movie);
*/
AviError AVI_set_compress_option(
AviMovie *movie, int option_type, int stream, AviOption option, void *opt_data);
-/* Hmmm... there should be some explanation about what these mean */
+
+/* TODO: there should be some explanation about what these mean. */
/**
* Compression option, for use in avi_set_compress_option
*/
diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp
index 29c17b500f3..cbb30ccf51d 100644
--- a/source/blender/io/collada/BCAnimationSampler.cpp
+++ b/source/blender/io/collada/BCAnimationSampler.cpp
@@ -225,24 +225,26 @@ bool BCAnimationSampler::is_animated_by_constraint(Object *ob,
for (con = (bConstraint *)conlist->first; con; con = con->next) {
ListBase targets = {nullptr, nullptr};
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
if (!bc_validateConstraints(con)) {
continue;
}
- if (cti && cti->get_constraint_targets) {
+ if (BKE_constraint_targets_get(con, &targets)) {
bConstraintTarget *ct;
Object *obtar;
- cti->get_constraint_targets(con, &targets);
+ bool found = false;
+
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
obtar = ct->tar;
if (obtar) {
if (animated_objects.find(obtar) != animated_objects.end()) {
- return true;
+ found = true;
+ break;
}
}
}
+ BKE_constraint_targets_flush(con, &targets, true);
+ return found;
}
}
return false;
diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp
index fc97110611a..d48e46ca115 100644
--- a/source/blender/io/collada/BCMath.cpp
+++ b/source/blender/io/collada/BCMath.cpp
@@ -49,11 +49,7 @@ BCMatrix::BCMatrix(BC_global_forward_axis global_forward_axis, BC_global_up_axis
float mrot[3][3];
float mat[4][4];
mat3_from_axis_conversion(
- BC_DEFAULT_FORWARD, BC_DEFAULT_UP, global_forward_axis, global_up_axis, mrot);
-
- /* TODO: Verify that `mat3_from_axis_conversion()` returns a transposed matrix */
- transpose_m3(mrot);
-
+ global_forward_axis, global_up_axis, BC_DEFAULT_FORWARD, BC_DEFAULT_UP, mrot);
copy_m4_m3(mat, mrot);
set_transform(mat);
}
diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h
index 85f960abfe6..416b5728b66 100644
--- a/source/blender/io/collada/MeshImporter.h
+++ b/source/blender/io/collada/MeshImporter.h
@@ -72,7 +72,7 @@ class MeshImporter : public MeshImporterBase {
std::map<std::string, std::string> mesh_geom_map; /* needed for correct shape key naming */
std::map<COLLADAFW::UniqueId, Mesh *> uid_mesh_map; /* geometry unique id-to-mesh map */
- std::map<COLLADAFW::UniqueId, Object *> uid_object_map; /* geom uid-to-object */
+ std::map<COLLADAFW::UniqueId, Object *> uid_object_map; /* geom UID-to-object */
std::vector<Object *> imported_objects; /* list of imported objects */
/* this structure is used to assign material indices to polygons
@@ -86,7 +86,7 @@ class MeshImporter : public MeshImporterBase {
/* crazy name! */
std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map;
/* < materials that have already been mapped to a geometry.
- * A pair/of geom uid and mat uid, one geometry can have several materials */
+ * A pair/of geom UID and mat UID, one geometry can have several materials. */
std::multimap<COLLADAFW::UniqueId, COLLADAFW::UniqueId> materials_mapped_to_geom;
bool set_poly_indices(
diff --git a/source/blender/io/collada/SceneExporter.cpp b/source/blender/io/collada/SceneExporter.cpp
index ea95729666a..1b1da110573 100644
--- a/source/blender/io/collada/SceneExporter.cpp
+++ b/source/blender/io/collada/SceneExporter.cpp
@@ -191,24 +191,19 @@ void SceneExporter::writeNode(Object *ob)
/* not ideal: add the target object name as another parameter.
* No real mapping in the `.dae`.
* Need support for multiple target objects also. */
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {nullptr, nullptr};
- if (cti && cti->get_constraint_targets) {
+ ListBase targets = {nullptr, nullptr};
+ if (BKE_constraint_targets_get(con, &targets)) {
bConstraintTarget *ct;
Object *obtar;
- cti->get_constraint_targets(con, &targets);
-
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
obtar = ct->tar;
std::string tar_id((obtar) ? id_name(obtar) : "");
colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "target_id", tar_id);
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, true);
- }
+ BKE_constraint_targets_flush(con, &targets, true);
}
con = con->next;
diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt
index e80bd850825..a6818c0bf5d 100644
--- a/source/blender/io/common/CMakeLists.txt
+++ b/source/blender/io/common/CMakeLists.txt
@@ -8,6 +8,7 @@ set(INC
../../depsgraph
../../makesdna
../../../../intern/guardedalloc
+ ../../makesrna
)
set(INC_SYS
@@ -19,12 +20,14 @@ set(SRC
intern/dupli_persistent_id.cc
intern/object_identifier.cc
intern/path_util.cc
+ intern/orientation.c
IO_abstract_hierarchy_iterator.h
IO_dupli_persistent_id.hh
IO_path_util.hh
IO_path_util_types.h
IO_types.h
+ IO_orientation.h
intern/dupli_parent_finder.hh
)
diff --git a/source/blender/io/common/IO_abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
index 3371501db95..a67cfe6a9d6 100644
--- a/source/blender/io/common/IO_abstract_hierarchy_iterator.h
+++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
@@ -59,9 +59,8 @@ struct HierarchyContext {
*
* The export hierarchy is kept as close to the hierarchy in Blender as possible. As such, an
* object that serves as a parent for another object, but which should NOT be exported itself, is
- * exported only as transform (i.e. as empty). This happens with objects that are part of a
- * holdout collection (which prevents them from being exported) but also parent of an exported
- * object. */
+ * exported only as transform (i.e. as empty). This happens with objects that are invisible when
+ * exporting with "Visible Only" enabled, for example. */
bool weak_export;
/* When true, this object should check its parents for animation data when determining whether
diff --git a/source/blender/io/common/IO_orientation.h b/source/blender/io/common/IO_orientation.h
new file mode 100644
index 00000000000..09fcbc7045c
--- /dev/null
+++ b/source/blender/io/common/IO_orientation.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "RNA_types.h"
+
+typedef enum {
+ IO_AXIS_X = 0,
+ IO_AXIS_Y = 1,
+ IO_AXIS_Z = 2,
+ IO_AXIS_NEGATIVE_X = 3,
+ IO_AXIS_NEGATIVE_Y = 4,
+ IO_AXIS_NEGATIVE_Z = 5,
+} eIOAxis;
+
+extern const EnumPropertyItem io_transform_axis[];
diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
index 82bb1c57833..1fbddc45964 100644
--- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
@@ -267,6 +267,11 @@ void AbstractHierarchyIterator::export_graph_construct()
{
Scene *scene = DEG_get_evaluated_scene(depsgraph_);
+ /* Add a "null" root node with no children immediately for the case where the top-most node in
+ * the scene is not being exported and a root node otherwise wouldn't get added. */
+ ExportGraph::key_type root_node_id = ObjectIdentifier::for_real_object(nullptr);
+ export_graph_[root_node_id] = ExportChildren();
+
DEG_OBJECT_ITER_BEGIN (depsgraph_,
object,
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
diff --git a/source/blender/io/common/intern/orientation.c b/source/blender/io/common/intern/orientation.c
new file mode 100644
index 00000000000..0ffbaa8fe8e
--- /dev/null
+++ b/source/blender/io/common/intern/orientation.c
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "RNA_types.h"
+
+#include "IO_orientation.h"
+
+const EnumPropertyItem io_transform_axis[] = {
+ {IO_AXIS_X, "X", 0, "X", "Positive X axis"},
+ {IO_AXIS_Y, "Y", 0, "Y", "Positive Y axis"},
+ {IO_AXIS_Z, "Z", 0, "Z", "Positive Z axis"},
+ {IO_AXIS_NEGATIVE_X, "NEGATIVE_X", 0, "-X", "Negative X axis"},
+ {IO_AXIS_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y", "Negative Y axis"},
+ {IO_AXIS_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z", "Negative Z axis"},
+ {0, NULL, 0, NULL, NULL}};
diff --git a/source/blender/io/stl/CMakeLists.txt b/source/blender/io/stl/CMakeLists.txt
new file mode 100644
index 00000000000..e0c48bbbf7e
--- /dev/null
+++ b/source/blender/io/stl/CMakeLists.txt
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set(INC
+ .
+ ./importer
+ ../common
+ ../../blenkernel
+ ../../blenlib
+ ../../bmesh
+ ../../bmesh/intern
+ ../../depsgraph
+ ../../editors/include
+ ../../makesdna
+ ../../makesrna
+ ../../nodes
+ ../../windowmanager
+ ../../../../extern/fast_float
+ ../../../../intern/guardedalloc
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ IO_stl.cc
+ importer/stl_import_mesh.cc
+ importer/stl_import_ascii_reader.cc
+ importer/stl_import_binary_reader.cc
+ importer/stl_import.cc
+
+ IO_stl.h
+ importer/stl_import_mesh.hh
+ importer/stl_import_ascii_reader.hh
+ importer/stl_import_binary_reader.hh
+ importer/stl_import.hh
+)
+
+set(LIB
+ bf_blenkernel
+ bf_io_common
+)
+
+blender_add_lib(bf_stl "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/io/stl/IO_stl.cc b/source/blender/io/stl/IO_stl.cc
new file mode 100644
index 00000000000..b26c1533692
--- /dev/null
+++ b/source/blender/io/stl/IO_stl.cc
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include "BLI_timeit.hh"
+
+#include "IO_stl.h"
+#include "stl_import.hh"
+
+void STL_import(bContext *C, const struct STLImportParams *import_params)
+{
+ SCOPED_TIMER("STL Import");
+ blender::io::stl::importer_main(C, *import_params);
+}
diff --git a/source/blender/io/stl/IO_stl.h b/source/blender/io/stl/IO_stl.h
new file mode 100644
index 00000000000..bbe537948e8
--- /dev/null
+++ b/source/blender/io/stl/IO_stl.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include "BKE_context.h"
+#include "BLI_path_util.h"
+#include "IO_orientation.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct STLImportParams {
+ /** Full path to the source STL file to import. */
+ char filepath[FILE_MAX];
+ eIOAxis forward_axis;
+ eIOAxis up_axis;
+ bool use_facet_normal;
+ bool use_scene_unit;
+ float global_scale;
+ bool use_mesh_validate;
+};
+
+/**
+ * C-interface for the importer.
+ */
+void STL_import(bContext *C, const struct STLImportParams *import_params);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/io/stl/importer/stl_import.cc b/source/blender/io/stl/importer/stl_import.cc
new file mode 100644
index 00000000000..f358598a216
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import.cc
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include <cstdio>
+
+#include "BKE_customdata.h"
+#include "BKE_layer.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_fileops.hh"
+#include "BLI_math_vector.h"
+#include "BLI_memory_utils.hh"
+
+#include "DNA_object_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "stl_import.hh"
+#include "stl_import_ascii_reader.hh"
+#include "stl_import_binary_reader.hh"
+
+namespace blender::io::stl {
+
+void importer_main(bContext *C, const STLImportParams &import_params)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ importer_main(bmain, scene, view_layer, import_params);
+}
+
+void importer_main(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ const STLImportParams &import_params)
+{
+ FILE *file = BLI_fopen(import_params.filepath, "rb");
+ if (!file) {
+ fprintf(stderr, "Failed to open STL file:'%s'.\n", import_params.filepath);
+ return;
+ }
+ BLI_SCOPED_DEFER([&]() { fclose(file); });
+
+ /* Detect STL file type by comparing file size with expected file size,
+ * could check if file starts with "solid", but some files do not adhere,
+ * this is the same as the old Python importer.
+ */
+ uint32_t num_tri = 0;
+ size_t file_size = BLI_file_size(import_params.filepath);
+ fseek(file, BINARY_HEADER_SIZE, SEEK_SET);
+ fread(&num_tri, sizeof(uint32_t), 1, file);
+ bool is_ascii_stl = (file_size != (BINARY_HEADER_SIZE + 4 + BINARY_STRIDE * num_tri));
+
+ /* Name used for both mesh and object. */
+ char ob_name[FILE_MAX];
+ BLI_strncpy(ob_name, BLI_path_basename(import_params.filepath), FILE_MAX);
+ BLI_path_extension_replace(ob_name, FILE_MAX, "");
+
+ Mesh *mesh;
+ if (is_ascii_stl) {
+ mesh = read_stl_ascii(import_params.filepath, bmain, ob_name, import_params.use_facet_normal);
+ }
+ else {
+ mesh = read_stl_binary(file, bmain, ob_name, import_params.use_facet_normal);
+ }
+
+ if (import_params.use_mesh_validate) {
+ bool verbose_validate = false;
+#ifdef DEBUG
+ verbose_validate = true;
+#endif
+ BKE_mesh_validate(mesh, verbose_validate, false);
+ }
+
+ BKE_view_layer_base_deselect_all(view_layer);
+ LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
+ Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name);
+ BKE_mesh_assign_object(bmain, obj, mesh);
+ BKE_collection_object_add(bmain, lc->collection, obj);
+ Base *base = BKE_view_layer_base_find(view_layer, obj);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
+
+ float global_scale = import_params.global_scale;
+ if ((scene->unit.system != USER_UNIT_NONE) && import_params.use_scene_unit) {
+ global_scale *= scene->unit.scale_length;
+ }
+ float scale_vec[3] = {global_scale, global_scale, global_scale};
+ float obmat3x3[3][3];
+ unit_m3(obmat3x3);
+ float obmat4x4[4][4];
+ unit_m4(obmat4x4);
+ /* +Y-forward and +Z-up are the Blender's default axis settings. */
+ mat3_from_axis_conversion(
+ IO_AXIS_Y, IO_AXIS_Z, import_params.forward_axis, import_params.up_axis, obmat3x3);
+ copy_m4_m3(obmat4x4, obmat3x3);
+ rescale_m4(obmat4x4, scale_vec);
+ BKE_object_apply_mat4(obj, obmat4x4, true, false);
+
+ DEG_id_tag_update(&lc->collection->id, ID_RECALC_COPY_ON_WRITE);
+ int flags = ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION |
+ ID_RECALC_BASE_FLAGS;
+ DEG_id_tag_update_ex(bmain, &obj->id, flags);
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
+ DEG_relations_tag_update(bmain);
+}
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import.hh b/source/blender/io/stl/importer/stl_import.hh
new file mode 100644
index 00000000000..377544c26af
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import.hh
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include "IO_stl.h"
+
+namespace blender::io::stl {
+
+/* Main import function used from within Blender. */
+void importer_main(bContext *C, const STLImportParams &import_params);
+
+/* Used from tests, where full bContext does not exist. */
+void importer_main(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ const STLImportParams &import_params);
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.cc b/source/blender/io/stl/importer/stl_import_ascii_reader.cc
new file mode 100644
index 00000000000..2edb3c6a114
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_ascii_reader.cc
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include <cstdint>
+#include <cstdio>
+
+#include "BKE_mesh.h"
+
+#include "BLI_fileops.hh"
+#include "BLI_memory_utils.hh"
+#include "BLI_string_ref.hh"
+
+#include "DNA_mesh_types.h"
+
+/* NOTE: we could use C++17 <charconv> from_chars to parse
+ * floats, but even if some compilers claim full support,
+ * their standard libraries are not quite there yet.
+ * LLVM/libc++ only has a float parser since LLVM 14,
+ * and gcc/libstdc++ since 11.1. So until at least these are
+ * the minimum spec, use an external library. */
+#include "fast_float.h"
+
+#include "stl_import.hh"
+#include "stl_import_ascii_reader.hh"
+#include "stl_import_mesh.hh"
+
+namespace blender::io::stl {
+
+class StringBuffer {
+ private:
+ char *start;
+ const char *end;
+
+ public:
+ StringBuffer(char *buf, size_t len)
+ {
+ start = buf;
+ end = start + len;
+ }
+
+ bool is_empty() const
+ {
+ return start == end;
+ }
+
+ void drop_leading_control_chars()
+ {
+ while ((start < end) && (*start) <= ' ') {
+ start++;
+ }
+ }
+
+ void drop_leading_non_control_chars()
+ {
+ while ((start < end) && (*start) > ' ') {
+ start++;
+ }
+ }
+
+ void drop_line()
+ {
+ while (start < end && *start != '\n') {
+ start++;
+ }
+ }
+
+ bool parse_token(const char *token, size_t token_length)
+ {
+ drop_leading_control_chars();
+ if (end - start < token_length + 1) {
+ return false;
+ }
+ if (memcmp(start, token, token_length) != 0) {
+ return false;
+ }
+ if (start[token_length] > ' ') {
+ return false;
+ }
+ start += token_length + 1;
+ return true;
+ }
+
+ void drop_token()
+ {
+ drop_leading_non_control_chars();
+ drop_leading_control_chars();
+ }
+
+ void parse_float(float &out)
+ {
+ drop_leading_control_chars();
+ /* Skip '+' */
+ if (start < end && *start == '+') {
+ start++;
+ }
+ fast_float::from_chars_result res = fast_float::from_chars(start, end, out);
+ if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
+ out = 0.0f;
+ }
+ start = const_cast<char *>(res.ptr);
+ }
+};
+
+static inline void parse_float3(StringBuffer &buf, float out[3])
+{
+ for (int i = 0; i < 3; i++) {
+ buf.parse_float(out[i]);
+ }
+}
+
+Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals)
+{
+ size_t buffer_len;
+ void *buffer = BLI_file_read_text_as_mem(filepath, 0, &buffer_len);
+ if (buffer == nullptr) {
+ fprintf(stderr, "STL Importer: cannot read from ASCII STL file: '%s'\n", filepath);
+ return BKE_mesh_add(bmain, mesh_name);
+ }
+ BLI_SCOPED_DEFER([&]() { MEM_freeN(buffer); });
+
+ int num_reserved_tris = 1024;
+
+ StringBuffer str_buf(static_cast<char *>(buffer), buffer_len);
+ STLMeshHelper stl_mesh(num_reserved_tris, use_custom_normals);
+ float triangle_buf[3][3];
+ float custom_normal_buf[3];
+ str_buf.drop_line(); /* Skip header line */
+ while (!str_buf.is_empty()) {
+ if (str_buf.parse_token("vertex", 6)) {
+ parse_float3(str_buf, triangle_buf[0]);
+ if (str_buf.parse_token("vertex", 6)) {
+ parse_float3(str_buf, triangle_buf[1]);
+ }
+ if (str_buf.parse_token("vertex", 6)) {
+ parse_float3(str_buf, triangle_buf[2]);
+ }
+ if (use_custom_normals) {
+ stl_mesh.add_triangle(
+ triangle_buf[0], triangle_buf[1], triangle_buf[2], custom_normal_buf);
+ }
+ else {
+ stl_mesh.add_triangle(triangle_buf[0], triangle_buf[1], triangle_buf[2]);
+ }
+ }
+ else if (str_buf.parse_token("facet", 5)) {
+ str_buf.drop_token(); /* Expecting "normal" */
+ parse_float3(str_buf, custom_normal_buf);
+ }
+ else {
+ str_buf.drop_token();
+ }
+ }
+
+ return stl_mesh.to_mesh(bmain, mesh_name);
+}
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.hh b/source/blender/io/stl/importer/stl_import_ascii_reader.hh
new file mode 100644
index 00000000000..e8aed911bf1
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_ascii_reader.hh
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include <cstdio>
+
+#include "BKE_mesh.h"
+
+#include "stl_import.hh"
+
+/**
+ * ASCII STL spec:
+ * <pre>
+ * solid name
+ * facet normal ni nj nk
+ * outer loop
+ * vertex v1x v1y v1z
+ * vertex v2x v2y v2z
+ * vertex v3x v3y v3z
+ * endloop
+ * endfacet
+ * ...
+ * endsolid name
+ * </pre>
+ */
+
+namespace blender::io::stl {
+
+Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals);
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.cc b/source/blender/io/stl/importer/stl_import_binary_reader.cc
new file mode 100644
index 00000000000..6eaed16160e
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_binary_reader.cc
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include <cstdint>
+#include <cstdio>
+
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+
+#include "BLI_array.hh"
+#include "BLI_memory_utils.hh"
+
+#include "DNA_mesh_types.h"
+
+#include "stl_import_binary_reader.hh"
+#include "stl_import_mesh.hh"
+
+namespace blender::io::stl {
+
+#pragma pack(push, 1)
+struct STLBinaryTriangle {
+ float normal[3];
+ float v1[3], v2[3], v3[3];
+ uint16_t attribute_byte_count;
+};
+#pragma pack(pop)
+
+Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals)
+{
+ const int chunk_size = 1024;
+ uint32_t num_tris = 0;
+ fseek(file, BINARY_HEADER_SIZE, SEEK_SET);
+ fread(&num_tris, sizeof(uint32_t), 1, file);
+ if (num_tris == 0) {
+ return BKE_mesh_add(bmain, mesh_name);
+ }
+
+ Array<STLBinaryTriangle> tris_buf(chunk_size);
+ STLMeshHelper stl_mesh(num_tris, use_custom_normals);
+ size_t num_read_tris;
+ while ((num_read_tris = fread(tris_buf.data(), sizeof(STLBinaryTriangle), chunk_size, file))) {
+ for (size_t i = 0; i < num_read_tris; i++) {
+ if (use_custom_normals) {
+ stl_mesh.add_triangle(tris_buf[i].v1, tris_buf[i].v2, tris_buf[i].v3, tris_buf[i].normal);
+ }
+ else {
+ stl_mesh.add_triangle(tris_buf[i].v1, tris_buf[i].v2, tris_buf[i].v3);
+ }
+ }
+ }
+
+ return stl_mesh.to_mesh(bmain, mesh_name);
+}
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.hh b/source/blender/io/stl/importer/stl_import_binary_reader.hh
new file mode 100644
index 00000000000..71d5dbbbe58
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_binary_reader.hh
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include <cstdio>
+
+#include "BKE_mesh.h"
+
+/* Binary STL spec.:
+ * UINT8[80] – Header - 80 bytes
+ * UINT32 – Number of triangles - 4 bytes
+ * For each triangle - 50 bytes:
+ * REAL32[3] – Normal vector - 12 bytes
+ * REAL32[3] – Vertex 1 - 12 bytes
+ * REAL32[3] – Vertex 2 - 12 bytes
+ * REAL32[3] – Vertex 3 - 12 bytes
+ * UINT16 – Attribute byte count - 2 bytes
+ */
+
+namespace blender::io::stl {
+
+const size_t BINARY_HEADER_SIZE = 80;
+const size_t BINARY_STRIDE = 12 * 4 + 2;
+
+Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals);
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc
new file mode 100644
index 00000000000..7de8239b233
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_mesh.cc
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include "BKE_customdata.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+
+#include "BLI_array.hh"
+#include "BLI_math_vector.h"
+#include "BLI_math_vector.hh"
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "stl_import_mesh.hh"
+
+namespace blender::io::stl {
+
+STLMeshHelper::STLMeshHelper(int tris_num, bool use_custom_normals)
+ : use_custom_normals_(use_custom_normals)
+{
+ degenerate_tris_num_ = 0;
+ duplicate_tris_num_ = 0;
+ tris_.reserve(tris_num);
+ /* Upper bound (all vertices are unique). */
+ verts_.reserve(tris_num * 3);
+ if (use_custom_normals) {
+ loop_normals_.reserve(tris_num * 3);
+ }
+}
+
+bool STLMeshHelper::add_triangle(const float3 &a, const float3 &b, const float3 &c)
+{
+ int v1_id = verts_.index_of_or_add(a);
+ int v2_id = verts_.index_of_or_add(b);
+ int v3_id = verts_.index_of_or_add(c);
+ if ((v1_id == v2_id) || (v1_id == v3_id) || (v2_id == v3_id)) {
+ degenerate_tris_num_++;
+ return false;
+ }
+ if (!tris_.add({v1_id, v2_id, v3_id})) {
+ duplicate_tris_num_++;
+ return false;
+ }
+ return true;
+}
+
+void STLMeshHelper::add_triangle(const float3 &a,
+ const float3 &b,
+ const float3 &c,
+ const float3 &custom_normal)
+{
+ if (add_triangle(a, b, c)) {
+ loop_normals_.append_n_times(custom_normal, 3);
+ }
+}
+
+Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name)
+{
+ if (degenerate_tris_num_ > 0) {
+ std::cout << "STL Importer: " << degenerate_tris_num_ << "degenerate triangles were removed"
+ << std::endl;
+ }
+ if (duplicate_tris_num_ > 0) {
+ std::cout << "STL Importer: " << duplicate_tris_num_ << "duplicate triangles were removed"
+ << std::endl;
+ }
+
+ Mesh *mesh = BKE_mesh_add(bmain, mesh_name);
+ /* User count is already 1 here, but will be set later in #BKE_mesh_assign_object. */
+ id_us_min(&mesh->id);
+
+ mesh->totvert = verts_.size();
+ mesh->mvert = static_cast<MVert *>(
+ CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert));
+ for (int i = 0; i < mesh->totvert; i++) {
+ copy_v3_v3(mesh->mvert[i].co, verts_[i]);
+ }
+
+ mesh->totpoly = tris_.size();
+ mesh->totloop = tris_.size() * 3;
+ mesh->mpoly = static_cast<MPoly *>(
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly));
+ mesh->mloop = static_cast<MLoop *>(
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop));
+
+ threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) {
+ for (const int i : tris_range) {
+ mesh->mpoly[i].loopstart = 3 * i;
+ mesh->mpoly[i].totloop = 3;
+
+ mesh->mloop[3 * i].v = tris_[i].v1;
+ mesh->mloop[3 * i + 1].v = tris_[i].v2;
+ mesh->mloop[3 * i + 2].v = tris_[i].v3;
+ }
+ });
+
+ /* NOTE: edges must be calculated first before setting custom normals. */
+ BKE_mesh_calc_edges(mesh, false, false);
+
+ if (use_custom_normals_ && loop_normals_.size() == mesh->totloop) {
+ BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(loop_normals_.data()));
+ mesh->flag |= ME_AUTOSMOOTH;
+ }
+
+ return mesh;
+}
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_mesh.hh b/source/blender/io/stl/importer/stl_import_mesh.hh
new file mode 100644
index 00000000000..f1c0d2126a9
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_mesh.hh
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include "BLI_math_vec_types.hh"
+#include "BLI_set.hh"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
+
+#include "DNA_mesh_types.h"
+
+namespace blender::io::stl {
+class Triangle {
+ public:
+ int v1, v2, v3;
+ /* Based on an old version of Python's frozen-set hash
+ * https://web.archive.org/web/20220520211017/https://stackoverflow.com/questions/20832279/python-frozenset-hashing-algorithm-implementation
+ */
+ uint64_t hash() const
+ {
+ uint64_t res = 1927868237UL;
+ res *= 4;
+ res ^= (v1 ^ (v1 << 16) ^ 89869747UL) * 3644798167UL;
+ res ^= (v2 ^ (v2 << 16) ^ 89869747UL) * 3644798167UL;
+ res ^= (v3 ^ (v3 << 16) ^ 89869747UL) * 3644798167UL;
+ return res * 69069U + 907133923UL;
+ }
+ friend bool operator==(const Triangle &a, const Triangle &b)
+ {
+ bool i = (a.v1 == b.v1) && (a.v2 == b.v2) && (a.v3 == b.v3);
+ bool j = (a.v1 == b.v1) && (a.v3 == b.v2) && (a.v2 == b.v3);
+ bool k = (a.v2 == b.v1) && (a.v1 == b.v2) && (a.v3 == b.v3);
+
+ bool l = (a.v2 == b.v1) && (a.v3 == b.v2) && (a.v1 == b.v3);
+ bool m = (a.v3 == b.v1) && (a.v1 == b.v2) && (a.v2 == b.v3);
+ bool n = (a.v3 == b.v1) && (a.v2 == b.v2) && (a.v1 == b.v3);
+
+ return i || j || k || l || m || n;
+ }
+};
+
+class STLMeshHelper {
+ private:
+ VectorSet<float3> verts_;
+ VectorSet<Triangle> tris_;
+ Vector<float3> loop_normals_;
+ int degenerate_tris_num_;
+ int duplicate_tris_num_;
+ const bool use_custom_normals_;
+
+ public:
+ STLMeshHelper(int tris_num, bool use_custom_normals);
+
+ /* Creates a new triangle from specified vertex locations,
+ * duplicate vertices and triangles are merged.
+ */
+ bool add_triangle(const float3 &a, const float3 &b, const float3 &c);
+ void add_triangle(const float3 &a,
+ const float3 &b,
+ const float3 &c,
+ const float3 &custom_normal);
+ Mesh *to_mesh(Main *bmain, char *mesh_name);
+};
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc
index 29b256125f0..4118205d87f 100644
--- a/source/blender/io/usd/intern/usd_capi_import.cc
+++ b/source/blender/io/usd/intern/usd_capi_import.cc
@@ -277,7 +277,6 @@ static void import_endjob(void *customdata)
}
}
else if (data->archive) {
- /* Add object to scene. */
Base *base;
LayerCollection *lc;
ViewLayer *view_layer = data->view_layer;
@@ -286,20 +285,30 @@ static void import_endjob(void *customdata)
lc = BKE_layer_collection_get_active(view_layer);
+ /* Add all objects to the collection (don't do sync for each object). */
+ BKE_layer_collection_resync_forbid();
for (USDPrimReader *reader : data->archive->readers()) {
-
if (!reader) {
continue;
}
-
Object *ob = reader->object();
-
if (!ob) {
continue;
}
-
BKE_collection_object_add(data->bmain, lc->collection, ob);
+ }
+ /* Sync the collection, and do view layer operations. */
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync(data->bmain);
+ for (USDPrimReader *reader : data->archive->readers()) {
+ if (!reader) {
+ continue;
+ }
+ Object *ob = reader->object();
+ if (!ob) {
+ continue;
+ }
base = BKE_view_layer_base_find(view_layer, ob);
/* TODO: is setting active needed? */
BKE_view_layer_base_select_and_set_active(view_layer, base);
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 2c86bfff4da..36e1a40953c 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -62,11 +62,57 @@ static void build_mat_map(const Main *bmain, std::map<std::string, Material *> *
}
}
+static pxr::UsdShadeMaterial compute_bound_material(const pxr::UsdPrim &prim)
+{
+ return pxr::UsdShadeMaterialBindingAPI(prim).ComputeBoundMaterial();
+}
+
+/* Returns an existing Blender material that corresponds to the USD
+ * material with with the given path. Returns null if no such material
+ * exists. */
+static Material *find_existing_material(
+ const pxr::SdfPath &usd_mat_path,
+ const USDImportParams &params,
+ const std::map<std::string, Material *> &mat_map,
+ const std::map<std::string, std::string> &usd_path_to_mat_name)
+{
+ if (params.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) {
+ /* Check if we've already created the Blender material with a modified name. */
+ std::map<std::string, std::string>::const_iterator path_to_name_iter =
+ usd_path_to_mat_name.find(usd_mat_path.GetAsString());
+
+ if (path_to_name_iter != usd_path_to_mat_name.end()) {
+ std::string mat_name = path_to_name_iter->second;
+ std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name);
+ if (mat_iter != mat_map.end()) {
+ return mat_iter->second;
+ }
+ else {
+ /* We can't find the Blender material which was previously created for this USD
+ * material, which should never happen. */
+ BLI_assert_unreachable();
+ }
+ }
+ }
+ else {
+ std::string mat_name = usd_mat_path.GetName();
+ std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name);
+
+ if (mat_iter != mat_map.end()) {
+ return mat_iter->second;
+ }
+ }
+
+ return nullptr;
+}
+
static void assign_materials(Main *bmain,
Object *ob,
const std::map<pxr::SdfPath, int> &mat_index_map,
const USDImportParams &params,
- pxr::UsdStageRefPtr stage)
+ pxr::UsdStageRefPtr stage,
+ std::map<std::string, Material *> &mat_name_to_mat,
+ std::map<std::string, std::string> &usd_path_to_mat_name)
{
if (!(stage && bmain && ob)) {
return;
@@ -87,20 +133,13 @@ static void assign_materials(Main *bmain,
return;
}
- /* TODO(kevin): use global map? */
- std::map<std::string, Material *> mat_map;
- build_mat_map(bmain, &mat_map);
-
blender::io::usd::USDMaterialReader mat_reader(params, bmain);
for (it = mat_index_map.begin(); it != mat_index_map.end(); ++it) {
- std::string mat_name = it->first.GetName();
-
- std::map<std::string, Material *>::iterator mat_iter = mat_map.find(mat_name);
-
- Material *assigned_mat = nullptr;
- if (mat_iter == mat_map.end()) {
+ Material *assigned_mat = find_existing_material(
+ it->first, params, mat_name_to_mat, usd_path_to_mat_name);
+ if (!assigned_mat) {
/* Blender material doesn't exist, so create it now. */
/* Look up the USD material. */
@@ -122,11 +161,14 @@ static void assign_materials(Main *bmain,
continue;
}
- mat_map[mat_name] = assigned_mat;
- }
- else {
- /* We found an existing Blender material. */
- assigned_mat = mat_iter->second;
+ const std::string mat_name = pxr::TfMakeValidIdentifier(assigned_mat->id.name + 2);
+ mat_name_to_mat[mat_name] = assigned_mat;
+
+ if (params.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) {
+ /* Record the name of the Blender material we created for the USD material
+ * with the given path. */
+ usd_path_to_mat_name[it->first.GetAsString()] = mat_name;
+ }
}
if (assigned_mat) {
@@ -134,7 +176,7 @@ static void assign_materials(Main *bmain,
}
else {
/* This shouldn't happen. */
- std::cout << "WARNING: Couldn't assign material " << mat_name << std::endl;
+ std::cout << "WARNING: Couldn't assign material " << it->first << std::endl;
}
}
}
@@ -710,11 +752,8 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
int current_mat = 0;
if (!subsets.empty()) {
for (const pxr::UsdGeomSubset &subset : subsets) {
- pxr::UsdShadeMaterialBindingAPI subset_api = pxr::UsdShadeMaterialBindingAPI(
- subset.GetPrim());
-
- pxr::UsdShadeMaterial subset_mtl = subset_api.ComputeBoundMaterial();
+ pxr::UsdShadeMaterial subset_mtl = utils::compute_bound_material(subset.GetPrim());
if (!subset_mtl) {
continue;
}
@@ -743,10 +782,9 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
}
if (r_mat_map->empty()) {
- pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(prim_);
-
- if (pxr::UsdShadeMaterial mtl = api.ComputeBoundMaterial()) {
+ pxr::UsdShadeMaterial mtl = utils::compute_bound_material(prim_);
+ if (mtl) {
pxr::SdfPath mtl_path = mtl.GetPath();
if (!mtl_path.IsEmpty()) {
@@ -764,7 +802,17 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot
std::map<pxr::SdfPath, int> mat_map;
assign_facesets_to_mpoly(motionSampleTime, mesh->mpoly, mesh->totpoly, &mat_map);
- utils::assign_materials(bmain, object_, mat_map, this->import_params_, this->prim_.GetStage());
+ /* Build material name map if it's not built yet. */
+ if (this->settings_->mat_name_to_mat.empty()) {
+ utils::build_mat_map(bmain, &this->settings_->mat_name_to_mat);
+ }
+ utils::assign_materials(bmain,
+ object_,
+ mat_map,
+ this->import_params_,
+ this->prim_.GetStage(),
+ this->settings_->mat_name_to_mat,
+ this->settings_->usd_path_to_mat_name);
}
Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
diff --git a/source/blender/io/usd/intern/usd_reader_prim.h b/source/blender/io/usd/intern/usd_reader_prim.h
index fdf6247de16..c44c4a14ad7 100644
--- a/source/blender/io/usd/intern/usd_reader_prim.h
+++ b/source/blender/io/usd/intern/usd_reader_prim.h
@@ -7,7 +7,11 @@
#include <pxr/usd/usd/prim.h>
+#include <map>
+#include <string>
+
struct Main;
+struct Material;
struct Object;
namespace blender::io::usd {
@@ -33,6 +37,17 @@ struct ImportSettings {
CacheFile *cache_file;
+ /* Map a USD material prim path to a Blender material name.
+ * This map is updated by readers during stage traversal.
+ * This field is mutable because it is used to keep track
+ * of what the importer is doing. This is necessary even
+ * when all the other import settings are to remain const. */
+ mutable std::map<std::string, std::string> usd_path_to_mat_name;
+ /* Map a material name to Blender material.
+ * This map is updated by readers during stage traversal,
+ * and is mutable similar to the map above. */
+ mutable std::map<std::string, Material *> mat_name_to_mat;
+
ImportSettings()
: do_convert_mat(false),
from_up(0),
diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc
index 857896b9330..6862f3835cf 100644
--- a/source/blender/io/usd/intern/usd_writer_material.cc
+++ b/source/blender/io/usd/intern/usd_writer_material.cc
@@ -590,6 +590,7 @@ static std::string get_tex_image_asset_path(bNode *node,
BLI_split_dir_part(stage_path.c_str(), dir_path, FILE_MAX);
BLI_path_join(exp_path, FILE_MAX, dir_path, "textures", file_path, nullptr);
}
+ BLI_str_replace_char(exp_path, '\\', '/');
return exp_path;
}
@@ -608,7 +609,7 @@ static std::string get_tex_image_asset_path(bNode *node,
if (!BLI_path_is_rel(rel_path)) {
return path;
}
-
+ BLI_str_replace_char(rel_path, '\\', '/');
return rel_path + 2;
}
diff --git a/source/blender/io/usd/tests/usd_tests_common.h b/source/blender/io/usd/tests/usd_tests_common.h
index 7f6ae558354..949348da959 100644
--- a/source/blender/io/usd/tests/usd_tests_common.h
+++ b/source/blender/io/usd/tests/usd_tests_common.h
@@ -12,7 +12,7 @@ namespace blender::io::usd {
* Thus function must be called before instantiating a USD
* stage to avoid errors. The returned string is the path to
* the USD data files directory from which the plugins were
- * loaded. If the USD data files directory can't be determined,
+ * loaded. If the USD data files directory can't be determined,
* plugin registration is skipped and the empty string is
* returned. */
std::string register_usd_plugins_for_tests();
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index 2e4dcb0da94..a07315d8b4e 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -15,6 +15,13 @@ struct CacheReader;
struct Object;
struct bContext;
+/* Behavior when the name of an imported material
+ * conflicts with an existing material. */
+typedef enum eUSDMtlNameCollisionMode {
+ USD_MTL_NAME_COLLISION_MAKE_UNIQUE = 0,
+ USD_MTL_NAME_COLLISION_REFERENCE_EXISTING = 1,
+} eUSDMtlNameCollisionMode;
+
struct USDExportParams {
bool export_animation;
bool export_hair;
@@ -57,6 +64,7 @@ struct USDImportParams {
bool import_usd_preview;
bool set_material_blend;
float light_intensity_scale;
+ eUSDMtlNameCollisionMode mtl_name_collision_mode;
};
/* The USD_export takes a as_background_job parameter, and returns a boolean.
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
index bebad06d37f..a719dff2126 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -9,30 +9,13 @@
#include "BKE_context.h"
#include "BLI_path_util.h"
#include "DEG_depsgraph.h"
+#include "IO_orientation.h"
#include "IO_path_util_types.h"
#ifdef __cplusplus
extern "C" {
#endif
-typedef enum {
- OBJ_AXIS_X_UP = 0,
- OBJ_AXIS_Y_UP = 1,
- OBJ_AXIS_Z_UP = 2,
- OBJ_AXIS_NEGATIVE_X_UP = 3,
- OBJ_AXIS_NEGATIVE_Y_UP = 4,
- OBJ_AXIS_NEGATIVE_Z_UP = 5,
-} eTransformAxisUp;
-
-typedef enum {
- OBJ_AXIS_X_FORWARD = 0,
- OBJ_AXIS_Y_FORWARD = 1,
- OBJ_AXIS_Z_FORWARD = 2,
- OBJ_AXIS_NEGATIVE_X_FORWARD = 3,
- OBJ_AXIS_NEGATIVE_Y_FORWARD = 4,
- OBJ_AXIS_NEGATIVE_Z_FORWARD = 5,
-} eTransformAxisForward;
-
static const int TOTAL_AXES = 3;
struct OBJExportParams {
@@ -52,8 +35,8 @@ struct OBJExportParams {
int end_frame;
/* Geometry Transform options. */
- eTransformAxisForward forward_axis;
- eTransformAxisUp up_axis;
+ eIOAxis forward_axis;
+ eIOAxis up_axis;
float scaling_factor;
/* File Write Options. */
@@ -62,6 +45,7 @@ struct OBJExportParams {
eEvaluationMode export_eval_mode;
bool export_uv;
bool export_normals;
+ bool export_colors;
bool export_materials;
bool export_triangulated_mesh;
bool export_curves_as_nurbs;
@@ -86,8 +70,8 @@ struct OBJImportParams {
char filepath[FILE_MAX];
/** Value 0 disables clamping. */
float clamp_size;
- eTransformAxisForward forward_axis;
- eTransformAxisUp up_axis;
+ eIOAxis forward_axis;
+ eIOAxis up_axis;
bool validate_meshes;
};
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
index 11d1bafdafe..cb95c561547 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
@@ -8,7 +8,9 @@
#include <cstdio>
#include "BKE_blender_version.h"
+#include "BKE_geometry_set.hh"
+#include "BLI_color.hh"
#include "BLI_enumerable_thread_specific.hh"
#include "BLI_path_util.h"
#include "BLI_task.hh"
@@ -241,13 +243,38 @@ void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh,
}
void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
- const OBJMesh &obj_mesh_data) const
+ const OBJMesh &obj_mesh_data,
+ bool write_colors) const
{
const int tot_count = obj_mesh_data.tot_vertices();
- obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
- float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
- buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
- });
+
+ Mesh *mesh = obj_mesh_data.get_mesh();
+ CustomDataLayer *colors_layer = nullptr;
+ if (write_colors) {
+ colors_layer = BKE_id_attributes_active_color_get(&mesh->id);
+ }
+ if (write_colors && (colors_layer != nullptr)) {
+ MeshComponent component;
+ component.replace(mesh, GeometryOwnershipType::ReadOnly);
+ VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>(
+ colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f});
+
+ BLI_assert(tot_count == attribute.size());
+ obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ ColorGeometry4f linear = attribute.get(i);
+ float srgb[3];
+ linearrgb_to_srgb_v3_v3(srgb, linear);
+ buf.write<eOBJSyntaxElement::vertex_coords_color>(
+ vertex[0], vertex[1], vertex[2], srgb[0], srgb[1], srgb[2]);
+ });
+ }
+ else {
+ obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
+ });
+ }
}
void OBJWriter::write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &r_obj_mesh_data) const
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
index 77da7b44276..97c23484426 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -72,9 +72,11 @@ class OBJWriter : NonMovable, NonCopyable {
*/
void write_mtllib_name(const StringRefNull mtl_filepath) const;
/**
- * Write vertex coordinates for all vertices as "v x y z".
+ * Write vertex coordinates for all vertices as "v x y z" or "v x y z r g b".
*/
- void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const;
+ void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
+ const OBJMesh &obj_mesh_data,
+ bool write_colors) const;
/**
* Write UV vertex coordinates for all vertices as `vt u v`.
* \note UV indices are stored here, but written with polygons later.
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
index f0263989bfc..5413c9969e3 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
@@ -30,6 +30,7 @@ enum class eFileType {
enum class eOBJSyntaxElement {
vertex_coords,
+ vertex_coords_color,
uv_vertex_coords,
normal,
poly_element_begin,
@@ -130,6 +131,9 @@ constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key
case eOBJSyntaxElement::vertex_coords: {
return {"v {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>};
}
+ case eOBJSyntaxElement::vertex_coords_color: {
+ return {"v {:.6f} {:.6f} {:.6f} {:.4f} {:.4f} {:.4f}\n", 6, is_type_float<T...>};
+ }
case eOBJSyntaxElement::uv_vertex_coords: {
return {"vt {:.6f} {:.6f}\n", 2, is_type_float<T...>};
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
index c2a9e0574eb..e2ecda32717 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -117,15 +117,12 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
return {triangulated, true};
}
-void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward,
- const eTransformAxisUp up)
+void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up)
{
float axes_transform[3][3];
unit_m3(axes_transform);
/* +Y-forward and +Z-up are the default Blender axis settings. */
- mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform);
- /* mat3_from_axis_conversion returns a transposed matrix! */
- transpose_m3(axes_transform);
+ mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform);
mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.obmat);
/* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */
mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_.obmat[3]);
@@ -290,7 +287,7 @@ void OBJMesh::store_uv_coords_and_indices()
const MLoop *mloop = export_mesh_eval_->mloop;
const int totpoly = export_mesh_eval_->totpoly;
const int totvert = export_mesh_eval_->totvert;
- const MLoopUV *mloopuv = static_cast<MLoopUV *>(
+ const MLoopUV *mloopuv = static_cast<const MLoopUV *>(
CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV));
if (!mloopuv) {
tot_uv_vertices_ = 0;
@@ -382,8 +379,8 @@ void OBJMesh::store_normal_coords_and_indices()
normal_to_index.reserve(export_mesh_eval_->totpoly);
loop_to_normal_index_.resize(export_mesh_eval_->totloop);
loop_to_normal_index_.fill(-1);
- const float(
- *lnors)[3] = (const float(*)[3])(CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL));
+ const float(*lnors)[3] = static_cast<const float(*)[3]>(
+ CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL));
for (int poly_index = 0; poly_index < export_mesh_eval_->totpoly; ++poly_index) {
const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
bool need_per_loop_normals = lnors != nullptr || (mpoly.flag & ME_SMOOTH);
@@ -453,7 +450,7 @@ int16_t OBJMesh::get_poly_deform_group_index(const int poly_index,
BLI_assert(poly_index < export_mesh_eval_->totpoly);
BLI_assert(group_weights.size() == BKE_object_defgroup_count(&export_object_eval_));
- const MDeformVert *dvert_layer = static_cast<MDeformVert *>(
+ const MDeformVert *dvert_layer = static_cast<const MDeformVert *>(
CustomData_get_layer(&export_mesh_eval_->vdata, CD_MDEFORMVERT));
if (!dvert_layer) {
return NOT_FOUND;
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
index f47ca423dbc..ee2e6227700 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -241,6 +241,11 @@ class OBJMesh : NonCopyable {
return i < 0 || i >= poly_order_.size() ? i : poly_order_[i];
}
+ Mesh *get_mesh() const
+ {
+ return export_mesh_eval_;
+ }
+
private:
/**
* Free the mesh if _the exporter_ created it.
@@ -256,6 +261,6 @@ class OBJMesh : NonCopyable {
/**
* Set the final transform after applying axes settings and an Object's world transform.
*/
- void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up);
+ void set_world_axes_transform(eIOAxis forward, eIOAxis up);
};
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
index c247048ce13..172a59e5341 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
@@ -25,15 +25,12 @@ OBJCurve::OBJCurve(const Depsgraph *depsgraph,
set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
}
-void OBJCurve::set_world_axes_transform(const eTransformAxisForward forward,
- const eTransformAxisUp up)
+void OBJCurve::set_world_axes_transform(const eIOAxis forward, const eIOAxis up)
{
float axes_transform[3][3];
unit_m3(axes_transform);
/* +Y-forward and +Z-up are the Blender's default axis settings. */
- mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform);
- /* mat3_from_axis_conversion returns a transposed matrix! */
- transpose_m3(axes_transform);
+ mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform);
mul_m4_m3m4(world_axes_transform_, axes_transform, export_object_eval_->obmat);
/* #mul_m4_m3m4 does not transform last row of #Object.obmat, i.e. location data. */
mul_v3_m3v3(world_axes_transform_[3], axes_transform, export_object_eval_->obmat[3]);
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
index fe826725daf..65389d44f59 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
@@ -56,7 +56,7 @@ class OBJCurve : NonCopyable {
/**
* Set the final transform after applying axes settings and an Object's world transform.
*/
- void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up);
+ void set_world_axes_transform(eIOAxis forward, eIOAxis up);
};
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
index b6e636b389d..b0938084efb 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
@@ -195,7 +195,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
auto &fh = buffers[i];
obj_writer.write_object_name(fh, obj);
- obj_writer.write_vertex_coords(fh, obj);
+ obj_writer.write_vertex_coords(fh, obj, export_params.export_colors);
if (obj.tot_polygons() > 0) {
if (export_params.export_smooth_groups) {
diff --git a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
index 7019e67419e..f33753d720d 100644
--- a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
+++ b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
@@ -99,13 +99,8 @@ void transform_object(Object *object, const OBJImportParams &import_params)
float obmat[4][4];
unit_m4(obmat);
/* +Y-forward and +Z-up are the default Blender axis settings. */
- mat3_from_axis_conversion(import_params.forward_axis,
- import_params.up_axis,
- OBJ_AXIS_Y_FORWARD,
- OBJ_AXIS_Z_UP,
- axes_transform);
- /* mat3_from_axis_conversion returns a transposed matrix! */
- transpose_m3(axes_transform);
+ mat3_from_axis_conversion(
+ IO_AXIS_Y, IO_AXIS_Z, import_params.forward_axis, import_params.up_axis, axes_transform);
copy_m4_m3(obmat, axes_transform);
BKE_object_apply_mat4(object, obmat, true, false);
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 c7990028312..ee55dd1e45a 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
@@ -5,12 +5,15 @@
*/
#include "BLI_map.hh"
+#include "BLI_math_color.h"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
#include "obj_import_file_reader.hh"
#include "obj_import_string_utils.hh"
+#include <charconv>
+
namespace blender::io::obj {
using std::string;
@@ -34,6 +37,7 @@ static Geometry *create_geometry(Geometry *const prev_geometry,
g->geom_type_ = new_type;
g->geometry_name_ = name.is_empty() ? "New object" : name;
g->vertex_start_ = global_vertices.vertices.size();
+ g->vertex_color_start_ = global_vertices.vertex_colors.size();
r_offset.set_index_offset(g->vertex_start_);
return g;
};
@@ -71,9 +75,51 @@ static void geom_add_vertex(Geometry *geom,
GlobalVertices &r_global_vertices)
{
float3 vert;
- parse_floats(p, end, 0.0f, vert, 3);
+ p = parse_floats(p, end, 0.0f, vert, 3);
r_global_vertices.vertices.append(vert);
geom->vertex_count_++;
+ /* OBJ extension: `xyzrgb` vertex colors, when the vertex position
+ * is followed by 3 more RGB color components. See
+ * http://paulbourke.net/dataformats/obj/colour.html */
+ if (p < end) {
+ float3 srgb;
+ p = parse_floats(p, end, -1.0f, srgb, 3);
+ if (srgb.x >= 0 && srgb.y >= 0 && srgb.z >= 0) {
+ float3 linear;
+ srgb_to_linearrgb_v3_v3(linear, srgb);
+ r_global_vertices.vertex_colors.append(linear);
+ geom->vertex_color_count_++;
+ }
+ }
+}
+
+static void geom_add_mrgb_colors(Geometry *geom,
+ const char *p,
+ const char *end,
+ GlobalVertices &r_global_vertices)
+{
+ /* MRGB color extension, in the form of
+ * "#MRGB MMRRGGBBMMRRGGBB ..."
+ * http://paulbourke.net/dataformats/obj/colour.html */
+ p = drop_whitespace(p, end);
+ const int mrgb_length = 8;
+ while (p + mrgb_length <= end) {
+ uint32_t value = 0;
+ std::from_chars_result res = std::from_chars(p, p + mrgb_length, value, 16);
+ if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
+ return;
+ }
+ unsigned char srgb[4];
+ srgb[0] = (value >> 16) & 0xFF;
+ srgb[1] = (value >> 8) & 0xFF;
+ srgb[2] = value & 0xFF;
+ srgb[3] = 0xFF;
+ float linear[4];
+ srgb_to_linearrgb_uchar4(linear, srgb);
+ r_global_vertices.vertex_colors.append({linear[0], linear[1], linear[2]});
+ geom->vertex_color_count_++;
+ p += mrgb_length;
+ }
}
static void geom_add_vertex_normal(Geometry *geom,
@@ -149,7 +195,7 @@ static void geom_add_polygon(Geometry *geom,
if (p < end && *p == '/') {
++p;
p = parse_int(p, end, INT32_MAX, corner.vertex_normal_index, false);
- got_normal = corner.uv_vert_index != INT32_MAX;
+ got_normal = corner.vertex_normal_index != INT32_MAX;
}
}
/* Always keep stored indices non-negative and zero-based. */
@@ -172,7 +218,10 @@ static void geom_add_polygon(Geometry *geom,
face_valid = false;
}
}
- if (got_normal) {
+ /* Ignore corner normal index, if the geometry does not have any normals.
+ * Some obj files out there do have face definitions that refer to normal indices,
+ * without any normals being present (T98782). */
+ if (got_normal && geom->has_vertex_normals_) {
corner.vertex_normal_index += corner.vertex_normal_index < 0 ?
global_vertices.vertex_normals.size() :
-1;
@@ -343,9 +392,14 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
return;
}
+ /* Use the filename as the default name given to the initial object. */
+ char ob_name[FILE_MAXFILE];
+ BLI_strncpy(ob_name, BLI_path_basename(import_params_.filepath), FILE_MAXFILE);
+ BLI_path_extension_replace(ob_name, FILE_MAXFILE, "");
+
VertexIndexOffset offsets;
Geometry *curr_geom = create_geometry(
- nullptr, GEOM_MESH, "", r_global_vertices, r_all_geometries, offsets);
+ nullptr, GEOM_MESH, ob_name, r_global_vertices, r_all_geometries, offsets);
/* State variables: once set, they remain the same for the remaining
* elements in the object. */
@@ -477,6 +531,9 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
else if (parse_keyword(p, end, "mtllib")) {
add_mtl_library(StringRef(p, end).trim());
}
+ else if (parse_keyword(p, end, "#MRGB")) {
+ geom_add_mrgb_colors(curr_geom, p, end, r_global_vertices);
+ }
/* Comments. */
else if (*p == '#') {
/* Nothing to do. */
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
index 8d560bd2c8c..acc35ad46e1 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
@@ -8,6 +8,7 @@
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
+#include "BKE_attribute.h"
#include "BKE_customdata.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -50,6 +51,7 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
create_edges(mesh);
create_uv_verts(mesh);
create_normals(mesh);
+ create_colors(mesh);
create_materials(bmain, materials, created_materials, obj);
if (import_params.validate_meshes || mesh_geometry_.has_invalid_polys_) {
@@ -289,7 +291,7 @@ static Material *get_or_create_material(Main *bmain,
/* We have not, will have to create it. Create a new default
* MTLMaterial too, in case the OBJ file tries to use a material
* that was not in the MTL file. */
- const MTLMaterial &mtl = *materials.lookup_or_add(name, std::make_unique<MTLMaterial>()).get();
+ const MTLMaterial &mtl = *materials.lookup_or_add(name, std::make_unique<MTLMaterial>());
Material *mat = BKE_material_add(bmain, name.c_str());
ShaderNodetreeWrap mat_wrap{bmain, mtl, mat};
@@ -345,4 +347,26 @@ void MeshFromGeometry::create_normals(Mesh *mesh)
MEM_freeN(loop_normals);
}
+void MeshFromGeometry::create_colors(Mesh *mesh)
+{
+ /* Nothing to do if we don't have vertex colors. */
+ if (mesh_geometry_.vertex_color_count_ < 1) {
+ return;
+ }
+ if (mesh_geometry_.vertex_color_count_ != mesh_geometry_.vertex_count_) {
+ std::cerr << "Mismatching number of vertices (" << mesh_geometry_.vertex_count_
+ << ") and colors (" << mesh_geometry_.vertex_color_count_ << ") on object '"
+ << mesh_geometry_.geometry_name_ << "', ignoring colors." << std::endl;
+ return;
+ }
+
+ CustomDataLayer *color_layer = BKE_id_attribute_new(
+ &mesh->id, "Color", CD_PROP_COLOR, ATTR_DOMAIN_POINT, nullptr);
+ float4 *colors = (float4 *)color_layer->data;
+ for (int i = 0; i < mesh_geometry_.vertex_color_count_; ++i) {
+ float3 c = global_vertices_.vertex_colors[mesh_geometry_.vertex_color_start_ + i];
+ colors[i] = float4(c.x, c.y, c.z, 1.0f);
+ }
+}
+
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh b/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
index cf4a2aee394..216717f3578 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
@@ -65,6 +65,7 @@ class MeshFromGeometry : NonMovable, NonCopyable {
Map<std::string, Material *> &created_materials,
Object *obj);
void create_normals(Mesh *mesh);
+ void create_colors(Mesh *mesh);
};
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_objects.hh b/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
index b67ba46af03..69babc26bb0 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
+++ b/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
@@ -26,6 +26,7 @@ struct GlobalVertices {
Vector<float3> vertices;
Vector<float2> uv_vertices;
Vector<float3> vertex_normals;
+ Vector<float3> vertex_colors;
};
/**
@@ -102,6 +103,8 @@ struct Geometry {
int vertex_start_ = 0;
int vertex_count_ = 0;
+ int vertex_color_start_ = 0;
+ int vertex_color_count_ = 0;
/** Edges written in the file in addition to (or even without polygon) elements. */
Vector<MEdge> edges_;
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
index 8c49af90a82..6aec848573f 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -315,8 +315,8 @@ TEST_F(obj_exporter_regression_test, all_quads)
TEST_F(obj_exporter_regression_test, fgons)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden(
"io_tests/blend_geometry/fgons.blend", "io_tests/obj/fgons.obj", "", _export.params);
@@ -325,8 +325,8 @@ TEST_F(obj_exporter_regression_test, fgons)
TEST_F(obj_exporter_regression_test, edges)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden(
"io_tests/blend_geometry/edges.blend", "io_tests/obj/edges.obj", "", _export.params);
@@ -335,8 +335,8 @@ TEST_F(obj_exporter_regression_test, edges)
TEST_F(obj_exporter_regression_test, vertices)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden(
"io_tests/blend_geometry/vertices.blend", "io_tests/obj/vertices.obj", "", _export.params);
@@ -355,8 +355,8 @@ TEST_F(obj_exporter_regression_test, non_uniform_scale)
TEST_F(obj_exporter_regression_test, nurbs_as_nurbs)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_curves_as_nurbs = true;
compare_obj_export_to_golden(
@@ -366,8 +366,8 @@ TEST_F(obj_exporter_regression_test, nurbs_as_nurbs)
TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_curves_as_nurbs = true;
compare_obj_export_to_golden("io_tests/blend_geometry/nurbs_curves.blend",
@@ -379,8 +379,8 @@ TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs)
TEST_F(obj_exporter_regression_test, nurbs_as_mesh)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_curves_as_nurbs = false;
compare_obj_export_to_golden(
@@ -390,8 +390,8 @@ TEST_F(obj_exporter_regression_test, nurbs_as_mesh)
TEST_F(obj_exporter_regression_test, cube_all_data_triangulated)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_triangulated_mesh = true;
compare_obj_export_to_golden("io_tests/blend_geometry/cube_all_data.blend",
@@ -403,8 +403,8 @@ TEST_F(obj_exporter_regression_test, cube_all_data_triangulated)
TEST_F(obj_exporter_regression_test, cube_normal_edit)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden("io_tests/blend_geometry/cube_normal_edit.blend",
"io_tests/obj/cube_normal_edit.obj",
@@ -436,6 +436,19 @@ TEST_F(obj_exporter_regression_test, cubes_positioned)
_export.params);
}
+TEST_F(obj_exporter_regression_test, cubes_vertex_colors)
+{
+ OBJExportParamsDefault _export;
+ _export.params.export_colors = true;
+ _export.params.export_normals = false;
+ _export.params.export_uv = false;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden("io_tests/blend_geometry/cubes_vertex_colors.blend",
+ "io_tests/obj/cubes_vertex_colors.obj",
+ "",
+ _export.params);
+}
+
TEST_F(obj_exporter_regression_test, cubes_with_textures_strip)
{
OBJExportParamsDefault _export;
@@ -459,8 +472,8 @@ TEST_F(obj_exporter_regression_test, cubes_with_textures_relative)
TEST_F(obj_exporter_regression_test, suzanne_all_data)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_smooth_groups = true;
compare_obj_export_to_golden("io_tests/blend_geometry/suzanne_all_data.blend",
@@ -491,9 +504,10 @@ TEST_F(obj_exporter_regression_test, all_curves_as_nurbs)
TEST_F(obj_exporter_regression_test, all_objects)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_smooth_groups = true;
+ _export.params.export_colors = true;
compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend",
"io_tests/obj/all_objects.obj",
"io_tests/obj/all_objects.mtl",
@@ -503,8 +517,8 @@ TEST_F(obj_exporter_regression_test, all_objects)
TEST_F(obj_exporter_regression_test, all_objects_mat_groups)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_smooth_groups = true;
_export.params.export_material_groups = true;
compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend",
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
index ef27a65fb4b..7d3b41ed527 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
@@ -17,8 +17,8 @@ struct OBJExportParamsDefault {
params.start_frame = 0;
params.end_frame = 1;
- params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD;
- params.up_axis = OBJ_AXIS_Y_UP;
+ params.forward_axis = IO_AXIS_NEGATIVE_Z;
+ params.up_axis = IO_AXIS_Y;
params.scaling_factor = 1.f;
params.apply_modifiers = true;
@@ -26,6 +26,7 @@ struct OBJExportParamsDefault {
params.export_selected_objects = false;
params.export_uv = true;
params.export_normals = true;
+ params.export_colors = false;
params.export_materials = true;
params.path_mode = PATH_REFERENCE_AUTO;
params.export_triangulated_mesh = false;
diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
index d7f4ce3d773..b67adbc9753 100644
--- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
@@ -39,6 +39,7 @@ struct Expectation {
float3 vert_first, vert_last;
float3 normal_first;
float2 uv_first;
+ float4 color_first = {-1, -1, -1, -1};
};
class obj_importer_test : public BlendfileLoadingBaseTest {
@@ -55,8 +56,8 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
OBJImportParams params;
params.clamp_size = 0;
- params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD;
- params.up_axis = OBJ_AXIS_Y_UP;
+ params.forward_axis = IO_AXIS_NEGATIVE_Z;
+ params.up_axis = IO_AXIS_Y;
std::string obj_path = blender::tests::flags_test_asset_dir() + "/io_tests/obj/" + path;
strncpy(params.filepath, obj_path.c_str(), FILE_MAX - 1);
@@ -98,6 +99,15 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
float2 uv_first = mloopuv ? float2(mloopuv->uv) : float2(0, 0);
EXPECT_V2_NEAR(uv_first, exp.uv_first, 0.0001f);
+ if (exp.color_first.x >= 0) {
+ const float4 *colors = (const float4 *)(CustomData_get_layer(&mesh->vdata,
+ CD_PROP_COLOR));
+ EXPECT_TRUE(colors != nullptr);
+ EXPECT_V4_NEAR(colors[0], exp.color_first, 0.0001f);
+ }
+ else {
+ EXPECT_FALSE(CustomData_has_layer(&mesh->vdata, CD_PROP_COLOR));
+ }
}
if (object->type == OB_CURVES_LEGACY) {
Curve *curve = static_cast<Curve *>(DEG_get_evaluated_object(depsgraph, object)->data);
@@ -111,7 +121,7 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
int endpoint = (nurb->flagu & CU_NURB_ENDPOINT) ? 1 : 0;
EXPECT_EQ(nurb->orderu, exp.mesh_totpoly_or_curve_order);
EXPECT_EQ(endpoint, exp.mesh_totedge_or_curve_endp);
- // Cyclic flag is not set by the importer yet
+ /* Cyclic flag is not set by the importer yet. */
// int cyclic = (nurb->flagu & CU_NURB_CYCLIC) ? 1 : 0;
// EXPECT_EQ(cyclic, exp.mesh_totloop_or_curve_cyclic);
}
@@ -133,7 +143,7 @@ TEST_F(obj_importer_test, import_cube)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object",
+ {"OBcube",
OB_MESH,
8,
12,
@@ -168,7 +178,7 @@ TEST_F(obj_importer_test, import_nurbs)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object",
+ {"OBnurbs",
OB_CURVES_LEGACY,
12,
0,
@@ -184,7 +194,7 @@ TEST_F(obj_importer_test, import_nurbs_curves)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object", OB_CURVES_LEGACY, 4, 0, 4, 0, float3(2, -2, 0), float3(-2, -2, 0)},
+ {"OBnurbs_curves", OB_CURVES_LEGACY, 4, 0, 4, 0, float3(2, -2, 0), float3(-2, -2, 0)},
{"OBNurbsCurveDiffWeights",
OB_CURVES_LEGACY,
4,
@@ -211,7 +221,7 @@ TEST_F(obj_importer_test, import_nurbs_cyclic)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object",
+ {"OBnurbs_cyclic",
OB_CURVES_LEGACY,
31,
0,
@@ -262,7 +272,7 @@ TEST_F(obj_importer_test, import_materials)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object", OB_MESH, 8, 12, 6, 24, float3(-1, -1, 1), float3(1, -1, -1)},
+ {"OBmaterials", OB_MESH, 8, 12, 6, 24, float3(-1, -1, 1), float3(1, -1, -1)},
};
import_and_check("materials.obj", expect, std::size(expect), 4);
}
@@ -434,7 +444,17 @@ TEST_F(obj_importer_test, import_all_objects)
float3(16, 1, -1),
float3(14, 1, 1),
float3(0, 0, 1)},
- {"OBVColCube", OB_MESH, 8, 13, 7, 26, float3(13, 1, -1), float3(11, 1, 1), float3(0, 0, 1)},
+ {"OBVColCube",
+ OB_MESH,
+ 8,
+ 13,
+ 7,
+ 26,
+ float3(13, 1, -1),
+ float3(11, 1, 1),
+ float3(0, 0, 1),
+ float2(0, 0),
+ float4(0.0f, 0.002125f, 1.0f, 1.0f)},
{"OBUVCube",
OB_MESH,
8,
@@ -490,4 +510,103 @@ TEST_F(obj_importer_test, import_all_objects)
import_and_check("all_objects.obj", expect, std::size(expect), 7);
}
+TEST_F(obj_importer_test, import_cubes_vertex_colors)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBCubeVertexByte",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1.0f, 1.0f, -1.0f),
+ float3(-1.0f, -1.0f, 1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.846873f, 0.027321f, 0.982123f, 1.0f)},
+ {"OBCubeVertexFloat",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(3.392028f, 1.0f, -1.0f),
+ float3(1.392028f, -1.0f, 1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(49.99467f, 0.027321f, 0.982123f, 1.0f)},
+ {"OBCubeCornerByte",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1.0f, 1.0f, -3.812445f),
+ float3(-1.0f, -1.0f, -1.812445f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.89627f, 0.036889f, 0.47932f, 1.0f)},
+ {"OBCubeCornerFloat",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(3.481967f, 1.0f, -3.812445f),
+ float3(1.481967f, -1.0f, -1.812445f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(1.564582f, 0.039217f, 0.664309f, 1.0f)},
+ {"OBCubeMultiColorAttribs",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(-4.725068f, -1.0f, 1.0f),
+ float3(-2.725068f, 1.0f, -1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.270498f, 0.47932f, 0.262251f, 1.0f)},
+ {"OBCubeNoColors",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(-4.550208f, -1.0f, -1.918042f),
+ float3(-2.550208f, 1.0f, -3.918042f)},
+ };
+ import_and_check("cubes_vertex_colors.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_cubes_vertex_colors_mrgb)
+{
+ Expectation expect[] = {{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBCubeXYZRGB",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1, 1, -1),
+ float3(-1, -1, 1),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.6038f, 0.3185f, 0.1329f, 1.0f)},
+ {"OBCubeMRGB",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(4, 1, -1),
+ float3(2, -1, 1),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.8714f, 0.6308f, 0.5271f, 1.0f)}};
+ import_and_check("cubes_vertex_colors_mrgb.obj", expect, std::size(expect), 0);
+}
+
} // namespace blender::io::obj
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 1989118bef9..451c921c4ef 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -472,7 +472,7 @@ typedef struct Library {
ushort tag;
char _pad_0[6];
- /* Temp data needed by read/write code, and liboverride recursive resync. */
+ /** Temp data needed by read/write code, and lib-override recursive re-synchronized. */
int temp_index;
/** See BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION, needed for do_versions. */
short versionfile, subversionfile;
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index c1dfab8a041..e2b58cefef6 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -771,7 +771,7 @@ typedef enum eNlaStrip_Blend_Mode {
NLASTRIP_MODE_COMBINE,
} eNlaStrip_Blend_Mode;
-/** NLA Strip Extrpolation Mode. */
+/** NLA Strip Extrapolation Mode. */
typedef enum eNlaStrip_Extrapolate_Mode {
/* extend before first frame if no previous strips in track,
* and always hold+extend last frame */
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 24e77ecf87f..d13496b21f7 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -97,7 +97,7 @@ typedef struct BrushGpencilSettings {
/** Simplify adaptive factor */
float simplify_f;
- /** Mix colorfactor */
+ /** Mix color-factor. */
float vertex_factor;
int vertex_mode;
diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h
index e79a53704c9..8ac899df701 100644
--- a/source/blender/makesdna/DNA_cloth_types.h
+++ b/source/blender/makesdna/DNA_cloth_types.h
@@ -20,8 +20,8 @@ extern "C" {
* Mass-Spring Model to Describe Rigid Cloth Behavior by Xavier Provot.
*
* I've tried to keep similar, if not exact names for the variables as
- * are presented in the paper. Where I've changed the concept slightly,
- * as in stepsPerFrame compared to the time step in the paper, I've used
+ * are presented in the paper. Where I've changed the concept slightly,
+ * as in `stepsPerFrame` compared to the time step in the paper, I've used
* variables with different names to minimize confusion.
*/
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 6557f35970d..ad046cbe79a 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -247,10 +247,9 @@ typedef struct bArmatureConstraint {
typedef struct bTrackToConstraint {
struct Object *tar;
/**
- * I'll be using reserved1 and reserved2 as Track and Up flags,
+ * NOTE(@theeth): I'll be using reserved1 and reserved2 as Track and Up flags,
* not sure if that's what they were intended for anyway.
* Not sure either if it would create backward incompatibility if I were to rename them.
- * - theeth
*/
int reserved1;
int reserved2;
diff --git a/source/blender/makesdna/DNA_curves_types.h b/source/blender/makesdna/DNA_curves_types.h
index 9690c342fdd..ed909c283c4 100644
--- a/source/blender/makesdna/DNA_curves_types.h
+++ b/source/blender/makesdna/DNA_curves_types.h
@@ -157,6 +157,13 @@ typedef struct Curves {
*/
struct Object *surface;
+ /**
+ * The name of the attribute on the surface #Mesh used to give meaning to the UV attachment
+ * coordinates stored on each curve. Expected to be a 2D vector attribute on the face corner
+ * domain.
+ */
+ char *surface_uv_map;
+
/* Draw Cache. */
void *batch_cache;
} Curves;
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index c20fb180fcd..56963bae3e1 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -1098,7 +1098,7 @@ typedef struct LineartGpencilModifierData {
struct LineartCache *cache;
/* Keep a pointer to the render buffer so we can call destroy from ModifierData. */
- struct LineartRenderBuffer *render_buffer_ptr;
+ struct LineartData *la_data_ptr;
} LineartGpencilModifierData;
diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h
index 70ee7c99d01..ef35b72d2ab 100644
--- a/source/blender/makesdna/DNA_ipo_types.h
+++ b/source/blender/makesdna/DNA_ipo_types.h
@@ -338,7 +338,7 @@ typedef struct Ipo {
#define CAM_STA 2
#define CAM_END 3
-/* yafray aperture & focal distance curves */
+/* YAFRAY aperture & focal distance curves. */
#define CAM_YF_APERT 4
#define CAM_YF_FDIST 5
diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h
index 9202d7c2d51..f1bf0580b94 100644
--- a/source/blender/makesdna/DNA_light_types.h
+++ b/source/blender/makesdna/DNA_light_types.h
@@ -120,7 +120,7 @@ typedef struct Light {
/* #define LA_NO_DIFF (1 << 11) */ /* not used anywhere */
/* #define LA_NO_SPEC (1 << 12) */ /* not used anywhere */
/* #define LA_SHAD_RAY (1 << 13) */ /* not used anywhere - cleaned */
-/* yafray: light shadowbuffer flag, softlight */
+/* YAFRAY: light shadow-buffer flag, soft-light. */
/* Since it is used with LOCAL light, can't use LA_SHAD */
/* #define LA_YF_SOFT (1 << 14) */ /* not used anymore */
/* #define LA_LAYER_SHADOW (1 << 15) */ /* not used anymore */
diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h
index df496269644..444a0e6f247 100644
--- a/source/blender/makesdna/DNA_lineart_types.h
+++ b/source/blender/makesdna/DNA_lineart_types.h
@@ -14,7 +14,7 @@
* Edge flags and usage flags are used by with scene/object/gpencil modifier bits, and those values
* needs to stay consistent throughout. */
-/* These flags are used for 1 time calculation, not stroke selection afterwards. */
+/** These flags are used for 1 time calculation, not stroke selection afterwards. */
typedef enum eLineartMainFlags {
LRT_INTERSECTION_AS_CONTOUR = (1 << 0),
LRT_EVERYTHING_AS_CONTOUR = (1 << 1),
@@ -48,9 +48,11 @@ typedef enum eLineartEdgeFlag {
LRT_EDGE_FLAG_INTERSECTION = (1 << 4),
LRT_EDGE_FLAG_LOOSE = (1 << 5),
/* 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. */
+ /**
+ * It's a legacy limit of 8 bits for feature lines that come from original mesh edges. It should
+ * not be needed in current object loading scheme, but might still be relevant if we are to
+ * implement edit-mesh loading, so don't exceed 8 bits just yet.
+ */
LRT_EDGE_FLAG_CHAIN_PICKED = (1 << 8),
LRT_EDGE_FLAG_CLIPPED = (1 << 9),
/** Limited to 16 bits for the entire thing. */
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 4a57f60be26..2eca84959b8 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -32,6 +32,7 @@ struct MVert;
struct Material;
struct Mesh;
struct SubdivCCG;
+struct SubsurfRuntimeData;
#
#
@@ -83,7 +84,7 @@ typedef struct Mesh_Runtime {
/**
* Data used to efficiently draw the mesh in the viewport, especially useful when
- * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.c`.
+ * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.cc`.
*/
void *batch_cache;
@@ -123,26 +124,18 @@ typedef struct Mesh_Runtime {
/**
* Settings for lazily evaluating the subdivision on the CPU if needed. These are
- * set in the modifier when GPU subdivision can be performed.
+ * set in the modifier when GPU subdivision can be performed, and owned by the by
+ * the modifier in the object.
*/
- SessionUUID subsurf_session_uuid;
- char subsurf_resolution;
- char subsurf_do_loop_normals;
- char subsurf_apply_render;
- char subsurf_use_optimal_display;
-
- /* Cached from the draw code for stats display. */
- int subsurf_totvert;
- int subsurf_totedge;
- int subsurf_totpoly;
- int subsurf_totloop;
- char _pad2[2];
+ struct SubsurfRuntimeData *subsurf_runtime_data;
+ void *_pad1;
/**
* Caches for lazily computed vertex and polygon normals. These are stored here rather than in
* #CustomData because they can be calculated on a const mesh, and adding custom data layers on a
* const mesh is not thread-safe.
*/
+ char _pad2[6];
char vert_normals_dirty;
char poly_normals_dirty;
float (*vert_normals)[3];
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 6e3ce7e98a8..f148116eba8 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -178,13 +178,6 @@ typedef enum {
SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS = 1,
} eSubsurfBoundarySmooth;
-typedef struct SubsurfRuntimeData {
- /* Cached subdivision surface descriptor, with topology and settings. */
- struct Subdiv *subdiv;
- char set_by_draw_code;
- char _pad[7];
-} SubsurfRuntimeData;
-
typedef struct SubsurfModifierData {
ModifierData modifier;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 9dc2971b322..25c8a1f1514 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1915,12 +1915,6 @@ typedef enum GeometryNodeBooleanOperation {
GEO_NODE_BOOLEAN_DIFFERENCE = 2,
} GeometryNodeBooleanOperation;
-typedef enum GeometryNodeSplineType {
- GEO_NODE_SPLINE_TYPE_BEZIER = 0,
- GEO_NODE_SPLINE_TYPE_NURBS = 1,
- GEO_NODE_SPLINE_TYPE_POLY = 2,
-} GeometryNodeSplineType;
-
typedef enum GeometryNodeCurvePrimitiveCircleMode {
GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS = 0,
GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS = 1
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index f257833efe8..698fbe8ee8f 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -374,7 +374,7 @@ typedef struct Object {
/** Dupliface scale. */
float instance_faces_scale;
- /** Custom index, for renderpasses. */
+ /** Custom index, for render-passes. */
short index;
/** Current deformation group, NOTE: index starts at 1. */
unsigned short actdef DNA_DEPRECATED;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 1be27e0354c..1c62a550e60 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -991,6 +991,9 @@ typedef struct Sculpt {
// float pivot[3]; XXX not used?
int flags;
+ /* Transform tool. */
+ int transform_mode;
+
int automasking_flags;
/* Control tablet input */
@@ -1011,6 +1014,8 @@ typedef struct Sculpt {
float constant_detail;
float detail_percent;
+ char _pad[4];
+
struct Object *gravity_object;
} Sculpt;
@@ -1490,18 +1495,19 @@ typedef struct ToolSettings {
/* Transform */
char transform_pivot_point;
char transform_flag;
- /** Snap elements (per spacetype). */
+ /** Snap elements (per spacetype), #eSnapMode. */
char snap_mode;
char snap_node_mode;
char snap_uv_mode;
- /** Generic flags (per spacetype). */
+ /** Generic flags (per spacetype), #eSnapFlag. */
char snap_flag;
char snap_flag_node;
char snap_flag_seq;
char snap_uv_flag;
- /** Default snap source. */
+ /** Default snap source, #eSnapSourceSelect. */
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source_point`, because target is incorrect. */
char snap_target;
- /** Snap mask for transform modes. */
+ /** Snap mask for transform modes, #eSnapTransformMode. */
char snap_transform_mode_flag;
char proportional_edit, prop_mode;
@@ -2075,30 +2081,64 @@ enum {
};
/** #ToolSettings.snap_flag */
-#define SCE_SNAP (1 << 0)
-#define SCE_SNAP_ROTATE (1 << 1)
-#define SCE_SNAP_PEEL_OBJECT (1 << 2)
-#define SCE_SNAP_PROJECT (1 << 3)
-#define SCE_SNAP_NO_SELF (1 << 4)
-#define SCE_SNAP_ABS_GRID (1 << 5)
-#define SCE_SNAP_BACKFACE_CULLING (1 << 6)
-
-/** #ToolSettings.snap_target */
-#define SCE_SNAP_TARGET_CLOSEST 0
-#define SCE_SNAP_TARGET_CENTER 1
-#define SCE_SNAP_TARGET_MEDIAN 2
-#define SCE_SNAP_TARGET_ACTIVE 3
+typedef enum eSnapFlag {
+ SCE_SNAP = (1 << 0),
+ SCE_SNAP_ROTATE = (1 << 1),
+ SCE_SNAP_PEEL_OBJECT = (1 << 2),
+ SCE_SNAP_PROJECT = (1 << 3),
+ SCE_SNAP_NO_SELF = (1 << 4),
+ SCE_SNAP_ABS_GRID = (1 << 5),
+ SCE_SNAP_BACKFACE_CULLING = (1 << 6),
+} eSnapFlag;
+/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */
+/* TODO: move this macro to a more general place. */
+#ifdef ENUM_OPERATORS
+ENUM_OPERATORS(eSnapFlag, SCE_SNAP_BACKFACE_CULLING)
+#endif
+
+/** #ToolSettings.snap_target and #TransSnap.source_select */
+typedef enum eSnapSourceSelect {
+ SCE_SNAP_SOURCE_CLOSEST = 0,
+ SCE_SNAP_SOURCE_CENTER = 1,
+ SCE_SNAP_SOURCE_MEDIAN = 2,
+ SCE_SNAP_SOURCE_ACTIVE = 3,
+} eSnapSourceSelect;
+
+/** #TransSnap.target_select and #ToolSettings.snap_flag (SCE_SNAP_NO_SELF) */
+typedef enum eSnapTargetSelect {
+ SCE_SNAP_TARGET_ALL = 0,
+ SCE_SNAP_TARGET_NOT_SELECTED = 1,
+ SCE_SNAP_TARGET_NOT_ACTIVE = 2,
+ SCE_SNAP_TARGET_NOT_EDITED = 3,
+ SCE_SNAP_TARGET_ONLY_SELECTABLE = 4,
+} eSnapTargetSelect;
/** #ToolSettings.snap_mode */
-#define SCE_SNAP_MODE_VERTEX (1 << 0)
-#define SCE_SNAP_MODE_EDGE (1 << 1)
-#define SCE_SNAP_MODE_FACE (1 << 2)
-#define SCE_SNAP_MODE_VOLUME (1 << 3)
-#define SCE_SNAP_MODE_EDGE_MIDPOINT (1 << 4)
-#define SCE_SNAP_MODE_EDGE_PERPENDICULAR (1 << 5)
-#define SCE_SNAP_MODE_GEOM \
- (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | \
- SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT)
+typedef enum eSnapMode {
+ SCE_SNAP_MODE_NONE = 0,
+ SCE_SNAP_MODE_VERTEX = (1 << 0),
+ SCE_SNAP_MODE_EDGE = (1 << 1),
+ SCE_SNAP_MODE_FACE = (1 << 2), /* TODO(@gfxcoder): Rename to `SCE_SNAP_MODE_FACE_RAYCAST`
+ when other face snapping methods are added. */
+ SCE_SNAP_MODE_VOLUME = (1 << 3),
+ SCE_SNAP_MODE_EDGE_MIDPOINT = (1 << 4),
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR = (1 << 5),
+ SCE_SNAP_MODE_GEOM = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT),
+
+ /** #ToolSettings.snap_node_mode */
+ SCE_SNAP_MODE_NODE_X = (1 << 0),
+ SCE_SNAP_MODE_NODE_Y = (1 << 1),
+
+ /* #ToolSettings.snap_mode and #ToolSettings.snap_node_mode and #ToolSettings.snap_uv_mode */
+ SCE_SNAP_MODE_INCREMENT = (1 << 6),
+ SCE_SNAP_MODE_GRID = (1 << 7),
+} eSnapMode;
+/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */
+/* TODO: move this macro to a more general place. */
+#ifdef ENUM_OPERATORS
+ENUM_OPERATORS(eSnapMode, SCE_SNAP_MODE_GRID)
+#endif
/** #SequencerToolSettings.snap_mode */
#define SEQ_SNAP_TO_STRIPS (1 << 0)
@@ -2110,22 +2150,12 @@ enum {
#define SEQ_SNAP_IGNORE_SOUND (1 << 1)
#define SEQ_SNAP_CURRENT_FRAME_TO_STRIPS (1 << 2)
-/** #ToolSettings.snap_node_mode */
-#define SCE_SNAP_MODE_NODE_X (1 << 0)
-#define SCE_SNAP_MODE_NODE_Y (1 << 1)
-
-/**
- * #ToolSettings.snap_mode and #ToolSettings.snap_node_mode
- */
-#define SCE_SNAP_MODE_INCREMENT (1 << 6)
-#define SCE_SNAP_MODE_GRID (1 << 7)
-
/** #ToolSettings.snap_transform_mode_flag */
-enum {
+typedef enum eSnapTransformMode {
SCE_SNAP_TRANSFORM_MODE_TRANSLATE = (1 << 0),
SCE_SNAP_TRANSFORM_MODE_ROTATE = (1 << 1),
SCE_SNAP_TRANSFORM_MODE_SCALE = (1 << 2),
-};
+} eSnapTransformMode;
/** #ToolSettings.selectmode */
#define SCE_SELECT_VERTEX (1 << 0) /* for mesh */
@@ -2279,6 +2309,12 @@ typedef enum eSculptFlags {
SCULPT_HIDE_FACE_SETS = (1 << 17),
} eSculptFlags;
+/* Sculpt.transform_mode */
+typedef enum eSculptTransformMode {
+ SCULPT_TRANSFORM_MODE_ALL_VERTICES = 0,
+ SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC = 1,
+} eSculptTrasnformMode;
+
/** PaintModeSettings.mode */
typedef enum ePaintCanvasSource {
/** Paint on the active node of the active material slot. */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 59bd385c207..be073ef2c15 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -2014,6 +2014,7 @@ typedef enum eSpreadsheetColumnValueType {
SPREADSHEET_VALUE_TYPE_INSTANCES = 6,
SPREADSHEET_VALUE_TYPE_STRING = 7,
SPREADSHEET_VALUE_TYPE_BYTE_COLOR = 8,
+ SPREADSHEET_VALUE_TYPE_INT8 = 9,
} eSpreadsheetColumnValueType;
/**
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 275a89ec680..d00826208be 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -146,6 +146,7 @@ typedef struct ThemeUI {
uiWidgetColors wcol_num, wcol_numslider, wcol_tab;
uiWidgetColors wcol_menu, wcol_pulldown, wcol_menu_back, wcol_menu_item, wcol_tooltip;
uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item, wcol_pie_menu;
+ uiWidgetColors wcol_view_item;
uiWidgetStateColors wcol_state;
@@ -314,7 +315,7 @@ typedef struct ThemeSpace {
char _pad5[3];
float dash_alpha;
- /* syntax for textwindow and nodes */
+ /* Syntax for text-window and nodes. */
unsigned char syntaxl[4], syntaxs[4]; /* in nodespace used for backdrop matte */
unsigned char syntaxb[4], syntaxn[4]; /* in nodespace used for color input */
unsigned char syntaxv[4], syntaxc[4]; /* in nodespace used for converter group */
@@ -858,7 +859,7 @@ typedef struct UserDef {
float glalphaclip;
- /** #eAutokey_Mode, autokeying mode. */
+ /** #eAutokey_Mode, auto-keying mode. */
short autokey_mode;
/** Flags for autokeying. */
short autokey_flag;
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index cfd0c986df9..f7aaa1186db 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -463,14 +463,19 @@ typedef struct wmKeyMap {
/** #wmKeyMap.flag */
enum {
- KEYMAP_MODAL = (1 << 0), /* modal map, not using operatornames */
- KEYMAP_USER = (1 << 1), /* user keymap */
+ /** Modal map, not using operator-names. */
+ KEYMAP_MODAL = (1 << 0),
+ /** User key-map. */
+ KEYMAP_USER = (1 << 1),
KEYMAP_EXPANDED = (1 << 2),
KEYMAP_CHILDREN_EXPANDED = (1 << 3),
- KEYMAP_DIFF = (1 << 4), /* diff keymap for user preferences */
- KEYMAP_USER_MODIFIED = (1 << 5), /* keymap has user modifications */
+ /** Diff key-map for user preferences. */
+ KEYMAP_DIFF = (1 << 4),
+ /** Key-map has user modifications. */
+ KEYMAP_USER_MODIFIED = (1 << 5),
KEYMAP_UPDATE = (1 << 6),
- KEYMAP_TOOL = (1 << 7), /* keymap for active tool system */
+ /** key-map for active tool system. */
+ KEYMAP_TOOL = (1 << 7),
};
/**
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index e855395482e..67605201a9f 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -490,6 +490,18 @@ char *RNA_path_append(
char *RNA_path_back(const char *path);
#endif
+/**
+ * Search for the start of the 'rna array index' part of the given `rna_path`.
+ *
+ * Given the root RNA pointer and resolved RNA property, and the RNA path, return the first
+ * character in `rna_path` that is part of the array index for the given property. Return NULL if
+ * none can be found, e.g. because the property is not an RNA array.
+ *
+ * \param array_prop if not NULL, the PropertyRNA assumed to be the last one from the RNA path.
+ * Only used to ensure it is a valid array property.
+ */
+const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop);
+
/* RNA_path_resolve() variants only ensure that a valid pointer (and optionally property) exist. */
/**
diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h
index 37af598729b..61c5c1a6c72 100644
--- a/source/blender/makesrna/RNA_enum_items.h
+++ b/source/blender/makesrna/RNA_enum_items.h
@@ -21,7 +21,7 @@ DEF_ENUM(rna_enum_metaelem_type_items)
DEF_ENUM(rna_enum_proportional_falloff_items)
DEF_ENUM(rna_enum_proportional_falloff_curve_only_items)
-DEF_ENUM(rna_enum_snap_target_items)
+DEF_ENUM(rna_enum_snap_source_items)
DEF_ENUM(rna_enum_snap_element_items)
DEF_ENUM(rna_enum_snap_node_element_items)
DEF_ENUM(rna_enum_curve_fit_method_items)
@@ -147,6 +147,7 @@ DEF_ENUM(rna_enum_keymap_propvalue_items)
DEF_ENUM(rna_enum_operator_context_items)
DEF_ENUM(rna_enum_wm_report_items)
+DEF_ENUM(rna_enum_wm_job_type_items)
DEF_ENUM(rna_enum_property_type_items)
DEF_ENUM(rna_enum_property_subtype_items)
@@ -227,6 +228,8 @@ DEF_ENUM(rna_enum_transform_orientation_items)
DEF_ENUM(rna_enum_velocity_unit_items)
+DEF_ENUM(rna_enum_curves_types)
+
/* Not available to RNA pre-processing (`makesrna`).
* Defined in editors for example. */
#ifndef RNA_MAKESRNA
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index b5cf8abaac6..8d2ee0ab534 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -33,41 +33,41 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
{ID_AC, "ACTION", ICON_ACTION, "Action", ""},
{ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armature", ""},
{ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brush", ""},
- {ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""},
{ID_CF, "CACHEFILE", ICON_FILE, "Cache File", ""},
+ {ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""},
+ {ID_GR, "COLLECTION", ICON_OUTLINER_COLLECTION, "Collection", ""},
{ID_CU_LEGACY, "CURVE", ICON_CURVE_DATA, "Curve", ""},
+ {ID_CV, "CURVES", ICON_CURVES_DATA, "Curves", ""},
{ID_VF, "FONT", ICON_FONT_DATA, "Font", ""},
{ID_GD, "GREASEPENCIL", ICON_GREASEPENCIL, "Grease Pencil", ""},
- {ID_GR, "COLLECTION", ICON_OUTLINER_COLLECTION, "Collection", ""},
{ID_IM, "IMAGE", ICON_IMAGE_DATA, "Image", ""},
{ID_KE, "KEY", ICON_SHAPEKEY_DATA, "Key", ""},
- {ID_LA, "LIGHT", ICON_LIGHT_DATA, "Light", ""},
+ {ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""},
{ID_LI, "LIBRARY", ICON_LIBRARY_DATA_DIRECT, "Library", ""},
+ {ID_LA, "LIGHT", ICON_LIGHT_DATA, "Light", ""},
+ {ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""},
{ID_LS, "LINESTYLE", ICON_LINE_DATA, "Line Style", ""},
- {ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""},
{ID_MSK, "MASK", ICON_MOD_MASK, "Mask", ""},
{ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Material", ""},
- {ID_MB, "META", ICON_META_DATA, "Metaball", ""},
{ID_ME, "MESH", ICON_MESH_DATA, "Mesh", ""},
+ {ID_MB, "META", ICON_META_DATA, "Metaball", ""},
{ID_MC, "MOVIECLIP", ICON_TRACKER, "Movie Clip", ""},
{ID_NT, "NODETREE", ICON_NODETREE, "Node Tree", ""},
{ID_OB, "OBJECT", ICON_OBJECT_DATA, "Object", ""},
{ID_PC, "PAINTCURVE", ICON_CURVE_BEZCURVE, "Paint Curve", ""},
{ID_PAL, "PALETTE", ICON_COLOR, "Palette", ""},
{ID_PA, "PARTICLE", ICON_PARTICLE_DATA, "Particle", ""},
- {ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""},
+ {ID_PT, "POINTCLOUD", ICON_POINTCLOUD_DATA, "Point Cloud", ""},
{ID_SCE, "SCENE", ICON_SCENE_DATA, "Scene", ""},
{ID_SIM, "SIMULATION", ICON_PHYSICS, "Simulation", ""}, /* TODO: Use correct icon. */
{ID_SO, "SOUND", ICON_SOUND, "Sound", ""},
{ID_SPK, "SPEAKER", ICON_SPEAKER, "Speaker", ""},
{ID_TXT, "TEXT", ICON_TEXT, "Text", ""},
{ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Texture", ""},
- {ID_CV, "CURVES", ICON_CURVES_DATA, "Hair Curves", ""},
- {ID_PT, "POINTCLOUD", ICON_POINTCLOUD_DATA, "Point Cloud", ""},
{ID_VO, "VOLUME", ICON_VOLUME_DATA, "Volume", ""},
{ID_WM, "WINDOWMANAGER", ICON_WINDOW, "Window Manager", ""},
- {ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""},
{ID_WS, "WORKSPACE", ICON_WORKSPACE, "Workspace", ""},
+ {ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 75579107465..0bc35d86490 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -5482,6 +5482,52 @@ static UNUSED_FUNCTION_WITH_RETURN_TYPE(char *, RNA_path_back)(const char *path)
return result;
}
+const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop)
+{
+ if (array_prop != NULL) {
+ if (!ELEM(array_prop->type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ BLI_assert(array_prop->arraydimension == 0);
+ return NULL;
+ }
+ if (array_prop->arraydimension == 0) {
+ return NULL;
+ }
+ }
+
+ /* Valid 'array part' of a rna path can only have '[', ']' and digit characters.
+ * It may have more than one of those (e.g. `[12][1]`) in case of multi-dimensional arrays. */
+ off_t rna_path_len = (off_t)strlen(rna_path);
+ if (rna_path[rna_path_len] != ']') {
+ return NULL;
+ }
+ const char *last_valid_index_token_start = NULL;
+ for (rna_path_len--; rna_path_len >= 0; rna_path_len--) {
+ switch (rna_path[rna_path_len]) {
+ case '[':
+ if (rna_path_len <= 0 || rna_path[rna_path_len - 1] != ']') {
+ return &rna_path[rna_path_len];
+ }
+ last_valid_index_token_start = &rna_path[rna_path_len];
+ rna_path_len--;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+ default:
+ return last_valid_index_token_start;
+ }
+ }
+ return last_valid_index_token_start;
+}
+
/* generic path search func
* if its needed this could also reference the IDProperty direct */
typedef struct IDP_Chain {
@@ -6062,7 +6108,7 @@ char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
}
if ((index == -1) || (RNA_property_array_check(prop) == false)) {
- ret = BLI_sprintfN("%s", data_path);
+ ret = BLI_strdup(data_path);
}
else {
ret = BLI_sprintfN("%s[%d]", data_path, index);
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index 5af714660ed..5e17f22ecf5 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -163,13 +163,14 @@ static StructRNA *rna_Attribute_refine(PointerRNA *ptr)
static void rna_Attribute_name_set(PointerRNA *ptr, const char *value)
{
- BKE_id_attribute_rename(ptr->owner_id, ptr->data, value, NULL);
+ const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
+ BKE_id_attribute_rename(ptr->owner_id, layer->name, value, NULL);
}
static int rna_Attribute_name_editable(PointerRNA *ptr, const char **r_info)
{
CustomDataLayer *layer = ptr->data;
- if (BKE_id_attribute_required(ptr->owner_id, layer)) {
+ if (BKE_id_attribute_required(ptr->owner_id, layer->name)) {
*r_info = N_("Cannot modify name of required geometry attribute");
return false;
}
@@ -358,8 +359,8 @@ static PointerRNA rna_AttributeGroup_new(
static void rna_AttributeGroup_remove(ID *id, ReportList *reports, PointerRNA *attribute_ptr)
{
- CustomDataLayer *layer = (CustomDataLayer *)attribute_ptr->data;
- BKE_id_attribute_remove(id, layer, reports);
+ const CustomDataLayer *layer = (const CustomDataLayer *)attribute_ptr->data;
+ BKE_id_attribute_remove(id, layer->name, reports);
RNA_POINTER_INVALIDATE(attribute_ptr);
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
@@ -538,7 +539,7 @@ static void rna_AttributeGroup_active_color_set(PointerRNA *ptr,
static int rna_AttributeGroup_active_color_index_get(PointerRNA *ptr)
{
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(ptr->owner_id);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(ptr->owner_id);
return BKE_id_attribute_to_index(
ptr->owner_id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 46b009191ca..423cb084f27 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -243,15 +243,17 @@ const EnumPropertyItem rna_enum_brush_gpencil_weight_types_items[] = {
{0, NULL, 0, NULL, NULL},
};
+/* clang-format off */
const EnumPropertyItem rna_enum_brush_curves_sculpt_tool_items[] = {
- {CURVES_SCULPT_TOOL_COMB, "COMB", ICON_NONE, "Comb Curves", ""},
- {CURVES_SCULPT_TOOL_DELETE, "DELETE", ICON_NONE, "Delete Curves", ""},
- {CURVES_SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_NONE, "Curves Snake Hook", ""},
- {CURVES_SCULPT_TOOL_ADD, "ADD", ICON_NONE, "Add Curves", ""},
- {CURVES_SCULPT_TOOL_GROW_SHRINK, "GROW_SHRINK", ICON_NONE, "Grow / Shrink Curves", ""},
- {CURVES_SCULPT_TOOL_SELECTION_PAINT, "SELECTION_PAINT", ICON_NONE, "Paint Selection", ""},
+ {CURVES_SCULPT_TOOL_COMB, "COMB", ICON_BRUSH_CURVES_COMB, "Comb Curves", ""},
+ {CURVES_SCULPT_TOOL_DELETE, "DELETE", ICON_BRUSH_CURVES_DELETE, "Delete Curves", ""},
+ {CURVES_SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_CURVES_SNAKE_HOOK, "Curves Snake Hook", ""},
+ {CURVES_SCULPT_TOOL_ADD, "ADD", ICON_BRUSH_CURVES_ADD, "Add Curves", ""},
+ {CURVES_SCULPT_TOOL_GROW_SHRINK, "GROW_SHRINK", ICON_BRUSH_CURVES_GROW_SHRINK, "Grow / Shrink Curves", ""},
+ {CURVES_SCULPT_TOOL_SELECTION_PAINT, "SELECTION_PAINT", ICON_BRUSH_PAINT_SELECT, "Paint Selection", ""},
{0, NULL, 0, NULL, NULL},
};
+/* clang-format om */
#ifndef RNA_RUNTIME
static EnumPropertyItem rna_enum_gpencil_brush_eraser_modes_items[] = {
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index dcf0647392e..9628c6b2d65 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -125,6 +125,24 @@ static char *rna_Camera_background_image_path(const PointerRNA *ptr)
return NULL;
}
+char *rna_CameraBackgroundImage_image_or_movieclip_user_path(const PointerRNA *ptr)
+{
+ const char *user = ptr->data;
+ Camera *camera = (Camera *)ptr->owner_id;
+
+ int bgpic_index = BLI_findindex(&camera->bg_images, user - offsetof(CameraBGImage, iuser));
+ if (bgpic_index >= 0) {
+ return BLI_sprintfN("background_images[%d].image_user", bgpic_index);
+ }
+
+ bgpic_index = BLI_findindex(&camera->bg_images, user - offsetof(CameraBGImage, cuser));
+ if (bgpic_index >= 0) {
+ return BLI_sprintfN("background_images[%d].clip_user", bgpic_index);
+ }
+
+ return NULL;
+}
+
static bool rna_Camera_background_images_override_apply(Main *bmain,
PointerRNA *ptr_dst,
PointerRNA *ptr_src,
@@ -272,6 +290,7 @@ static void rna_def_camera_background_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "ImageUser");
RNA_def_property_pointer_sdna(prop, NULL, "iuser");
RNA_def_property_ui_text(
prop,
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 24f226eb6e6..1420ef36493 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -598,22 +598,17 @@ static const EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSE
bool *UNUSED(r_free))
{
bConstraint *con = (bConstraint *)ptr->data;
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar && ct->tar->type == OB_ARMATURE) {
break;
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 1);
- }
+ BKE_constraint_targets_flush(con, &targets, 1);
if (ct) {
return target_space_pchan_items;
diff --git a/source/blender/makesrna/intern/rna_curves.c b/source/blender/makesrna/intern/rna_curves.c
index caefd2f45ff..bc3e5203ed0 100644
--- a/source/blender/makesrna/intern/rna_curves.c
+++ b/source/blender/makesrna/intern/rna_curves.c
@@ -18,6 +18,14 @@
#include "WM_types.h"
+const EnumPropertyItem rna_enum_curves_types[] = {
+ {CURVE_TYPE_CATMULL_ROM, "CATMULL_ROM", 0, "Catmull Rom", ""},
+ {CURVE_TYPE_POLY, "POLY", 0, "Poly", ""},
+ {CURVE_TYPE_BEZIER, "BEZIER", 0, "Bezier", ""},
+ {CURVE_TYPE_NURBS, "NURBS", 0, "NURBS", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "BLI_math_vector.h"
@@ -292,6 +300,14 @@ 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);
+ prop = RNA_def_property(srna, "surface_uv_map", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "surface_uv_map");
+ RNA_def_property_ui_text(prop,
+ "Surface UV Map",
+ "The name of the attribute on the surface mesh used to define the "
+ "attachment of each curve");
+ RNA_def_property_update(prop, 0, "rna_Curves_update_draw");
+
/* Symmetry. */
prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "symmetry", CURVES_SYMMETRY_X);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index c3d5819caa3..47bed955b54 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -1279,8 +1279,8 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna)
/* Sample */
prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "length");
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_range(prop, 0, 1.0, 0.01, 3);
+ RNA_def_property_range(prop, 0.005, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1.0, 0.05, 3);
RNA_def_property_ui_text(prop, "Length", "Length of each segment");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 440e99ad277..38706606997 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -226,12 +226,12 @@ static char *rna_ImageUser_path(const PointerRNA *ptr)
switch (GS(ptr->owner_id->name)) {
case ID_OB:
- case ID_TE: {
+ case ID_TE:
return BLI_strdup("image_user");
- }
- case ID_NT: {
+ case ID_NT:
return rna_Node_ImageUser_path(ptr);
- }
+ case ID_CA:
+ return rna_CameraBackgroundImage_image_or_movieclip_user_path(ptr);
default:
break;
}
@@ -301,6 +301,51 @@ static void rna_Image_file_format_set(PointerRNA *ptr, int value)
}
}
+static void rna_UDIMTile_size_get(PointerRNA *ptr, int *values)
+{
+ ImageTile *tile = (ImageTile *)ptr->data;
+ Image *image = (Image *)ptr->owner_id;
+
+ ImageUser image_user;
+ BKE_imageuser_default(&image_user);
+ image_user.tile = tile->tile_number;
+
+ void *lock;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &image_user, &lock);
+ if (ibuf) {
+ values[0] = ibuf->x;
+ values[1] = ibuf->y;
+ }
+ else {
+ values[0] = 0;
+ values[1] = 0;
+ }
+
+ BKE_image_release_ibuf(image, ibuf, lock);
+}
+
+static int rna_UDIMTile_channels_get(PointerRNA *ptr)
+{
+ ImageTile *tile = (ImageTile *)ptr->data;
+ Image *image = (Image *)ptr->owner_id;
+
+ ImageUser image_user;
+ BKE_imageuser_default(&image_user);
+ image_user.tile = tile->tile_number;
+
+ int channels = 0;
+
+ void *lock;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &image_user, &lock);
+ if (ibuf) {
+ channels = ibuf->channels;
+ }
+
+ BKE_image_release_ibuf(image, ibuf, lock);
+
+ return channels;
+}
+
static void rna_UDIMTile_label_get(PointerRNA *ptr, char *value)
{
ImageTile *tile = (ImageTile *)ptr->data;
@@ -823,6 +868,8 @@ static void rna_def_imageuser(BlenderRNA *brna)
"Parameters defining how an Image data-block is used by another data-block");
RNA_def_struct_path_func(srna, "rna_ImageUser_path");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_auto_refresh", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_ANIM_ALWAYS);
RNA_def_property_ui_text(prop, "Auto Refresh", "Always refresh image on frame changes");
@@ -884,6 +931,8 @@ static void rna_def_imageuser(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "tile");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Tile", "Tile in tiled image");
+
+ RNA_define_lib_overridable(false);
}
/* image.packed_files */
@@ -993,6 +1042,26 @@ static void rna_def_udim_tile(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Number", "Number of the position that this tile covers");
RNA_def_property_int_funcs(prop, NULL, "rna_UDIMTile_tile_number_set", NULL);
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
+
+ prop = RNA_def_int_vector(
+ srna,
+ "size",
+ 2,
+ NULL,
+ 0,
+ 0,
+ "Size",
+ "Width and height of the tile buffer in pixels, zero when image data can't be loaded",
+ 0,
+ 0);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ RNA_def_property_int_funcs(prop, "rna_UDIMTile_size_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "channels", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_UDIMTile_channels_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Channels", "Number of channels in the tile pixels buffer");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_udim_tiles(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 46bb0df5c11..be1e344d73f 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -164,7 +164,10 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
{
if (!BKE_image_scale(image, width, height)) {
BKE_reportf(reports, RPT_ERROR, "Image '%s' does not have any image data", image->id.name + 2);
+ return;
}
+ BKE_image_partial_update_mark_full_update(image);
+ WM_main_add_notifier(NC_IMAGE | NA_EDITED, image);
}
static int rna_Image_gl_load(
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 058c63f640a..9e743a4f205 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -404,6 +404,7 @@ bool rna_GPencil_datablocks_obdata_poll(struct PointerRNA *ptr, const struct Poi
char *rna_TextureSlot_path(const struct PointerRNA *ptr);
char *rna_Node_ImageUser_path(const struct PointerRNA *ptr);
+char *rna_CameraBackgroundImage_image_or_movieclip_user_path(const struct PointerRNA *ptr);
/* Set U.is_dirty and redraw. */
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 4f88959b5ba..a5b06cabade 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -532,7 +532,7 @@ struct StructRNA {
/* property to iterate over properties */
PropertyRNA *iteratorproperty;
- /* struct this is derivedfrom */
+ /** Struct this is derived from. */
struct StructRNA *base;
/* only use for nested structs, where both the parent and child access
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index 8c9c66bffcf..6ab9d3a46ad 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -339,6 +339,7 @@ static void rna_LayerCollection_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_IMAGE | ND_LAYER_CONTENT, NULL);
}
static bool rna_LayerCollection_has_objects(LayerCollection *lc)
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index e9b49dbe7d1..b5302eca1bf 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -118,6 +118,22 @@ static PointerRNA rna_MovieClip_metadata_get(MovieClip *clip)
return ptr;
}
+static char *rna_MovieClipUser_path(const PointerRNA *ptr)
+{
+ if (ptr->owner_id) {
+ /* MovieClipUser *mc_user = ptr->data; */
+
+ switch (GS(ptr->owner_id->name)) {
+ case ID_CA:
+ return rna_CameraBackgroundImage_image_or_movieclip_user_path(ptr);
+ default:
+ break;
+ }
+ }
+
+ return BLI_strdup("");
+}
+
#else
static void rna_def_movieclip_proxy(BlenderRNA *brna)
@@ -244,7 +260,7 @@ static void rna_def_movieclip_proxy(BlenderRNA *brna)
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClip_reload_update");
}
-static void rna_def_moviecliUser(BlenderRNA *brna)
+static void rna_def_movieclipUser(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
@@ -263,6 +279,9 @@ static void rna_def_moviecliUser(BlenderRNA *brna)
srna,
"Movie Clip User",
"Parameters defining how a MovieClip data-block is used by another data-block");
+ RNA_def_struct_path_func(srna, "rna_MovieClipUser_path");
+
+ RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "frame_current", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "framenr");
@@ -286,6 +305,8 @@ static void rna_def_moviecliUser(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Render Undistorted", "Render preview using undistorted proxy");
RNA_def_property_update(
prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClipUser_proxy_render_settings_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_movieClipScopes(BlenderRNA *brna)
@@ -435,7 +456,7 @@ void RNA_def_movieclip(BlenderRNA *brna)
{
rna_def_movieclip(brna);
rna_def_movieclip_proxy(brna);
- rna_def_moviecliUser(brna);
+ rna_def_movieclipUser(brna);
rna_def_movieClipScopes(brna);
}
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 841c250df4c..65a8d8bf24a 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -1610,26 +1610,31 @@ static char *rna_Node_path(const PointerRNA *ptr)
char *rna_Node_ImageUser_path(const PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node;
- char name_esc[sizeof(node->name) * 2];
+ if (!ELEM(ntree->type, NTREE_SHADER, NTREE_CUSTOM)) {
+ return NULL;
+ }
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_TEX_ENVIRONMENT) {
- NodeTexEnvironment *data = node->storage;
- if (&data->iuser != ptr->data) {
- continue;
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ switch (node->type) {
+ case SH_NODE_TEX_ENVIRONMENT: {
+ NodeTexEnvironment *data = node->storage;
+ if (&data->iuser != ptr->data) {
+ continue;
+ }
+ break;
}
- }
- else if (node->type == SH_NODE_TEX_IMAGE) {
- NodeTexImage *data = node->storage;
- if (&data->iuser != ptr->data) {
- continue;
+ case SH_NODE_TEX_IMAGE: {
+ NodeTexImage *data = node->storage;
+ if (&data->iuser != ptr->data) {
+ continue;
+ }
+ break;
}
- }
- else {
- continue;
+ default:
+ continue;
}
+ char name_esc[sizeof(node->name) * 2];
BLI_str_escape(name_esc, node->name, sizeof(name_esc));
return BLI_sprintfN("nodes[\"%s\"].image_user", name_esc);
}
@@ -9575,18 +9580,14 @@ static void def_geo_distribute_points_on_faces(StructRNA *srna)
static void def_geo_curve_spline_type(StructRNA *srna)
{
- static const EnumPropertyItem type_items[] = {
- {GEO_NODE_SPLINE_TYPE_BEZIER, "BEZIER", ICON_NONE, "Bezier", "Set the splines to Bezier"},
- {GEO_NODE_SPLINE_TYPE_NURBS, "NURBS", ICON_NONE, "NURBS", "Set the splines to NURBS"},
- {GEO_NODE_SPLINE_TYPE_POLY, "POLY", ICON_NONE, "Poly", "Set the splines to Poly"},
- {0, NULL, 0, NULL, NULL}};
-
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSplineType", "storage");
prop = RNA_def_property(srna, "spline_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spline_type");
- RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_enum_items(prop, rna_enum_curves_types);
+ RNA_def_property_ui_text(prop, "Type", "The curve type to change the selected curves to");
+
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 4108baca2fa..30df8e20e8d 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -698,16 +698,18 @@ bool rna_PoseChannel_constraints_override_apply(Main *bmain,
return true;
}
-static int rna_PoseChannel_proxy_editable(PointerRNA *ptr, const char **r_info)
+static int rna_PoseChannel_proxy_editable(PointerRNA *UNUSED(ptr), const char **UNUSED(r_info))
{
+# if 0
Object *ob = (Object *)ptr->owner_id;
bArmature *arm = ob->data;
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
- if (false && pchan->bone && (pchan->bone->layer & arm->layer_protected)) {
+ if (pchan->bone && (pchan->bone->layer & arm->layer_protected)) {
*r_info = "Can't edit property of a proxy on a protected layer";
return 0;
}
+# endif
return PROP_EDITABLE;
}
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 72ad695cd03..16a4dfe71cf 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -89,7 +89,7 @@ const EnumPropertyItem rna_enum_property_type_items[] = {
{PROP_XYZ, "XYZ", 0, "XYZ", ""}, \
{PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""}, \
{PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Color", ""}, \
- {PROP_COORDS, "COORDS", 0, "Coordinates", ""}, \
+ {PROP_COORDS, "COORDINATES", 0, "Coordinates", ""}, \
/* Boolean. */ \
{PROP_LAYER, "LAYER", 0, "Layer", ""}, \
{PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""}
@@ -154,7 +154,7 @@ const EnumPropertyItem rna_enum_property_flag_items[] = {
{PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""},
{PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""},
{PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""},
- {PROP_PROPORTIONAL, "PROPORTIONAL", 0, "Adjust values proportionally to eachother", ""},
+ {PROP_PROPORTIONAL, "PROPORTIONAL", 0, "Adjust values proportionally to each other", ""},
{PROP_TEXTEDIT_UPDATE,
"TEXTEDIT_UPDATE",
0,
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 9b8e94db081..9e2a1d81bd3 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -92,11 +92,11 @@ static const EnumPropertyItem uv_sculpt_relaxation_items[] = {
};
#endif
-const EnumPropertyItem rna_enum_snap_target_items[] = {
- {SCE_SNAP_TARGET_CLOSEST, "CLOSEST", 0, "Closest", "Snap closest point onto target"},
- {SCE_SNAP_TARGET_CENTER, "CENTER", 0, "Center", "Snap transformation center onto target"},
- {SCE_SNAP_TARGET_MEDIAN, "MEDIAN", 0, "Median", "Snap median onto target"},
- {SCE_SNAP_TARGET_ACTIVE, "ACTIVE", 0, "Active", "Snap active onto target"},
+const EnumPropertyItem rna_enum_snap_source_items[] = {
+ {SCE_SNAP_SOURCE_CLOSEST, "CLOSEST", 0, "Closest", "Snap closest point onto target"},
+ {SCE_SNAP_SOURCE_CENTER, "CENTER", 0, "Center", "Snap transformation center onto target"},
+ {SCE_SNAP_SOURCE_MEDIAN, "MEDIAN", 0, "Median", "Snap median onto target"},
+ {SCE_SNAP_SOURCE_ACTIVE, "ACTIVE", 0, "Active", "Snap active onto target"},
{0, NULL, 0, NULL, NULL},
};
@@ -2712,6 +2712,23 @@ static char *rna_FFmpegSettings_path(const PointerRNA *UNUSED(ptr))
return BLI_strdup("render.ffmpeg");
}
+# ifdef WITH_FFMPEG
+/* FFMpeg Codec setting update hook. */
+static void rna_FFmpegSettings_codec_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+ FFMpegCodecData *codec_data = (FFMpegCodecData *)ptr->data;
+ if (!ELEM(codec_data->codec, AV_CODEC_ID_H264, AV_CODEC_ID_MPEG4, AV_CODEC_ID_VP9)) {
+ /* Constant Rate Factor (CRF) setting is only available for H264,
+ * MPEG4 and WEBM/VP9 codecs. So changing encoder quality mode to
+ * CBR as CRF is not supported.
+ */
+ codec_data->constant_rate_factor = FFM_CRF_NONE;
+ }
+}
+# endif
+
#else
/* Grease Pencil Interpolation tool settings */
@@ -3306,9 +3323,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Absolute grid alignment while translating (based on the pivot center)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid
+ * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is
+ * geometry to which moved geometry is snapped). */
prop = RNA_def_property(srna, "snap_target", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "snap_target");
- RNA_def_property_enum_items(prop, rna_enum_snap_target_items);
+ RNA_def_property_enum_items(prop, rna_enum_snap_source_items);
RNA_def_property_ui_text(prop, "Snap Target", "Which part to snap onto the target");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
@@ -5919,6 +5939,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, ffmpeg_codec_items);
RNA_def_property_enum_default(prop, AV_CODEC_ID_H264);
RNA_def_property_ui_text(prop, "Video Codec", "FFmpeg codec to use for video output");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_update");
prop = RNA_def_property(srna, "video_bitrate", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "video_bitrate");
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 200e1d65caf..3953fc66fc8 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -140,7 +140,7 @@ static void rna_Scene_ray_cast(Scene *scene,
depsgraph,
NULL,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
},
origin,
direction,
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index ab5e4c2f0d5..3de9e632ff6 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -774,6 +774,20 @@ static void rna_def_sculpt(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem sculpt_transform_mode_items[] = {
+ {SCULPT_TRANSFORM_MODE_ALL_VERTICES,
+ "ALL_VERTICES",
+ 0,
+ "All Vertices",
+ "Applies the transformation to all vertices in the mesh"},
+ {SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC,
+ "RADIUS_ELASTIC",
+ 0,
+ "Elastic",
+ "Applies the transformation simulating elasticity using the radius of the cursor"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
StructRNA *srna;
PropertyRNA *prop;
@@ -912,6 +926,12 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Gravity", "Amount of gravity after each dab");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "transform_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, sculpt_transform_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Transform Mode", "How the transformation is going to be applied to the target");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "gravity_object", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index af43133c979..cae86801402 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -7818,6 +7818,12 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Integer Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+ prop = RNA_def_property(srna, "value_int8", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "value_int");
+ RNA_def_property_range(prop, -128, 127);
+ RNA_def_property_ui_text(prop, "8-Bit Integer Value", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
prop = RNA_def_property(srna, "value_boolean", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_ROW_FILTER_BOOL_VALUE);
RNA_def_property_ui_text(prop, "Boolean Value", "");
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 1d0723851ad..dabb89bcd5e 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -393,7 +393,14 @@ static StructRNA *rna_Panel_register(Main *bmain,
if (parent) {
pt->parent = parent;
- BLI_addtail(&parent->children, BLI_genericNodeN(pt));
+ LinkData *pt_child_iter = parent->children.last;
+ for (; pt_child_iter; pt_child_iter = pt_child_iter->prev) {
+ PanelType *pt_child = pt_child_iter->data;
+ if (pt_child->order <= pt->order) {
+ break;
+ }
+ }
+ BLI_insertlinkafter(&parent->children, pt_child_iter, BLI_genericNodeN(pt));
}
{
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 43e8879fc17..40dc1254a7d 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -1531,6 +1531,11 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "List Item Colors", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "wcol_view_item", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_ui_text(prop, "Data-View Item Colors", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
prop = RNA_def_property(srna, "wcol_state", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "State Colors", "");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 1dc2cbe9e69..3ff9e6be3ce 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -24,6 +24,7 @@
#include "rna_internal.h"
+#include "WM_api.h"
#include "WM_types.h"
#ifdef RNA_RUNTIME
@@ -123,6 +124,23 @@ static const EnumPropertyItem event_ndof_type_items[] = {
};
#endif /* RNA_RUNTIME */
+/**
+ * Job types for use in the `bpy.app.is_job_running(job_type)` call.
+ *
+ * This is a subset of the `WM_JOB_TYPE_...` anonymous enum defined in `WM_api.h`. It is
+ * intentionally kept as a subset, such that by default how jobs are handled is kept as an
+ * "internal implementation detail" of Blender, rather than a public, reliable part of the API.
+ *
+ * This array can be expanded on a case-by-case basis, when there is a clear and testable use case.
+ */
+const EnumPropertyItem rna_enum_wm_job_type_items[] = {
+ {WM_JOB_TYPE_RENDER, "RENDER", 0, "Regular rendering", ""},
+ {WM_JOB_TYPE_RENDER_PREVIEW, "RENDER_PREVIEW", 0, "Rendering previews", ""},
+ {WM_JOB_TYPE_OBJECT_BAKE, "OBJECT_BAKE", 0, "Object Baking", ""},
+ {WM_JOB_TYPE_COMPOSITE, "COMPOSITE", 0, "Compositing", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_event_type_items[] = {
/* - Note we abuse 'tooltip' message here to store a 'compact' form of some (too) long names.
* - Intentionally excluded: #CAPSLOCKKEY, #UNKNOWNKEY.
@@ -898,7 +916,7 @@ 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.
+ * Function makes sure key-modifiers are only valid keys, ESC keeps it unaltered.
*/
static void rna_wmKeyMapItem_keymodifier_set(PointerRNA *ptr, int value)
{
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 5da65510399..b9f36d35ee8 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -23,6 +23,7 @@
#include "wm_cursors.h"
#include "wm_event_types.h"
+#include "WM_api.h"
#include "WM_types.h"
#include "rna_internal.h" /* own include */
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 02aa5254e55..77915702ee4 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -464,7 +464,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
copy_m4_m4(offset, result_mat);
}
- /* Check if there is some scaling. If scaling, then we will not translate mapping */
+ /* Check if there is some scaling. If scaling, then we will not translate mapping */
mat4_to_size(scale, offset);
offset_has_scale = !is_one_v3(scale);
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index d47f2a130e3..5739de1c65c 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -223,7 +223,7 @@ static BMesh *BMD_mesh_bm_create(
Mesh *mesh, Object *object, Mesh *mesh_operand_ob, Object *operand_ob, bool *r_is_flip)
{
#ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
#endif
*r_is_flip = (is_negative_m4(object->obmat) != is_negative_m4(operand_ob->obmat));
@@ -270,7 +270,7 @@ static void BMD_mesh_intersection(BMesh *bm,
bool is_flip)
{
#ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
#endif
BooleanModifierData *bmd = (BooleanModifierData *)md;
@@ -399,7 +399,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
Vector<Array<short>> material_remaps;
# ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
# endif
if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object == nullptr) {
@@ -447,7 +447,8 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
material_remaps,
use_self,
hole_tolerant,
- bmd->operation);
+ bmd->operation,
+ nullptr);
}
#endif
@@ -470,7 +471,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
#endif
#ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
#endif
if (bmd->flag & eBooleanModifierFlag_Object) {
@@ -518,24 +519,29 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob,
false);
- if (mesh_operand_ob) {
- /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
- * But for 2.90 better not try to be smart here. */
- BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob);
+ if (mesh_operand_ob == nullptr) {
+ continue;
+ }
- bool is_flip;
- BMesh *bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip);
+ /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
+ * But for 2.90 better not try to be smart here. */
+ BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob);
- BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
+ bool is_flip;
+ BMesh *bm = BMD_mesh_bm_create(result, object, mesh_operand_ob, operand_ob, &is_flip);
- /* Needed for multiple objects to work. */
- BMeshToMeshParams bmesh_to_mesh_params{};
- bmesh_to_mesh_params.calc_object_remap = false;
- BM_mesh_bm_to_me(nullptr, bm, mesh, &bmesh_to_mesh_params);
+ BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
+ /* Needed for multiple objects to work. */
+ if (result == mesh) {
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
- BM_mesh_free(bm);
}
+ else {
+ BMeshToMeshParams bmesh_to_mesh_params{};
+ bmesh_to_mesh_params.calc_object_remap = false;
+ BM_mesh_bm_to_me(nullptr, bm, result, &bmesh_to_mesh_params);
+ }
+ BM_mesh_free(bm);
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 8b6c306dae8..3698f4403a1 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -801,8 +801,9 @@ static void panelRegister(ARegionType *region_type)
static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
CorrectiveSmoothModifierData csmd = *(const CorrectiveSmoothModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
- if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
BLI_assert(!ID_IS_LINKED(id_owner));
const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
if (!is_local) {
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index d76a750f7e8..8e85cb1bfb3 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -897,7 +897,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
{
Mesh *explode, *mesh = to_explode;
MFace *mf = NULL, *mface;
- /* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */
+ // ParticleSettings *part=psmd->psys->part; /* UNUSED */
ParticleSimulationData sim = {NULL};
ParticleData *pa = NULL, *pars = psmd->psys->particles;
ParticleKey state, birth;
@@ -906,7 +906,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
float *vertco = NULL, imat[4][4];
float rot[4];
float ctime;
- /* float timestep; */
+ // float timestep;
const int *facepa = emd->facepa;
int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0;
int i, v, u;
@@ -923,7 +923,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
sim.psys = psmd->psys;
sim.psmd = psmd;
- /* timestep = psys_get_timestep(&sim); */
+ // timestep = psys_get_timestep(&sim);
ctime = BKE_scene_ctime_get(scene);
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index 06ded1c4488..a22f4b35e0d 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -846,8 +846,9 @@ static void panelRegister(ARegionType *region_type)
static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
LaplacianDeformModifierData lmd = *(const LaplacianDeformModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
- if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
BLI_assert(!ID_IS_LINKED(id_owner));
const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
if (!is_local) {
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 0cff85d30ec..5dac31ac1df 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -584,8 +584,9 @@ static void panelRegister(ARegionType *region_type)
static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
MeshDeformModifierData mmd = *(const MeshDeformModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
- if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
BLI_assert(!ID_IS_LINKED(id_owner));
const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
if (!is_local) {
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 4201bab0326..23f447f2469 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -196,16 +196,21 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
/* Cache settings for lazy CPU evaluation. */
-static void subdiv_cache_cpu_evaluation_settings(const ModifierEvalContext *ctx,
- Mesh *me,
- SubsurfModifierData *smd)
+static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx,
+ Mesh *mesh,
+ SubsurfModifierData *smd,
+ SubsurfRuntimeData *runtime_data)
{
SubdivToMeshSettings mesh_settings;
subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
- me->runtime.subsurf_apply_render = (ctx->flag & MOD_APPLY_RENDER) != 0;
- me->runtime.subsurf_resolution = mesh_settings.resolution;
- me->runtime.subsurf_use_optimal_display = mesh_settings.use_optimal_display;
- me->runtime.subsurf_session_uuid = smd->modifier.session_uuid;
+
+ runtime_data->has_gpu_subdiv = true;
+ runtime_data->resolution = mesh_settings.resolution;
+ runtime_data->use_optimal_display = mesh_settings.use_optimal_display;
+ runtime_data->calc_loop_normals = false; /* Set at the end of modifier stack evaluation. */
+ runtime_data->use_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals);
+
+ mesh->runtime.subsurf_runtime_data = runtime_data;
}
/* Modifier itself. */
@@ -218,13 +223,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return result;
#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(
- &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
- if (subdiv_settings.level == 0) {
+ if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return result;
}
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
/* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier.
*/
@@ -237,13 +240,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
const bool is_editmode = (mesh->edit_mesh != NULL);
const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode);
if (BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ctx->object, mesh, smd, required_mode)) {
- subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd);
+ subdiv_cache_mesh_wrapper_settings(ctx, mesh, smd, runtime_data);
return result;
}
}
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
- smd, &subdiv_settings, mesh, false);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return result;
@@ -294,15 +296,11 @@ static void deformMatrices(ModifierData *md,
(void)deform_matrices;
SubsurfModifierData *smd = (SubsurfModifierData *)md;
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(
- &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
- if (subdiv_settings.level == 0) {
+ if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return;
}
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
- smd, &subdiv_settings, mesh, false);
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return;
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index 9b0012e3890..20cc9b2392f 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -1672,8 +1672,9 @@ static void panelRegister(ARegionType *region_type)
static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
SurfaceDeformModifierData smd = *(const SurfaceDeformModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
- if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
BLI_assert(!ID_IS_LINKED(id_owner));
const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
if (!is_local) {
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 064112b7efd..e4e4295fd3a 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -62,6 +62,8 @@ void register_node_type_geo_input_curve_handles(void);
void register_node_type_geo_input_curve_tilt(void);
void register_node_type_geo_input_id(void);
void register_node_type_geo_input_index(void);
+void register_node_type_geo_input_instance_rotation(void);
+void register_node_type_geo_input_instance_scale(void);
void register_node_type_geo_input_material_index(void);
void register_node_type_geo_input_material(void);
void register_node_type_geo_input_mesh_edge_angle(void);
@@ -133,6 +135,7 @@ void register_node_type_geo_transform(void);
void register_node_type_geo_translate_instances(void);
void register_node_type_geo_triangulate(void);
void register_node_type_geo_viewer(void);
+void register_node_type_geo_volume_cube(void);
void register_node_type_geo_volume_to_mesh(void);
#ifdef __cplusplus
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 8ffa9d978a8..b82c05f33be 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -298,47 +298,6 @@ class GeoNodeExecParams {
*/
void error_message_add(const NodeWarningType type, std::string message) const;
- /**
- * Creates a read-only attribute based on node inputs. The method automatically detects which
- * input socket with the given name is available.
- *
- * \note This will add an error message if the string socket is active and
- * the input attribute does not exist.
- */
- GVArray get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- eAttrDomain domain,
- eCustomDataType type,
- const void *default_value) const;
-
- template<typename T>
- VArray<T> get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const eAttrDomain domain,
- const T &default_value) const
- {
- const eCustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>());
- GVArray varray = this->get_input_attribute(name, component, domain, type, &default_value);
- return varray.typed<T>();
- }
-
- /**
- * Get the type of an input property or the associated constant socket types with the
- * same names. Fall back to the default value if no attribute exists with the name.
- */
- eCustomDataType get_input_attribute_data_type(const StringRef name,
- const GeometryComponent &component,
- eCustomDataType default_type) const;
-
- /**
- * If any of the corresponding input sockets are attributes instead of single values,
- * use the highest priority attribute domain from among them.
- * Otherwise return the default domain.
- */
- eAttrDomain get_highest_priority_input_domain(Span<std::string> names,
- const GeometryComponent &component,
- eAttrDomain default_domain) const;
-
std::string attribute_producer_name() const;
void set_default_remaining_outputs();
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index e0a4d241b3b..9793f133dd6 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -318,6 +318,8 @@ DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", In
DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "")
DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "")
DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_INSTANCE_ROTATION, 0, "INPUT_INSTANCE_ROTATION", InputInstanceRotation, "Instance Rotation", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_INSTANCE_SCALE, 0, "INPUT_INSTANCE_SCALE", InputInstanceScale, "Instance Scale", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL_INDEX, 0, "INPUT_MATERIAL_INDEX", InputMaterialIndex, "Material Index", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_ANGLE, 0, "MESH_EDGE_ANGLE", InputMeshEdgeAngle, "Edge Angle", "")
@@ -395,6 +397,7 @@ DefNode(GeometryNode, GEO_NODE_TRANSLATE_INSTANCES, 0, "TRANSLATE_INSTANCES", Tr
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
DefNode(GeometryNode, GEO_NODE_TRIM_CURVE, def_geo_curve_trim, "TRIM_CURVE", TrimCurve, "Trim Curve", "")
DefNode(GeometryNode, GEO_NODE_VIEWER, def_geo_viewer, "VIEWER", Viewer, "Viewer", "")
+DefNode(GeometryNode, GEO_NODE_VOLUME_CUBE, 0, "VOLUME_CUBE", VolumeCube, "Volume Cube", "")
DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
/* undefine macros */
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index 84280c0889a..015edf2d26c 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -71,6 +71,8 @@ set(SRC
nodes/node_geo_input_curve_tilt.cc
nodes/node_geo_input_id.cc
nodes/node_geo_input_index.cc
+ nodes/node_geo_input_instance_rotation.cc
+ nodes/node_geo_input_instance_scale.cc
nodes/node_geo_input_material.cc
nodes/node_geo_input_material_index.cc
nodes/node_geo_input_mesh_edge_angle.cc
@@ -142,6 +144,7 @@ set(SRC
nodes/node_geo_translate_instances.cc
nodes/node_geo_triangulate.cc
nodes/node_geo_viewer.cc
+ nodes/node_geo_volume_cube.cc
nodes/node_geo_volume_to_mesh.cc
node_geometry_exec.cc
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index d261928d1b8..efb7efaf1cc 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -73,7 +73,6 @@ void separate_geometry(GeometrySet &geometry_set,
eAttrDomain domain,
GeometryNodeDeleteGeometryMode mode,
const Field<bool> &selection_field,
- bool invert,
bool &r_is_error);
std::optional<eCustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index e485172d3e1..daeca311e08 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -20,6 +20,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Bool>(N_("Self Intersection"));
b.add_input<decl::Bool>(N_("Hole Tolerant"));
b.add_output<decl::Geometry>(N_("Mesh"));
+ b.add_output<decl::Bool>(N_("Intersecting Edges")).field_source();
}
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -27,6 +28,10 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
+struct AttributeOutputs {
+ StrongAnonymousAttributeID intersecting_edges_id;
+};
+
static void node_update(bNodeTree *ntree, bNode *node)
{
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1;
@@ -121,13 +126,21 @@ static void node_geo_exec(GeoNodeExecParams params)
}
}
- Mesh *result = blender::meshintersect::direct_mesh_boolean(meshes,
- transforms,
- float4x4::identity(),
- material_remaps,
- use_self,
- hole_tolerant,
- operation);
+ AttributeOutputs attribute_outputs;
+ if (params.output_is_required("Intersecting Edges")) {
+ attribute_outputs.intersecting_edges_id = StrongAnonymousAttributeID("Intersecting Edges");
+ }
+
+ Vector<int> intersecting_edges;
+ Mesh *result = blender::meshintersect::direct_mesh_boolean(
+ meshes,
+ transforms,
+ float4x4::identity(),
+ material_remaps,
+ use_self,
+ hole_tolerant,
+ operation,
+ attribute_outputs.intersecting_edges_id ? &intersecting_edges : nullptr);
if (!result) {
params.set_default_remaining_outputs();
return;
@@ -138,6 +151,26 @@ static void node_geo_exec(GeoNodeExecParams params)
result->totcol = materials.size();
MutableSpan(result->mat, result->totcol).copy_from(materials);
+ /* Store intersecting edges in attribute. */
+ if (attribute_outputs.intersecting_edges_id) {
+ MeshComponent mesh_component;
+ mesh_component.replace(result, GeometryOwnershipType::Editable);
+ OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>(
+ attribute_outputs.intersecting_edges_id.get(), ATTR_DOMAIN_EDGE);
+ MutableSpan<bool> selection = attribute.as_span();
+ selection.fill(false);
+ for (const int i : intersecting_edges) {
+ selection[i] = true;
+ }
+
+ attribute.save();
+
+ params.set_output(
+ "Intersecting Edges",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_outputs.intersecting_edges_id), params.attribute_producer_name()));
+ }
+
params.set_output("Mesh", GeometrySet::create_with_mesh(result));
#else
params.error_message_add(NodeWarningType::Error,
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 8401c94be4b..ae2b4fd779d 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
@@ -75,7 +75,7 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
case CURVE_TYPE_CATMULL_ROM: {
const int resolution = resolutions[i_curve];
for (const int i : IndexRange(points.size()).drop_back(1)) {
- lengths[i + 1] = evaluated_lengths[resolution * i];
+ lengths[i + 1] = evaluated_lengths[resolution * (i + 1) - 1];
}
break;
}
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 500804e41f0..8479d61a890 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
@@ -1,6 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
+#include <numeric>
+
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
#include "BLI_task.hh"
@@ -29,10 +33,39 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
- data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
+ data->spline_type = CURVE_TYPE_POLY;
node->storage = data;
}
+/**
+ * This function answers the question about possible conversion method for NURBS-to-Bezier. In
+ * general for 3rd degree NURBS curves there is one-to-one relation with 3rd degree Bezier curves
+ * that can be exploit for conversion - Bezier handles sit on NURBS hull segments and in the middle
+ * between those handles are Bezier anchor points.
+ */
+static bool is_nurbs_to_bezier_one_to_one(const KnotsMode knots_mode)
+{
+ if (ELEM(knots_mode, NURBS_KNOT_MODE_NORMAL, NURBS_KNOT_MODE_ENDPOINT)) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * As an optimization, just change the types on a mutable curves data-block when the conversion is
+ * simple. This could be expanded to more cases where the number of points doesn't change in the
+ * future, though that might require properly initializing some attributes, or removing others.
+ */
+static bool conversion_can_change_point_num(const CurveType dst_type)
+{
+ if (ELEM(dst_type, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_POLY)) {
+ /* The conversion to Catmull Rom or Poly should never change the number of points, no matter
+ * the source type (Bezier to Catmull Rom conversion cannot maintain the same shape anyway). */
+ return false;
+ }
+ return true;
+}
+
template<typename T>
static void scale_input_assign(const Span<T> src,
const int scale,
@@ -44,32 +77,97 @@ static void scale_input_assign(const Span<T> src,
}
}
-template<typename T>
-static void scale_output_assign(const Span<T> src,
- const int scale,
- const int offset,
- MutableSpan<T> dst)
+/**
+ * The Bezier control point and its handles become three control points on the NURBS curve,
+ * so each attribute value is duplicated three times.
+ */
+template<typename T> static void bezier_generic_to_nurbs(const Span<T> src, MutableSpan<T> dst)
{
for (const int i : src.index_range()) {
- dst[i * scale + offset] = src[i];
+ dst[i * 3] = src[i];
+ dst[i * 3 + 1] = src[i];
+ dst[i * 3 + 2] = src[i];
+ }
+}
+
+static void bezier_generic_to_nurbs(const GSpan src, GMutableSpan dst)
+{
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ bezier_generic_to_nurbs(src.typed<T>(), dst.typed<T>());
+ });
+}
+
+static void bezier_positions_to_nurbs(const Span<float3> src_positions,
+ const Span<float3> src_handles_l,
+ const Span<float3> src_handles_r,
+ MutableSpan<float3> dst_positions)
+{
+ for (const int i : src_positions.index_range()) {
+ dst_positions[i * 3] = src_handles_l[i];
+ dst_positions[i * 3 + 1] = src_positions[i];
+ dst_positions[i * 3 + 2] = src_handles_r[i];
+ }
+}
+
+static void catmull_rom_to_bezier_handles(const Span<float3> src_positions,
+ const bool cyclic,
+ MutableSpan<float3> dst_handles_l,
+ MutableSpan<float3> dst_handles_r)
+{
+ /* Catmull Rom curves are the same as Bezier curves with automatically defined handle positions.
+ * This constant defines the portion of the distance between the next/previous points to use for
+ * the length of the handles. */
+ constexpr float handle_scale = 1.0f / 6.0f;
+
+ if (src_positions.size() == 1) {
+ dst_handles_l.first() = src_positions.first();
+ dst_handles_r.first() = src_positions.first();
+ return;
+ }
+
+ const float3 first_offset = cyclic ? src_positions[1] - src_positions.last() :
+ src_positions[1] - src_positions[0];
+ dst_handles_r.first() = src_positions.first() + first_offset * handle_scale;
+ dst_handles_l.first() = src_positions.first() - first_offset * handle_scale;
+
+ const float3 last_offset = cyclic ? src_positions.first() - src_positions.last(1) :
+ src_positions.last() - src_positions.last(1);
+ dst_handles_l.last() = src_positions.last() - last_offset * handle_scale;
+ dst_handles_r.last() = src_positions.last() + last_offset * handle_scale;
+
+ for (const int i : src_positions.index_range().drop_front(1).drop_back(1)) {
+ const float3 left_offset = src_positions[i - 1] - src_positions[i + 1];
+ dst_handles_l[i] = src_positions[i] + left_offset * handle_scale;
+
+ const float3 right_offset = src_positions[i + 1] - src_positions[i - 1];
+ dst_handles_r[i] = src_positions[i] + right_offset * handle_scale;
}
}
+static void catmull_rom_to_nurbs_positions(const Span<float3> src_positions,
+ const bool cyclic,
+ MutableSpan<float3> dst_positions)
+{
+ /* Convert the Catmull Rom position data to Bezier handles in order to reuse the Bezier to
+ * NURBS positions assignment. If this becomes a bottleneck, this step could be avoided. */
+ Array<float3, 32> bezier_handles_l(src_positions.size());
+ Array<float3, 32> bezier_handles_r(src_positions.size());
+ catmull_rom_to_bezier_handles(src_positions, cyclic, bezier_handles_l, bezier_handles_r);
+ bezier_positions_to_nurbs(src_positions, bezier_handles_l, bezier_handles_r, dst_positions);
+}
+
template<typename T>
static void nurbs_to_bezier_assign(const Span<T> src,
const MutableSpan<T> dst,
const KnotsMode knots_mode)
{
switch (knots_mode) {
- case NURBS_KNOT_MODE_BEZIER:
- scale_input_assign<T>(src, 3, 1, dst);
- break;
case NURBS_KNOT_MODE_NORMAL:
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 : dst.index_range().drop_back(1).drop_front(1)) {
dst[i] = src[i + 1];
@@ -77,31 +175,19 @@ static void nurbs_to_bezier_assign(const Span<T> src,
dst.first() = src.first();
dst.last() = src.last();
break;
+ default:
+ /* Every 3rd NURBS position (starting from index 1) should have its attributes transferred.
+ */
+ scale_input_assign<T>(src, 3, 1, dst);
}
}
-template<typename CopyFn>
-static void copy_attributes(const Spline &input_spline, Spline &output_spline, CopyFn copy_fn)
+static void nurbs_to_bezier_assign(const GSpan src, const KnotsMode knots_mode, GMutableSpan dst)
{
- input_spline.attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id);
- BLI_assert(src);
- if (!output_spline.attributes.create(attribute_id, meta_data.data_type)) {
- BLI_assert_unreachable();
- return false;
- }
- std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(attribute_id);
- if (!dst) {
- BLI_assert_unreachable();
- return false;
- }
-
- copy_fn(*src, *dst);
-
- return true;
- },
- ATTR_DOMAIN_POINT);
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ nurbs_to_bezier_assign(src.typed<T>(), dst.typed<T>(), knots_mode);
+ });
}
static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_positions,
@@ -109,22 +195,8 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po
{
const int nurbs_positions_num = nurbs_positions.size();
Vector<float3> handle_positions;
- if (knots_mode == NURBS_KNOT_MODE_BEZIER) {
- for (const int i : IndexRange(nurbs_positions_num)) {
- if (i % 3 == 1) {
- continue;
- }
- handle_positions.append(nurbs_positions[i]);
- }
- if (nurbs_positions_num % 3 == 1) {
- handle_positions.pop_last();
- }
- else if (nurbs_positions_num % 3 == 2) {
- const int last_index = nurbs_positions_num - 1;
- handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
- }
- }
- else {
+
+ if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
const bool is_periodic = knots_mode == NURBS_KNOT_MODE_NORMAL;
if (is_periodic) {
handle_positions.append(nurbs_positions[1] +
@@ -134,11 +206,15 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po
handle_positions.append(2 * nurbs_positions[0] - nurbs_positions[1]);
handle_positions.append(nurbs_positions[1]);
}
+
+ /* Place Bezier handles on interior NURBS hull segments. Those handles can be either placed on
+ * endpoints, midpoints or 1/3 of the distance of a hull segment. */
const int segments_num = nurbs_positions_num - 1;
const bool ignore_interior_segment = segments_num == 3 && is_periodic == false;
if (ignore_interior_segment == false) {
const float mid_offset = (float)(segments_num - 1) / 2.0f;
for (const int i : IndexRange(1, segments_num - 2)) {
+ /* Divisor can have values: 1, 2 or 3. */
const int divisor = is_periodic ?
3 :
std::min(3, (int)(-std::abs(i - mid_offset) + mid_offset + 1.0f));
@@ -151,6 +227,7 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po
}
}
}
+
const int last_index = nurbs_positions_num - 1;
if (is_periodic) {
handle_positions.append(
@@ -162,199 +239,433 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po
handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
}
}
+ else {
+ for (const int i : IndexRange(nurbs_positions_num)) {
+ if (i % 3 == 1) {
+ continue;
+ }
+ handle_positions.append(nurbs_positions[i]);
+ }
+ if (nurbs_positions_num % 3 == 1) {
+ handle_positions.pop_last();
+ }
+ else if (nurbs_positions_num % 3 == 2) {
+ const int last_index = nurbs_positions_num - 1;
+ handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
+ }
+ }
+
return handle_positions;
}
-static Array<float3> create_nurbs_to_bezier_positions(const Span<float3> nurbs_positions,
- const Span<float3> handle_positions,
- const KnotsMode knots_mode)
+static void create_nurbs_to_bezier_positions(const Span<float3> nurbs_positions,
+ const Span<float3> handle_positions,
+ const KnotsMode knots_mode,
+ MutableSpan<float3> bezier_positions)
{
- if (knots_mode == NURBS_KNOT_MODE_BEZIER) {
- /* Every third NURBS position (starting from index 1) should be converted to Bezier position */
- const int scale = 3;
- const int offset = 1;
- Array<float3> bezier_positions((nurbs_positions.size() + offset) / scale);
- scale_input_assign(nurbs_positions, scale, offset, bezier_positions.as_mutable_span());
- return bezier_positions;
+ if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
+ for (const int i : bezier_positions.index_range()) {
+ bezier_positions[i] = math::interpolate(
+ handle_positions[i * 2], handle_positions[i * 2 + 1], 0.5f);
+ }
}
-
- Array<float3> bezier_positions(handle_positions.size() / 2);
- for (const int i : IndexRange(bezier_positions.size())) {
- bezier_positions[i] = math::interpolate(
- handle_positions[i * 2], handle_positions[i * 2 + 1], 0.5f);
+ else {
+ /* Every 3rd NURBS position (starting from index 1) should be converted to Bezier position. */
+ scale_input_assign(nurbs_positions, 3, 1, bezier_positions);
}
- return bezier_positions;
}
-static SplinePtr convert_to_poly_spline(const Spline &input)
+static int to_bezier_size(const CurveType src_type,
+ const bool cyclic,
+ const KnotsMode knots_mode,
+ const int src_size)
{
- std::unique_ptr<PolySpline> output = std::make_unique<PolySpline>();
- output->resize(input.positions().size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- Spline::copy_base_settings(input, *output);
- output->attributes = input.attributes;
- return output;
+ switch (src_type) {
+ case CURVE_TYPE_NURBS: {
+ if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
+ return cyclic ? src_size : src_size - 2;
+ }
+ return (src_size + 1) / 3;
+ }
+ default:
+ return src_size;
+ }
}
-static SplinePtr poly_to_nurbs(const Spline &input)
+static int to_nurbs_size(const CurveType src_type, const int src_size)
{
- std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
- output->resize(input.positions().size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- output->weights().fill(1.0f);
- output->set_resolution(12);
- output->set_order(4);
- Spline::copy_base_settings(input, *output);
- output->knots_mode = NURBS_KNOT_MODE_BEZIER;
- output->attributes = input.attributes;
- return output;
+ switch (src_type) {
+ case CURVE_TYPE_BEZIER:
+ case CURVE_TYPE_CATMULL_ROM:
+ return src_size * 3;
+ default:
+ return src_size;
+ }
}
-static SplinePtr bezier_to_nurbs(const Spline &input)
+static void retrieve_curve_sizes(const bke::CurvesGeometry &curves, MutableSpan<int> sizes)
{
- const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(input);
- std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
- output->resize(input.size() * 3);
-
- scale_output_assign(bezier_spline.handle_positions_left(), 3, 0, output->positions());
- scale_output_assign(input.radii(), 3, 0, output->radii());
- scale_output_assign(input.tilts(), 3, 0, output->tilts());
-
- scale_output_assign(bezier_spline.positions(), 3, 1, output->positions());
- scale_output_assign(input.radii(), 3, 1, output->radii());
- scale_output_assign(input.tilts(), 3, 1, output->tilts());
-
- scale_output_assign(bezier_spline.handle_positions_right(), 3, 2, output->positions());
- scale_output_assign(input.radii(), 3, 2, output->radii());
- scale_output_assign(input.tilts(), 3, 2, output->tilts());
-
- Spline::copy_base_settings(input, *output);
- output->weights().fill(1.0f);
- output->set_resolution(12);
- output->set_order(4);
- output->set_cyclic(input.is_cyclic());
- output->knots_mode = NURBS_KNOT_MODE_BEZIER;
- output->attributes.reallocate(output->size());
- copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) {
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- scale_output_assign<T>(src.typed<T>(), 3, 0, dst.typed<T>());
- scale_output_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>());
- scale_output_assign<T>(src.typed<T>(), 3, 2, dst.typed<T>());
- });
+ threading::parallel_for(curves.curves_range(), 4096, [&](IndexRange range) {
+ for (const int i : range) {
+ sizes[i] = curves.points_for_curve(i).size();
+ }
});
- return output;
}
-static SplinePtr poly_to_bezier(const Spline &input)
+struct GenericAttributes : NonCopyable, NonMovable {
+ Vector<GSpan> src;
+ Vector<GMutableSpan> dst;
+
+ Vector<OutputAttribute> attributes;
+};
+
+static void retrieve_generic_point_attributes(const CurveComponent &src_component,
+ CurveComponent &dst_component,
+ GenericAttributes &attributes)
{
- std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
- output->resize(input.size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- output->handle_types_left().fill(BEZIER_HANDLE_VECTOR);
- output->handle_types_right().fill(BEZIER_HANDLE_VECTOR);
- output->set_resolution(12);
- Spline::copy_base_settings(input, *output);
- output->attributes = input.attributes;
- return output;
+ src_component.attribute_foreach(
+ [&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (meta_data.domain != ATTR_DOMAIN_POINT) {
+ /* Curve domain attributes are all copied directly to the result in one step. */
+ return true;
+ }
+ if (src_component.attribute_is_builtin(id)) {
+ if (!(id.is_named() && ELEM(id, "tilt", "radius"))) {
+ return true;
+ }
+ }
+
+ GVArray src_attribute = src_component.attribute_try_get_for_read(id, ATTR_DOMAIN_POINT);
+ BLI_assert(src_attribute);
+ attributes.src.append(src_attribute.get_internal_span());
+
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ id, ATTR_DOMAIN_POINT, meta_data.data_type);
+ attributes.dst.append(dst_attribute.as_span());
+ attributes.attributes.append(std::move(dst_attribute));
+
+ return true;
+ });
}
-static SplinePtr nurbs_to_bezier(const Spline &input)
+static void convert_to_bezier(const CurveComponent &src_component,
+ const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ CurveComponent &dst_component,
+ bke::CurvesGeometry &dst_curves)
{
- const NURBSpline &nurbs_spline = static_cast<const NURBSpline &>(input);
- Span<float3> nurbs_positions;
- Vector<float3> nurbs_positions_vector;
- KnotsMode knots_mode;
- if (nurbs_spline.is_cyclic()) {
- nurbs_positions_vector = nurbs_spline.positions();
- nurbs_positions_vector.append(nurbs_spline.positions()[0]);
- nurbs_positions_vector.append(nurbs_spline.positions()[1]);
- nurbs_positions = nurbs_positions_vector;
- knots_mode = NURBS_KNOT_MODE_NORMAL;
+ const VArray<int8_t> src_knot_modes = src_curves.nurbs_knots_modes();
+ const VArray<int8_t> src_types = src_curves.curve_types();
+ const VArray<bool> src_cyclic = src_curves.cyclic();
+ const Span<float3> src_positions = src_curves.positions();
+
+ MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
+ retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write());
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ dst_offsets[i] = to_bezier_size(
+ CurveType(src_types[i]), src_cyclic[i], KnotsMode(src_knot_modes[i]), dst_offsets[i]);
+ }
+ });
+ bke::curves::accumulate_counts_to_offsets(dst_offsets);
+ dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
+
+ GenericAttributes attributes;
+ retrieve_generic_point_attributes(src_component, dst_component, attributes);
+
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+ MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
+ MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write();
+ MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
+ MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
+ MutableSpan<float> dst_weights = dst_curves.nurbs_weights_for_write();
+
+ auto catmull_rom_to_bezier = [&](IndexMask selection) {
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ catmull_rom_to_bezier_handles(src_positions.slice(src_points),
+ src_cyclic[i],
+ dst_handles_l.slice(dst_points),
+ dst_handles_r.slice(dst_points));
+ }
+ });
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
+ }
+ };
+
+ auto poly_to_bezier = [&](IndexMask selection) {
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_l);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_r);
+ dst_curves.calculate_bezier_auto_handles();
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
+ }
+ };
+
+ auto bezier_to_bezier = [&](IndexMask selection) {
+ const VArray_Span<int8_t> src_types_l = src_curves.handle_types_left();
+ const VArray_Span<int8_t> src_types_r = src_curves.handle_types_right();
+ const Span<float3> src_handles_l = src_curves.handle_positions_left();
+ const Span<float3> src_handles_r = src_curves.handle_positions_right();
+
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_l, dst_handles_l);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_r, dst_handles_r);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_l, dst_types_l);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_r, dst_types_r);
+
+ dst_curves.calculate_bezier_auto_handles();
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
+ }
+ };
+
+ auto nurbs_to_bezier = [&](IndexMask selection) {
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
+ bke::curves::fill_points<float>(dst_curves, selection, 0.0f, dst_weights);
+
+ threading::parallel_for(selection.index_range(), 64, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ const Span<float3> src_curve_positions = src_positions.slice(src_points);
+
+ KnotsMode knots_mode = KnotsMode(src_knot_modes[i]);
+ Span<float3> nurbs_positions = src_curve_positions;
+ Vector<float3> nurbs_positions_vector;
+ if (src_cyclic[i] && is_nurbs_to_bezier_one_to_one(knots_mode)) {
+ /* For conversion treat this as periodic closed curve. Extend NURBS hull to first and
+ * second point which will act as a skeleton for placing Bezier handles. */
+ nurbs_positions_vector.extend(src_curve_positions);
+ nurbs_positions_vector.append(src_curve_positions[0]);
+ nurbs_positions_vector.append(src_curve_positions[1]);
+ nurbs_positions = nurbs_positions_vector;
+ knots_mode = NURBS_KNOT_MODE_NORMAL;
+ }
+
+ const Vector<float3> handle_positions = create_nurbs_to_bezier_handles(nurbs_positions,
+ knots_mode);
+
+ scale_input_assign(handle_positions.as_span(), 2, 0, dst_handles_l.slice(dst_points));
+ scale_input_assign(handle_positions.as_span(), 2, 1, dst_handles_r.slice(dst_points));
+
+ create_nurbs_to_bezier_positions(
+ nurbs_positions, handle_positions, knots_mode, dst_positions.slice(dst_points));
+ }
+ });
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ nurbs_to_bezier_assign(attributes.src[i_attribute].slice(src_points),
+ KnotsMode(src_knot_modes[i]),
+ attributes.dst[i_attribute].slice(dst_points));
+ }
+ });
+ }
+ };
+
+ bke::curves::foreach_curve_by_type(src_curves.curve_types(),
+ src_curves.curve_type_counts(),
+ selection,
+ catmull_rom_to_bezier,
+ poly_to_bezier,
+ bezier_to_bezier,
+ nurbs_to_bezier);
+
+ const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
+ src_curves.curves_range());
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
}
- else {
- nurbs_positions = nurbs_spline.positions();
- knots_mode = nurbs_spline.knots_mode;
+
+ for (OutputAttribute &attribute : attributes.attributes) {
+ attribute.save();
}
- const Vector<float3> handle_positions = create_nurbs_to_bezier_handles(nurbs_positions,
- knots_mode);
- BLI_assert(handle_positions.size() % 2 == 0);
- const Array<float3> bezier_positions = create_nurbs_to_bezier_positions(
- nurbs_positions, handle_positions.as_span(), knots_mode);
- BLI_assert(handle_positions.size() == bezier_positions.size() * 2);
-
- std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
- output->resize(bezier_positions.size());
- output->positions().copy_from(bezier_positions);
- nurbs_to_bezier_assign(nurbs_spline.radii(), output->radii(), knots_mode);
- nurbs_to_bezier_assign(nurbs_spline.tilts(), output->tilts(), knots_mode);
- scale_input_assign(handle_positions.as_span(), 2, 0, output->handle_positions_left());
- scale_input_assign(handle_positions.as_span(), 2, 1, output->handle_positions_right());
- output->handle_types_left().fill(BEZIER_HANDLE_ALIGN);
- output->handle_types_right().fill(BEZIER_HANDLE_ALIGN);
- output->set_resolution(nurbs_spline.resolution());
- Spline::copy_base_settings(nurbs_spline, *output);
- output->attributes.reallocate(output->size());
- copy_attributes(nurbs_spline, *output, [knots_mode](GSpan src, GMutableSpan dst) {
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- nurbs_to_bezier_assign(src.typed<T>(), dst.typed<T>(), knots_mode);
- });
- });
- return output;
}
-static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params)
+static void convert_to_nurbs(const CurveComponent &src_component,
+ const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ CurveComponent &dst_component,
+ bke::CurvesGeometry &dst_curves)
{
- switch (input.type()) {
- case CURVE_TYPE_BEZIER:
- return input.copy();
- case CURVE_TYPE_POLY:
- return poly_to_bezier(input);
- case CURVE_TYPE_NURBS:
- if (input.size() < 4) {
- params.error_message_add(
- NodeWarningType::Info,
- TIP_("NURBS must have minimum of 4 points for Bezier Conversion"));
- return input.copy();
+ const VArray<int8_t> src_types = src_curves.curve_types();
+ const VArray<bool> src_cyclic = src_curves.cyclic();
+ const Span<float3> src_positions = src_curves.positions();
+
+ MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
+ retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write());
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ dst_offsets[i] = to_nurbs_size(CurveType(src_types[i]), dst_offsets[i]);
+ }
+ });
+ bke::curves::accumulate_counts_to_offsets(dst_offsets);
+ dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
+
+ GenericAttributes attributes;
+ retrieve_generic_point_attributes(src_component, dst_component, attributes);
+
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+
+ auto fill_weights_if_necessary = [&](const IndexMask selection) {
+ if (!src_curves.nurbs_weights().is_empty()) {
+ bke::curves::fill_points(dst_curves, selection, 1.0f, dst_curves.nurbs_weights_for_write());
+ }
+ };
+
+ auto catmull_rom_to_nurbs = [&](IndexMask selection) {
+ dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
+ dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
+ fill_weights_if_necessary(selection);
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ catmull_rom_to_nurbs_positions(
+ src_positions.slice(src_points), src_cyclic[i], dst_positions.slice(dst_points));
+ }
+ });
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points),
+ attributes.dst[i_attribute].slice(dst_points));
+ }
+ });
+ }
+ };
+
+ auto poly_to_nurbs = [&](IndexMask selection) {
+ dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+ fill_weights_if_necessary(selection);
+
+ /* Avoid using "Endpoint" knots modes for cyclic curves, since it adds a sharp point at the
+ * start/end. */
+ if (src_cyclic.is_single()) {
+ dst_curves.nurbs_knots_modes_for_write().fill_indices(
+ selection,
+ src_cyclic.get_internal_single() ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT);
+ }
+ else {
+ VArray_Span<bool> cyclic{src_cyclic};
+ MutableSpan<int8_t> knots_modes = dst_curves.nurbs_knots_modes_for_write();
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ knots_modes[i] = cyclic[i] ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT;
+ }
+ });
+ }
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ selection,
+ attributes.src[i_attribute],
+ attributes.dst[i_attribute]);
+ }
+ };
+
+ auto bezier_to_nurbs = [&](IndexMask selection) {
+ const Span<float3> src_handles_l = src_curves.handle_positions_left();
+ const Span<float3> src_handles_r = src_curves.handle_positions_right();
+
+ dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
+ dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
+ fill_weights_if_necessary(selection);
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ bezier_positions_to_nurbs(src_positions.slice(src_points),
+ src_handles_l.slice(src_points),
+ src_handles_r.slice(src_points),
+ dst_positions.slice(dst_points));
}
- return nurbs_to_bezier(input);
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- return {};
+ });
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points),
+ attributes.dst[i_attribute].slice(dst_points));
+ }
+ });
+ }
+ };
+
+ auto nurbs_to_nurbs = [&](IndexMask selection) {
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+
+ if (!src_curves.nurbs_weights().is_empty()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ selection,
+ src_curves.nurbs_weights(),
+ dst_curves.nurbs_weights_for_write());
}
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ selection,
+ attributes.src[i_attribute],
+ attributes.dst[i_attribute]);
+ }
+ };
+
+ bke::curves::foreach_curve_by_type(src_curves.curve_types(),
+ src_curves.curve_type_counts(),
+ selection,
+ catmull_rom_to_nurbs,
+ poly_to_nurbs,
+ bezier_to_nurbs,
+ nurbs_to_nurbs);
+
+ const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
+ src_curves.curves_range());
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
}
- BLI_assert_unreachable();
- return {};
-}
-static SplinePtr convert_to_nurbs(const Spline &input)
-{
- switch (input.type()) {
- case CURVE_TYPE_NURBS:
- return input.copy();
- case CURVE_TYPE_BEZIER:
- return bezier_to_nurbs(input);
- case CURVE_TYPE_POLY:
- return poly_to_nurbs(input);
- case CURVE_TYPE_CATMULL_ROM:
- BLI_assert_unreachable();
- return {};
+ for (OutputAttribute &attribute : attributes.attributes) {
+ attribute.save();
}
- BLI_assert_unreachable();
- return {};
}
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSplineType &storage = node_storage(params.node());
- const GeometryNodeSplineType dst_type = (const GeometryNodeSplineType)storage.spline_type;
+ const CurveType dst_type = CurveType(storage.spline_type);
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -363,45 +674,58 @@ static void node_geo_exec(GeoNodeExecParams params)
if (!geometry_set.has_curves()) {
return;
}
+ const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
+ const Curves &src_curves_id = *src_component.get_for_read();
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
+ if (src_curves.is_single_type(dst_type)) {
+ return;
+ }
- const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
- *curve_component->get_for_read());
- GeometryComponentFieldContext field_context{*curve_component, ATTR_DOMAIN_CURVE};
- const int domain_num = curve_component->attribute_domain_num(ATTR_DOMAIN_CURVE);
-
- Span<SplinePtr> src_splines = curve->splines();
-
- fn::FieldEvaluator selection_evaluator{field_context, domain_num};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
-
- std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
- new_curve->resize(src_splines.size());
-
- threading::parallel_for(src_splines.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- if (selection[i]) {
- switch (dst_type) {
- case GEO_NODE_SPLINE_TYPE_POLY:
- new_curve->splines()[i] = convert_to_poly_spline(*src_splines[i]);
- break;
- case GEO_NODE_SPLINE_TYPE_BEZIER:
- new_curve->splines()[i] = convert_to_bezier(*src_splines[i], params);
- break;
- case GEO_NODE_SPLINE_TYPE_NURBS:
- new_curve->splines()[i] = convert_to_nurbs(*src_splines[i]);
- break;
- }
- }
- else {
- new_curve->splines()[i] = src_splines[i]->copy();
- }
- }
- });
- new_curve->attributes = curve->attributes;
- geometry_set.replace_curves(curve_eval_to_curves(*new_curve));
+ GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
+ const int domain_size = src_component.attribute_domain_num(ATTR_DOMAIN_CURVE);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (!conversion_can_change_point_num(dst_type)) {
+ CurveComponent &dst_component = geometry_set.get_component_for_write<CurveComponent>();
+ Curves &curves_id = *dst_component.get_for_write();
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+ curves.fill_curve_types(selection, dst_type);
+ curves.remove_attributes_based_on_types();
+ return;
+ }
+
+ Curves *dst_curves_id = bke::curves_new_nomain(0, src_curves.curves_num());
+ bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
+ CurveComponent dst_component;
+ dst_component.replace(dst_curves_id, GeometryOwnershipType::Editable);
+ /* Directly copy curve attributes, since they stay the same (except for curve types). */
+ CustomData_copy(&src_curves.curve_data,
+ &dst_curves.curve_data,
+ CD_MASK_ALL,
+ CD_DUPLICATE,
+ src_curves.curves_num());
+
+ dst_curves.fill_curve_types(selection, dst_type);
+
+ switch (dst_type) {
+ case CURVE_TYPE_CATMULL_ROM:
+ case CURVE_TYPE_POLY:
+ /* Converting to Catmull Rom curves or poly curves should be handled
+ * above by the optimization to avoid changing the point count. */
+ BLI_assert_unreachable();
+ break;
+ case CURVE_TYPE_BEZIER:
+ convert_to_bezier(src_component, src_curves, selection, dst_component, dst_curves);
+ break;
+ case CURVE_TYPE_NURBS:
+ convert_to_nurbs(src_component, src_curves, selection, dst_component, dst_curves);
+ break;
+ }
+
+ geometry_set.replace_curves(dst_curves_id);
});
params.set_output("Curve", std::move(geometry_set));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index 5350896e93d..352411dd8f5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -8,10 +8,11 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
#include "node_geometry_util.hh"
@@ -38,19 +39,6 @@ static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> in
}
}
-/** Utility function for making an IndexMask from a boolean selection. The indices vector should
- * live at least as long as the returned IndexMask.
- */
-static IndexMask index_mask_indices(Span<bool> mask, const bool invert, Vector<int64_t> &indices)
-{
- for (const int i : mask.index_range()) {
- if (mask[i] != invert) {
- indices.append(i);
- }
- }
- return IndexMask(indices);
-}
-
/**
* Copies the attributes with a domain in `domains` to `result_component`.
*/
@@ -324,190 +312,56 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
}
}
-static void spline_copy_builtin_attributes(const Spline &spline,
- Spline &r_spline,
- const IndexMask mask)
-{
- copy_data_based_on_mask(spline.positions(), r_spline.positions(), mask);
- copy_data_based_on_mask(spline.radii(), r_spline.radii(), mask);
- copy_data_based_on_mask(spline.tilts(), r_spline.tilts(), mask);
- switch (spline.type()) {
- case CURVE_TYPE_POLY:
- break;
- case CURVE_TYPE_BEZIER: {
- const BezierSpline &src = static_cast<const BezierSpline &>(spline);
- BezierSpline &dst = static_cast<BezierSpline &>(r_spline);
- copy_data_based_on_mask(src.handle_positions_left(), dst.handle_positions_left(), mask);
- copy_data_based_on_mask(src.handle_positions_right(), dst.handle_positions_right(), mask);
- copy_data_based_on_mask(src.handle_types_left(), dst.handle_types_left(), mask);
- copy_data_based_on_mask(src.handle_types_right(), dst.handle_types_right(), mask);
- break;
- }
- case CURVE_TYPE_NURBS: {
- const NURBSpline &src = static_cast<const NURBSpline &>(spline);
- NURBSpline &dst = static_cast<NURBSpline &>(r_spline);
- copy_data_based_on_mask(src.weights(), dst.weights(), mask);
- break;
- }
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- break;
- }
- }
-}
-
-static void copy_dynamic_attributes(const CustomDataAttributes &src,
- CustomDataAttributes &dst,
- const IndexMask mask)
-{
- src.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src_attribute = src.get_for_read(attribute_id);
- BLI_assert(src_attribute);
-
- if (!dst.create(attribute_id, meta_data.data_type)) {
- /* Since the source spline of the same type had the attribute, adding it should work.
- */
- BLI_assert_unreachable();
- }
-
- std::optional<GMutableSpan> new_attribute = dst.get_for_write(attribute_id);
- BLI_assert(new_attribute);
-
- attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) {
- using T = decltype(dummy);
- copy_data_based_on_mask(src_attribute->typed<T>(), new_attribute->typed<T>(), mask);
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
-}
-
-/**
- * Deletes points in the spline. Those not in the mask are deleted. The spline is not split into
- * multiple newer splines.
- */
-static SplinePtr spline_delete(const Spline &spline, const IndexMask mask)
-{
- SplinePtr new_spline = spline.copy_only_settings();
- new_spline->resize(mask.size());
-
- spline_copy_builtin_attributes(spline, *new_spline, mask);
- copy_dynamic_attributes(spline.attributes, new_spline->attributes, mask);
-
- return new_spline;
-}
-
-static std::unique_ptr<CurveEval> curve_separate(const CurveEval &input_curve,
- const Span<bool> selection,
- const eAttrDomain selection_domain,
- const bool invert)
+static void delete_curves_selection(GeometrySet &geometry_set,
+ const Field<bool> &selection_field,
+ const eAttrDomain selection_domain)
{
- Span<SplinePtr> input_splines = input_curve.splines();
- std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
-
- /* Keep track of which splines were copied to the result to copy spline domain attributes. */
- Vector<int64_t> copied_splines;
-
- if (selection_domain == ATTR_DOMAIN_CURVE) {
- /* Operates on each of the splines as a whole, i.e. not on the points in the splines
- * themselves. */
- for (const int i : selection.index_range()) {
- if (selection[i] != invert) {
- output_curve->add_spline(input_splines[i]->copy());
- copied_splines.append(i);
- }
- }
- }
- else {
- /* Operates on the points in the splines themselves. */
-
- /* Reuse index vector for each spline. */
- Vector<int64_t> indices_to_copy;
-
- int selection_index = 0;
- for (const int i : input_splines.index_range()) {
- const Spline &spline = *input_splines[i];
-
- indices_to_copy.clear();
- for (const int i_point : IndexRange(spline.size())) {
- if (selection[selection_index] != invert) {
- /* Append i_point instead of selection_index because we need indices local to the spline
- * for copying. */
- indices_to_copy.append(i_point);
- }
- selection_index++;
- }
-
- /* Avoid creating an empty spline. */
- if (indices_to_copy.is_empty()) {
- continue;
- }
+ const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
+ GeometryComponentFieldContext field_context{src_component, selection_domain};
- SplinePtr new_spline = spline_delete(spline, IndexMask(indices_to_copy));
- output_curve->add_spline(std::move(new_spline));
- copied_splines.append(i);
- }
+ const int domain_num = src_component.attribute_domain_num(selection_domain);
+ fn::FieldEvaluator evaluator{field_context, domain_num};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
+ return;
}
-
- if (copied_splines.is_empty()) {
- return {};
+ if (selection.size() == domain_num) {
+ geometry_set.remove<CurveComponent>();
+ return;
}
- output_curve->attributes.reallocate(output_curve->splines().size());
- copy_dynamic_attributes(
- input_curve.attributes, output_curve->attributes, IndexMask(copied_splines));
-
- return output_curve;
-}
-
-static void separate_curve_selection(GeometrySet &geometry_set,
- const Field<bool> &selection_field,
- const eAttrDomain selection_domain,
- const bool invert)
-{
- const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
- GeometryComponentFieldContext field_context{src_component, selection_domain};
+ CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
+ Curves &curves_id = *component.get_for_write();
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- fn::FieldEvaluator selection_evaluator{field_context,
- src_component.attribute_domain_num(selection_domain)};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
- std::unique_ptr<CurveEval> r_curve = curve_separate(
- *curves_to_curve_eval(*src_component.get_for_read()), selection, selection_domain, invert);
- if (r_curve) {
- geometry_set.replace_curves(curve_eval_to_curves(*r_curve));
+ if (selection_domain == ATTR_DOMAIN_POINT) {
+ curves.remove_points(selection);
}
- else {
- geometry_set.replace_curves(nullptr);
+ else if (selection_domain == ATTR_DOMAIN_CURVE) {
+ curves.remove_curves(selection);
}
}
static void separate_point_cloud_selection(GeometrySet &geometry_set,
- const Field<bool> &selection_field,
- const bool invert)
+ const Field<bool> &selection_field)
{
const PointCloudComponent &src_points =
*geometry_set.get_component_for_read<PointCloudComponent>();
GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
- fn::FieldEvaluator selection_evaluator{field_context,
- src_points.attribute_domain_num(ATTR_DOMAIN_POINT)};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
-
- Vector<int64_t> indices;
- const IndexMask mask = index_mask_indices(selection, invert, indices);
- const int total = mask.size();
- PointCloud *pointcloud = BKE_pointcloud_new_nomain(total);
-
- if (total == 0) {
- geometry_set.replace_pointcloud(pointcloud);
+ fn::FieldEvaluator evaluator{field_context, src_points.attribute_domain_num(ATTR_DOMAIN_POINT)};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
+ geometry_set.replace_pointcloud(nullptr);
return;
}
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
+
PointCloudComponent dst_points;
dst_points.replace(pointcloud, GeometryOwnershipType::Editable);
@@ -515,36 +369,30 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set,
geometry_set.gather_attributes_for_propagation(
{GEO_COMPONENT_TYPE_POINT_CLOUD}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
- copy_attributes_based_on_mask(attributes, src_points, dst_points, ATTR_DOMAIN_POINT, mask);
+ copy_attributes_based_on_mask(attributes, src_points, dst_points, ATTR_DOMAIN_POINT, selection);
geometry_set.replace_pointcloud(pointcloud);
}
-static void separate_instance_selection(GeometrySet &geometry_set,
- const Field<bool> &selection_field,
- const bool invert)
+static void delete_selected_instances(GeometrySet &geometry_set,
+ const Field<bool> &selection_field)
{
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
- const int domain_num = instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
- evaluator.add(selection_field);
+ fn::FieldEvaluator evaluator{field_context,
+ instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE)};
+ evaluator.set_selection(selection_field);
evaluator.evaluate();
- const VArray_Span<bool> &selection = evaluator.get_evaluated<bool>(0);
-
- Vector<int64_t> indices;
- const IndexMask mask = index_mask_indices(selection, invert, indices);
-
- if (mask.is_empty()) {
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
geometry_set.remove<InstancesComponent>();
return;
}
- instances.remove_instances(mask);
+ instances.remove_instances(selection);
}
static void compute_selected_vertices_from_vertex_selection(const Span<bool> vertex_selection,
- const bool invert,
MutableSpan<int> r_vertex_map,
int *r_selected_vertices_num)
{
@@ -552,7 +400,7 @@ static void compute_selected_vertices_from_vertex_selection(const Span<bool> ver
int selected_verts_num = 0;
for (const int i : r_vertex_map.index_range()) {
- if (vertex_selection[i] != invert) {
+ if (vertex_selection[i]) {
r_vertex_map[i] = selected_verts_num;
selected_verts_num++;
}
@@ -566,7 +414,6 @@ static void compute_selected_vertices_from_vertex_selection(const Span<bool> ver
static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
const Span<bool> vertex_selection,
- const bool invert,
MutableSpan<int> r_edge_map,
int *r_selected_edges_num)
{
@@ -577,7 +424,7 @@ static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
const MEdge &edge = mesh.medge[i];
/* Only add the edge if both vertices will be in the new mesh. */
- if (vertex_selection[edge.v1] != invert && vertex_selection[edge.v2] != invert) {
+ if (vertex_selection[edge.v1] && vertex_selection[edge.v2]) {
r_edge_map[i] = selected_edges_num;
selected_edges_num++;
}
@@ -591,7 +438,6 @@ static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
const Span<bool> vertex_selection,
- const bool invert,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
int *r_selected_polys_num,
@@ -609,7 +455,7 @@ static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
bool all_verts_in_selection = true;
Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
for (const MLoop &loop : loops_src) {
- if (vertex_selection[loop.v] == invert) {
+ if (!vertex_selection[loop.v]) {
all_verts_in_selection = false;
break;
}
@@ -633,7 +479,6 @@ static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
static void compute_selected_vertices_and_edges_from_edge_selection(
const Mesh &mesh,
const Span<bool> edge_selection,
- const bool invert,
MutableSpan<int> r_vertex_map,
MutableSpan<int> r_edge_map,
int *r_selected_vertices_num,
@@ -645,7 +490,7 @@ static void compute_selected_vertices_and_edges_from_edge_selection(
int selected_verts_num = 0;
for (const int i : IndexRange(mesh.totedge)) {
const MEdge &edge = mesh.medge[i];
- if (edge_selection[i] != invert) {
+ if (edge_selection[i]) {
r_edge_map[i] = selected_edges_num;
selected_edges_num++;
if (r_vertex_map[edge.v1] == -1) {
@@ -671,7 +516,6 @@ static void compute_selected_vertices_and_edges_from_edge_selection(
*/
static void compute_selected_edges_from_edge_selection(const Mesh &mesh,
const Span<bool> edge_selection,
- const bool invert,
MutableSpan<int> r_edge_map,
int *r_selected_edges_num)
{
@@ -679,7 +523,7 @@ static void compute_selected_edges_from_edge_selection(const Mesh &mesh,
int selected_edges_num = 0;
for (const int i : IndexRange(mesh.totedge)) {
- if (edge_selection[i] != invert) {
+ if (edge_selection[i]) {
r_edge_map[i] = selected_edges_num;
selected_edges_num++;
}
@@ -697,7 +541,6 @@ static void compute_selected_edges_from_edge_selection(const Mesh &mesh,
*/
static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
const Span<bool> edge_selection,
- const bool invert,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
int *r_selected_polys_num,
@@ -713,7 +556,7 @@ static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
bool all_edges_in_selection = true;
Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
for (const MLoop &loop : loops_src) {
- if (edge_selection[loop.e] == invert) {
+ if (!edge_selection[loop.e]) {
all_edges_in_selection = false;
break;
}
@@ -736,7 +579,6 @@ static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
static void compute_selected_mesh_data_from_vertex_selection_edge_face(
const Mesh &mesh,
const Span<bool> vertex_selection,
- const bool invert,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
@@ -746,11 +588,10 @@ static void compute_selected_mesh_data_from_vertex_selection_edge_face(
{
compute_selected_edges_from_vertex_selection(
- mesh, vertex_selection, invert, r_edge_map, r_selected_edges_num);
+ mesh, vertex_selection, r_edge_map, r_selected_edges_num);
compute_selected_polygons_from_vertex_selection(mesh,
vertex_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -763,7 +604,6 @@ static void compute_selected_mesh_data_from_vertex_selection_edge_face(
*/
static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
const Span<bool> vertex_selection,
- const bool invert,
MutableSpan<int> r_vertex_map,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
@@ -774,14 +614,13 @@ static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
int *r_selected_loops_num)
{
compute_selected_vertices_from_vertex_selection(
- vertex_selection, invert, r_vertex_map, r_selected_vertices_num);
+ vertex_selection, r_vertex_map, r_selected_vertices_num);
compute_selected_edges_from_vertex_selection(
- mesh, vertex_selection, invert, r_edge_map, r_selected_edges_num);
+ mesh, vertex_selection, r_edge_map, r_selected_edges_num);
compute_selected_polygons_from_vertex_selection(mesh,
vertex_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -795,7 +634,6 @@ static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
static void compute_selected_mesh_data_from_edge_selection_edge_face(
const Mesh &mesh,
const Span<bool> edge_selection,
- const bool invert,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
@@ -804,10 +642,9 @@ static void compute_selected_mesh_data_from_edge_selection_edge_face(
int *r_selected_loops_num)
{
compute_selected_edges_from_edge_selection(
- mesh, edge_selection, invert, r_edge_map, r_selected_edges_num);
+ mesh, edge_selection, r_edge_map, r_selected_edges_num);
compute_selected_polygons_from_edge_selection(mesh,
edge_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -820,7 +657,6 @@ static void compute_selected_mesh_data_from_edge_selection_edge_face(
*/
static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
const Span<bool> edge_selection,
- const bool invert,
MutableSpan<int> r_vertex_map,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
@@ -833,14 +669,12 @@ static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
r_vertex_map.fill(-1);
compute_selected_vertices_and_edges_from_edge_selection(mesh,
edge_selection,
- invert,
r_vertex_map,
r_edge_map,
r_selected_vertices_num,
r_selected_edges_num);
compute_selected_polygons_from_edge_selection(mesh,
edge_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -852,7 +686,6 @@ static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
*/
static void compute_selected_polygons_from_poly_selection(const Mesh &mesh,
const Span<bool> poly_selection,
- const bool invert,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
int *r_selected_polys_num,
@@ -867,7 +700,7 @@ static void compute_selected_polygons_from_poly_selection(const Mesh &mesh,
for (const int i : IndexRange(mesh.totpoly)) {
const MPoly &poly_src = mesh.mpoly[i];
/* We keep this one. */
- if (poly_selection[i] != invert) {
+ if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
r_loop_starts.append_unchecked(selected_loops_num);
selected_loops_num += poly_src.totloop;
@@ -883,7 +716,6 @@ static void compute_selected_polygons_from_poly_selection(const Mesh &mesh,
static void compute_selected_mesh_data_from_poly_selection_edge_face(
const Mesh &mesh,
const Span<bool> poly_selection,
- const bool invert,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
@@ -903,7 +735,7 @@ static void compute_selected_mesh_data_from_poly_selection_edge_face(
for (const int i : IndexRange(mesh.totpoly)) {
const MPoly &poly_src = mesh.mpoly[i];
/* We keep this one. */
- if (poly_selection[i] != invert) {
+ if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
r_loop_starts.append_unchecked(selected_loops_num);
selected_loops_num += poly_src.totloop;
@@ -930,7 +762,6 @@ static void compute_selected_mesh_data_from_poly_selection_edge_face(
*/
static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
const Span<bool> poly_selection,
- const bool invert,
MutableSpan<int> r_vertex_map,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
@@ -954,7 +785,7 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
for (const int i : IndexRange(mesh.totpoly)) {
const MPoly &poly_src = mesh.mpoly[i];
/* We keep this one. */
- if (poly_selection[i] != invert) {
+ if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
r_loop_starts.append_unchecked(selected_loops_num);
selected_loops_num += poly_src.totloop;
@@ -985,8 +816,7 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
*/
static void do_mesh_separation(GeometrySet &geometry_set,
const MeshComponent &in_component,
- const VArray_Span<bool> &selection,
- const bool invert,
+ const Span<bool> selection,
const eAttrDomain domain,
const GeometryNodeDeleteGeometryMode mode)
{
@@ -1017,7 +847,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_POINT:
compute_selected_mesh_data_from_vertex_selection(mesh_in,
selection,
- invert,
vertex_map,
edge_map,
selected_poly_indices,
@@ -1030,7 +859,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_EDGE:
compute_selected_mesh_data_from_edge_selection(mesh_in,
selection,
- invert,
vertex_map,
edge_map,
selected_poly_indices,
@@ -1043,7 +871,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_FACE:
compute_selected_mesh_data_from_poly_selection(mesh_in,
selection,
- invert,
vertex_map,
edge_map,
selected_poly_indices,
@@ -1098,7 +925,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_POINT:
compute_selected_mesh_data_from_vertex_selection_edge_face(mesh_in,
selection,
- invert,
edge_map,
selected_poly_indices,
new_loop_starts,
@@ -1109,7 +935,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_EDGE:
compute_selected_mesh_data_from_edge_selection_edge_face(mesh_in,
selection,
- invert,
edge_map,
selected_poly_indices,
new_loop_starts,
@@ -1120,7 +945,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_FACE:
compute_selected_mesh_data_from_poly_selection_edge_face(mesh_in,
selection,
- invert,
edge_map,
selected_poly_indices,
new_loop_starts,
@@ -1169,7 +993,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_POINT:
compute_selected_polygons_from_vertex_selection(mesh_in,
selection,
- invert,
selected_poly_indices,
new_loop_starts,
&selected_polys_num,
@@ -1178,7 +1001,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_EDGE:
compute_selected_polygons_from_edge_selection(mesh_in,
selection,
- invert,
selected_poly_indices,
new_loop_starts,
&selected_polys_num,
@@ -1187,7 +1009,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_FACE:
compute_selected_polygons_from_poly_selection(mesh_in,
selection,
- invert,
selected_poly_indices,
new_loop_starts,
&selected_polys_num,
@@ -1231,31 +1052,24 @@ static void do_mesh_separation(GeometrySet &geometry_set,
static void separate_mesh_selection(GeometrySet &geometry_set,
const Field<bool> &selection_field,
const eAttrDomain selection_domain,
- const GeometryNodeDeleteGeometryMode mode,
- const bool invert)
+ const GeometryNodeDeleteGeometryMode mode)
{
const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
GeometryComponentFieldContext field_context{src_component, selection_domain};
- fn::FieldEvaluator selection_evaluator{field_context,
- src_component.attribute_domain_num(selection_domain)};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
-
+ fn::FieldEvaluator evaluator{field_context,
+ src_component.attribute_domain_num(selection_domain)};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+ const VArray<bool> selection = evaluator.get_evaluated<bool>(0);
/* Check if there is anything to delete. */
- bool delete_nothing = true;
- for (const int i : selection.index_range()) {
- if (selection[i] == invert) {
- delete_nothing = false;
- break;
- }
- }
- if (delete_nothing) {
+ if (selection.is_single() && selection.get_internal_single()) {
return;
}
- do_mesh_separation(geometry_set, src_component, selection, invert, selection_domain, mode);
+ const VArray_Span<bool> selection_span{selection};
+
+ do_mesh_separation(geometry_set, src_component, selection_span, selection_domain, mode);
}
} // namespace blender::nodes::node_geo_delete_geometry_cc
@@ -1266,7 +1080,6 @@ void separate_geometry(GeometrySet &geometry_set,
const eAttrDomain domain,
const GeometryNodeDeleteGeometryMode mode,
const Field<bool> &selection_field,
- const bool invert,
bool &r_is_error)
{
namespace file_ns = blender::nodes::node_geo_delete_geometry_cc;
@@ -1274,25 +1087,26 @@ void separate_geometry(GeometrySet &geometry_set,
bool some_valid_domain = false;
if (geometry_set.has_pointcloud()) {
if (domain == ATTR_DOMAIN_POINT) {
- file_ns::separate_point_cloud_selection(geometry_set, selection_field, invert);
+ file_ns::separate_point_cloud_selection(geometry_set, selection_field);
some_valid_domain = true;
}
}
if (geometry_set.has_mesh()) {
if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER)) {
- file_ns::separate_mesh_selection(geometry_set, selection_field, domain, mode, invert);
+ file_ns::separate_mesh_selection(geometry_set, selection_field, domain, mode);
some_valid_domain = true;
}
}
if (geometry_set.has_curves()) {
if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) {
- file_ns::separate_curve_selection(geometry_set, selection_field, domain, invert);
+ file_ns::delete_curves_selection(
+ geometry_set, fn::invert_boolean_field(selection_field), domain);
some_valid_domain = true;
}
}
if (geometry_set.has_instances()) {
if (domain == ATTR_DOMAIN_INSTANCE) {
- file_ns::separate_instance_selection(geometry_set, selection_field, invert);
+ file_ns::delete_selected_instances(geometry_set, selection_field);
some_valid_domain = true;
}
}
@@ -1342,7 +1156,11 @@ static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ /* The node's input is a selection of elements that should be deleted, but the code is
+ * implemented as a separation operation that copies the selected elements to a new geometry.
+ * Invert the selection to avoid the need to keep track of both cases in the code. */
+ const Field<bool> selection = fn::invert_boolean_field(
+ params.extract_input<Field<bool>>("Selection"));
const NodeGeometryDeleteGeometry &storage = node_storage(params.node());
const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
@@ -1350,13 +1168,13 @@ static void node_geo_exec(GeoNodeExecParams params)
if (domain == ATTR_DOMAIN_INSTANCE) {
bool is_error;
- separate_geometry(geometry_set, domain, mode, selection_field, true, is_error);
+ separate_geometry(geometry_set, domain, mode, selection, is_error);
}
else {
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
bool is_error;
/* Invert here because we want to keep the things not in the selection. */
- separate_geometry(geometry_set, domain, mode, selection_field, true, is_error);
+ separate_geometry(geometry_set, domain, mode, selection, is_error);
});
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
index cde40319388..691f341b518 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -98,7 +98,7 @@ static void threaded_slice_fill(Span<int> offsets,
MutableSpan<T> dst)
{
BLI_assert(offsets.last() == dst.size());
- BLI_assert(selection.size() == offsets.size());
+ BLI_assert(selection.size() == offsets.size() - 1);
threading::parallel_for(IndexRange(offsets.size() - 1), 512, [&](IndexRange range) {
for (const int i : range) {
dst.slice(range_for_offsets_index(offsets, i)).fill(src[selection[i]]);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
index 25c7840d633..3eca92e37a3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -145,6 +145,34 @@ static void expand_mesh(Mesh &mesh,
BKE_mesh_update_customdata_pointers(&mesh, false);
}
+static CustomData &get_customdata(Mesh &mesh, const eAttrDomain domain)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return mesh.vdata;
+ case ATTR_DOMAIN_EDGE:
+ return mesh.edata;
+ case ATTR_DOMAIN_FACE:
+ return mesh.pdata;
+ case ATTR_DOMAIN_CORNER:
+ return mesh.ldata;
+ default:
+ BLI_assert_unreachable();
+ return mesh.vdata;
+ }
+}
+
+static MutableSpan<int> get_orig_index_layer(Mesh &mesh, const eAttrDomain domain)
+{
+ MeshComponent component;
+ component.replace(&mesh, GeometryOwnershipType::ReadOnly);
+ CustomData &custom_data = get_customdata(mesh, domain);
+ if (int *orig_indices = static_cast<int *>(CustomData_get_layer(&custom_data, CD_ORIGINDEX))) {
+ return {orig_indices, component.attribute_domain_num(domain)};
+ }
+ return {};
+}
+
static MEdge new_edge(const int v1, const int v2)
{
MEdge edge;
@@ -292,6 +320,9 @@ static void extrude_mesh_vertices(MeshComponent &component,
});
});
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
if (attribute_outputs.top_id) {
save_selection_as_attribute(
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range);
@@ -615,6 +646,13 @@ static void extrude_mesh_edges(MeshComponent &component,
});
}
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE);
+ edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(duplicate_edge_range).fill(ORIGINDEX_NONE);
+
if (attribute_outputs.top_id) {
save_selection_as_attribute(
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range);
@@ -983,6 +1021,17 @@ static void extrude_mesh_face_regions(MeshComponent &component,
});
}
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE);
+ edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(new_inner_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(boundary_edge_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> poly_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_FACE);
+ poly_orig_indices.slice(side_poly_range).fill(ORIGINDEX_NONE);
+
if (attribute_outputs.top_id) {
save_selection_as_attribute(
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
@@ -1232,6 +1281,16 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
}
});
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE);
+ edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(duplicate_edge_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> poly_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_FACE);
+ poly_orig_indices.slice(side_poly_range).fill(ORIGINDEX_NONE);
+
/* Finally update each extruded polygon's loops to point to the new edges and vertices.
* This must be done last, because they were used to find original indices for attribute
* interpolation before. Alternatively an original index array could be built for each domain. */
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
new file mode 100644
index 00000000000..4c7a148a797
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_instance_rotation_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Rotation")).field_source();
+}
+
+class VectorFieldInput final : public GeometryFieldInput {
+ public:
+ VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Rotation")
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const eAttrDomain UNUSED(domain),
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) {
+ return {};
+ }
+
+ const InstancesComponent &instance_component = static_cast<const InstancesComponent &>(
+ component);
+
+ auto rotation_fn = [&](const int i) -> float3 {
+ return instance_component.instance_transforms()[i].to_euler();
+ };
+
+ return VArray<float3>::ForFunc(instance_component.instances_num(), rotation_fn);
+ }
+
+ uint64_t hash() const override
+ {
+ return 22374372;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VectorFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<float3> rotation{std::make_shared<VectorFieldInput>()};
+ params.set_output("Rotation", std::move(rotation));
+}
+
+} // namespace blender::nodes::node_geo_input_instance_rotation_cc
+
+void register_node_type_geo_input_instance_rotation()
+{
+ namespace file_ns = blender::nodes::node_geo_input_instance_rotation_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_INSTANCE_ROTATION, "Instance Rotation", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
new file mode 100644
index 00000000000..b3a362fbf3e
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_instance_scale_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Scale")).field_source();
+}
+
+class VectorFieldInput final : public GeometryFieldInput {
+ public:
+ VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Scale")
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const eAttrDomain UNUSED(domain),
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) {
+ return {};
+ }
+
+ const InstancesComponent &instance_component = static_cast<const InstancesComponent &>(
+ component);
+
+ auto scale_fn = [&](const int i) -> float3 {
+ return instance_component.instance_transforms()[i].scale();
+ };
+
+ return VArray<float3>::ForFunc(instance_component.instances_num(), scale_fn);
+ }
+
+ uint64_t hash() const override
+ {
+ return 8346343;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VectorFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<float3> scale{std::make_shared<VectorFieldInput>()};
+ params.set_output("Scale", std::move(scale));
+}
+
+} // namespace blender::nodes::node_geo_input_instance_scale_cc
+
+void register_node_type_geo_input_instance_scale()
+{
+ namespace file_ns = blender::nodes::node_geo_input_instance_scale_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_INSTANCE_SCALE, "Instance Scale", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
index c400760f902..532c3dc81e5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
@@ -65,7 +65,7 @@ class PlanarFieldInput final : public GeometryFieldInput {
float3 reference_normal = poly_normals[i_poly];
float min = FLT_MAX;
- float max = FLT_MIN;
+ float max = -FLT_MAX;
for (const int i_loop : poly_loops.index_range()) {
const float3 vert = mesh->mvert[poly_loops[i_loop].v].co;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
index 22712c873a3..d785694f253 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -45,36 +45,29 @@ static void node_geo_exec(GeoNodeExecParams params)
const NodeGeometrySeparateGeometry &storage = node_storage(params.node());
const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
- auto separate_geometry_maybe_recursively = [&](GeometrySet &geometry_set, bool invert) {
+ auto separate_geometry_maybe_recursively = [&](GeometrySet &geometry_set,
+ const Field<bool> &selection) {
bool is_error;
if (domain == ATTR_DOMAIN_INSTANCE) {
/* Only delete top level instances. */
- separate_geometry(geometry_set,
- domain,
- GEO_NODE_DELETE_GEOMETRY_MODE_ALL,
- selection_field,
- invert,
- is_error);
+ separate_geometry(
+ geometry_set, domain, GEO_NODE_DELETE_GEOMETRY_MODE_ALL, selection, is_error);
}
else {
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- separate_geometry(geometry_set,
- domain,
- GEO_NODE_DELETE_GEOMETRY_MODE_ALL,
- selection_field,
- invert,
- is_error);
+ separate_geometry(
+ geometry_set, domain, GEO_NODE_DELETE_GEOMETRY_MODE_ALL, selection, is_error);
});
}
};
GeometrySet second_set(geometry_set);
if (params.output_is_required("Selection")) {
- separate_geometry_maybe_recursively(geometry_set, false);
+ separate_geometry_maybe_recursively(geometry_set, selection_field);
params.set_output("Selection", std::move(geometry_set));
}
if (params.output_is_required("Inverted")) {
- separate_geometry_maybe_recursively(second_set, true);
+ separate_geometry_maybe_recursively(second_set, fn::invert_boolean_field(selection_field));
params.set_output("Inverted", std::move(second_set));
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
new file mode 100644
index 00000000000..d7e9e38ea0d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+# include <openvdb/tools/Dense.h>
+# include <openvdb/tools/LevelSetUtil.h>
+# include <openvdb/tools/ParticlesToLevelSet.h>
+#endif
+
+#include "node_geometry_util.hh"
+
+#include "DNA_mesh_types.h"
+
+#include "BLI_task.hh"
+
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_volume.h"
+
+namespace blender::nodes::node_geo_volume_cube_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Density"))
+ .description(N_("Volume density per voxel"))
+ .supports_field()
+ .default_value(1.0f);
+ b.add_input<decl::Float>(N_("Background"))
+ .description(N_("Value for voxels outside of the cube"));
+
+ b.add_input<decl::Vector>(N_("Min"))
+ .description(N_("Minimum boundary of volume"))
+ .default_value(float3(-1.0f));
+ b.add_input<decl::Vector>(N_("Max"))
+ .description(N_("Maximum boundary of volume"))
+ .default_value(float3(1.0f));
+
+ b.add_input<decl::Int>(N_("Resolution X"))
+ .description(N_("Number of voxels in the X axis"))
+ .default_value(32)
+ .min(2);
+ b.add_input<decl::Int>(N_("Resolution Y"))
+ .description(N_("Number of voxels in the Y axis"))
+ .default_value(32)
+ .min(2);
+ b.add_input<decl::Int>(N_("Resolution Z"))
+ .description(N_("Number of voxels in the Z axis"))
+ .default_value(32)
+ .min(2);
+
+ b.add_output<decl::Geometry>(N_("Volume"));
+}
+
+static float map(const float x,
+ const float in_min,
+ const float in_max,
+ const float out_min,
+ const float out_max)
+{
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+class Grid3DFieldContext : public FieldContext {
+ private:
+ int3 resolution_;
+ float3 bounds_min_;
+ float3 bounds_max_;
+
+ public:
+ Grid3DFieldContext(const int3 resolution, const float3 bounds_min, const float3 bounds_max)
+ : resolution_(resolution), bounds_min_(bounds_min), bounds_max_(bounds_max)
+ {
+ }
+
+ int64_t points_num() const
+ {
+ return static_cast<int64_t>(resolution_.x) * static_cast<int64_t>(resolution_.y) *
+ static_cast<int64_t>(resolution_.z);
+ }
+
+ GVArray get_varray_for_input(const FieldInput &field_input,
+ const IndexMask UNUSED(mask),
+ ResourceScope &UNUSED(scope)) const
+ {
+ const bke::AttributeFieldInput *attribute_field_input =
+ dynamic_cast<const bke::AttributeFieldInput *>(&field_input);
+ if (attribute_field_input == nullptr) {
+ return {};
+ }
+ if (attribute_field_input->attribute_name() != "position") {
+ return {};
+ }
+
+ Array<float3> positions(this->points_num());
+
+ threading::parallel_for(IndexRange(resolution_.x), 1, [&](const IndexRange x_range) {
+ /* Start indexing at current X slice. */
+ int64_t index = x_range.start() * resolution_.y * resolution_.z;
+ for (const int64_t x_i : x_range) {
+ const float x = map(x_i, 0.0f, resolution_.x - 1, bounds_min_.x, bounds_max_.x);
+ for (const int64_t y_i : IndexRange(resolution_.y)) {
+ const float y = map(y_i, 0.0f, resolution_.y - 1, bounds_min_.y, bounds_max_.y);
+ for (const int64_t z_i : IndexRange(resolution_.z)) {
+ const float z = map(z_i, 0.0f, resolution_.z - 1, bounds_min_.z, bounds_max_.z);
+ positions[index] = float3(x, y, z);
+ index++;
+ }
+ }
+ }
+ });
+ return VArray<float3>::ForContainer(std::move(positions));
+ }
+};
+
+#ifdef WITH_OPENVDB
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const float3 bounds_min = params.extract_input<float3>("Min");
+ const float3 bounds_max = params.extract_input<float3>("Max");
+
+ const int3 resolution = int3(params.extract_input<int>("Resolution X"),
+ params.extract_input<int>("Resolution Y"),
+ params.extract_input<int>("Resolution Z"));
+
+ if (resolution.x < 2 || resolution.y < 2 || resolution.z < 2) {
+ params.error_message_add(NodeWarningType::Error, TIP_("Resolution must be greater than 1"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ if (bounds_min.x == bounds_max.x || bounds_min.y == bounds_max.y ||
+ bounds_min.z == bounds_max.z) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Bounding box volume must be greater than 0"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ Field<float> input_field = params.extract_input<Field<float>>("Density");
+
+ /* Evaluate input field on a 3D grid. */
+ Grid3DFieldContext context(resolution, bounds_min, bounds_max);
+ FieldEvaluator evaluator(context, context.points_num());
+ Array<float> densities(context.points_num());
+ evaluator.add_with_destination(std::move(input_field), densities.as_mutable_span());
+ evaluator.evaluate();
+
+ /* Store resulting values in openvdb grid. */
+ const float background = params.extract_input<float>("Background");
+ openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(background);
+ grid->setGridClass(openvdb::GRID_FOG_VOLUME);
+
+ openvdb::tools::Dense<float, openvdb::tools::LayoutZYX> dense_grid{
+ openvdb::math::CoordBBox({0, 0, 0}, {resolution.x - 1, resolution.y - 1, resolution.z - 1}),
+ densities.data()};
+ openvdb::tools::copyFromDense(dense_grid, *grid, 0.0f);
+
+ grid->transform().preTranslate(openvdb::math::Vec3<float>(-0.5f));
+ const float3 scale_fac = (bounds_max - bounds_min) / float3(resolution - 1);
+ grid->transform().postScale(openvdb::math::Vec3<float>(scale_fac.x, scale_fac.y, scale_fac.z));
+ grid->transform().postTranslate(
+ openvdb::math::Vec3<float>(bounds_min.x, bounds_min.y, bounds_min.z));
+
+ Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
+ BKE_volume_init_grids(volume);
+
+ BKE_volume_grid_add_vdb(*volume, "density", std::move(grid));
+
+ GeometrySet r_geometry_set;
+ r_geometry_set.replace_volume(volume);
+ params.set_output("Volume", r_geometry_set);
+}
+
+#else
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenVDB"));
+ params.set_default_remaining_outputs();
+}
+#endif /* WITH_OPENVDB */
+
+} // namespace blender::nodes::node_geo_volume_cube_cc
+
+void register_node_type_geo_volume_cube()
+{
+ namespace file_ns = blender::nodes::node_geo_volume_cube_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_VOLUME_CUBE, "Volume Cube", NODE_CLASS_GEOMETRY);
+
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index e5827c24320..8770fa2b74b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -41,7 +41,9 @@ static void node_declare(NodeDeclarationBuilder &b)
.make_available([](bNode &node) {
node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT;
});
- b.add_input<decl::Float>(N_("Threshold")).default_value(0.1f).min(0.0f);
+ b.add_input<decl::Float>(N_("Threshold"))
+ .default_value(0.1f)
+ .description(N_("Values larger than the threshold are inside the generated mesh"));
b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
b.add_output<decl::Geometry>(N_("Mesh"));
}
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index 27ad12ba252..56e9c9f0496 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -110,137 +110,6 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name
return nullptr;
}
-GVArray GeoNodeExecParams::get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const eAttrDomain domain,
- const eCustomDataType type,
- const void *default_value) const
-{
- const bNodeSocket *found_socket = this->find_available_socket(name);
- BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
- const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type);
- const int64_t domain_num = component.attribute_domain_num(domain);
-
- if (default_value == nullptr) {
- default_value = cpp_type->default_value();
- }
-
- if (found_socket == nullptr) {
- return GVArray::ForSingle(*cpp_type, domain_num, default_value);
- }
-
- if (found_socket->type == SOCK_STRING) {
- const std::string name = this->get_input<std::string>(found_socket->identifier);
- /* Try getting the attribute without the default value. */
- GVArray attribute = component.attribute_try_get_for_read(name, domain, type);
- if (attribute) {
- return attribute;
- }
-
- /* If the attribute doesn't exist, use the default value and output an error message
- * (except when the field is empty, to avoid spamming error messages, and not when
- * the domain is empty and we don't expect an attribute anyway). */
- if (!name.empty() && component.attribute_domain_num(domain) != 0) {
- this->error_message_add(NodeWarningType::Error,
- TIP_("No attribute with name \"") + name + "\"");
- }
- return GVArray::ForSingle(*cpp_type, domain_num, default_value);
- }
- const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
- if (found_socket->type == SOCK_FLOAT) {
- const float value = this->get_input<float>(found_socket->identifier);
- BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
- conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer);
- return GVArray::ForSingle(*cpp_type, domain_num, buffer);
- }
- if (found_socket->type == SOCK_INT) {
- const int value = this->get_input<int>(found_socket->identifier);
- BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
- conversions.convert_to_uninitialized(CPPType::get<int>(), *cpp_type, &value, buffer);
- return GVArray::ForSingle(*cpp_type, domain_num, buffer);
- }
- if (found_socket->type == SOCK_VECTOR) {
- const float3 value = this->get_input<float3>(found_socket->identifier);
- BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
- conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer);
- return GVArray::ForSingle(*cpp_type, domain_num, buffer);
- }
- if (found_socket->type == SOCK_RGBA) {
- const ColorGeometry4f value = this->get_input<ColorGeometry4f>(found_socket->identifier);
- BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
- conversions.convert_to_uninitialized(
- CPPType::get<ColorGeometry4f>(), *cpp_type, &value, buffer);
- return GVArray::ForSingle(*cpp_type, domain_num, buffer);
- }
- BLI_assert(false);
- return GVArray::ForSingle(*cpp_type, domain_num, default_value);
-}
-
-eCustomDataType GeoNodeExecParams::get_input_attribute_data_type(
- const StringRef name,
- const GeometryComponent &component,
- const eCustomDataType default_type) const
-{
- const bNodeSocket *found_socket = this->find_available_socket(name);
- BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
- if (found_socket == nullptr) {
- return default_type;
- }
-
- if (found_socket->type == SOCK_STRING) {
- const std::string name = this->get_input<std::string>(found_socket->identifier);
- std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name);
- if (info) {
- return info->data_type;
- }
- return default_type;
- }
- if (found_socket->type == SOCK_FLOAT) {
- return CD_PROP_FLOAT;
- }
- if (found_socket->type == SOCK_VECTOR) {
- return CD_PROP_FLOAT3;
- }
- if (found_socket->type == SOCK_RGBA) {
- return CD_PROP_COLOR;
- }
- if (found_socket->type == SOCK_BOOLEAN) {
- return CD_PROP_BOOL;
- }
-
- BLI_assert(false);
- return default_type;
-}
-
-eAttrDomain GeoNodeExecParams::get_highest_priority_input_domain(
- Span<std::string> names,
- const GeometryComponent &component,
- const eAttrDomain default_domain) const
-{
- Vector<eAttrDomain, 8> input_domains;
- for (const std::string &name : names) {
- const bNodeSocket *found_socket = this->find_available_socket(name);
- BLI_assert(found_socket != nullptr); /* A socket should be available socket for the name. */
- if (found_socket == nullptr) {
- continue;
- }
-
- if (found_socket->type == SOCK_STRING) {
- const std::string name = this->get_input<std::string>(found_socket->identifier);
- std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name);
- if (info) {
- input_domains.append(info->domain);
- }
- }
- }
-
- if (input_domains.size() > 0) {
- return bke::attribute_domain_highest_priority(input_domains);
- }
-
- return default_domain;
-}
-
std::string GeoNodeExecParams::attribute_producer_name() const
{
return provider_->dnode->label_or_name() + TIP_(" node");
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 8179daa8e03..71138134370 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -310,6 +310,18 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_IO_WAVEFRONT_OBJ)
+ add_definitions(-DWITH_IO_WAVEFRONT_OBJ)
+endif()
+
+if(WITH_IO_STL)
+ add_definitions(-DWITH_IO_STL)
+endif()
+
+if(WITH_IO_GPENCIL)
+ add_definitions(-DWITH_IO_GPENCIL)
+endif()
+
if(WITH_ALEMBIC)
add_definitions(-DWITH_ALEMBIC)
endif()
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 621cc79a8db..939473ceaa0 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -36,15 +36,19 @@
#include "BKE_appdir.h"
#include "BKE_blender_version.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "DNA_ID.h"
#include "UI_interface_icons.h"
+#include "RNA_enum_types.h" /* For `rna_enum_wm_job_type_items`. */
+
/* for notifiers */
#include "WM_api.h"
#include "WM_types.h"
+#include "../generic/py_capi_rna.h"
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
@@ -450,6 +454,44 @@ static PyGetSetDef bpy_app_getsets[] = {
{NULL, NULL, NULL, NULL, NULL},
};
+PyDoc_STRVAR(bpy_app_is_job_running_doc,
+ ".. staticmethod:: is_job_running(job_type)\n"
+ "\n"
+ " Check whether a job of the given type is running.\n"
+ "\n"
+ " :arg job_type: job type in :ref:`rna_enum_wm_job_type_items`.\n"
+ " :type job_type: str\n"
+ " :return: Whether a job of the given type is currently running.\n"
+ " :rtype: bool.\n");
+static PyObject *bpy_app_is_job_running(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+{
+ struct BPy_EnumProperty_Parse job_type_enum = {
+ .items = rna_enum_wm_job_type_items,
+ .value = 0,
+ };
+ static const char *_keywords[] = {"job_type", NULL};
+ static _PyArg_Parser _parser = {
+ "O&" /* `job_type` */
+ ":is_job_running",
+ _keywords,
+ 0,
+ };
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser, pyrna_enum_value_parse_string, &job_type_enum)) {
+ return NULL;
+ }
+ wmWindowManager *wm = G_MAIN->wm.first;
+ return PyBool_FromLong(WM_jobs_has_running_type(wm, job_type_enum.value));
+}
+
+static struct PyMethodDef bpy_app_methods[] = {
+ {"is_job_running",
+ (PyCFunction)bpy_app_is_job_running,
+ METH_VARARGS | METH_KEYWORDS | METH_STATIC,
+ bpy_app_is_job_running_doc},
+ {NULL, NULL, 0, NULL},
+};
+
static void py_struct_seq_getset_init(void)
{
/* tricky dynamic members, not to py-spec! */
@@ -459,6 +501,17 @@ static void py_struct_seq_getset_init(void)
Py_DECREF(item);
}
}
+
+static void py_struct_seq_method_init(void)
+{
+ for (PyMethodDef *method = bpy_app_methods; method->ml_name; method++) {
+ BLI_assert_msg(method->ml_flags & METH_STATIC, "Only static methods make sense for 'bpy.app'");
+ PyObject *item = PyCFunction_New(method, NULL);
+ PyDict_SetItemString(BlenderAppType.tp_dict, method->ml_name, item);
+ Py_DECREF(item);
+ }
+}
+
/* end dynamic bpy.app */
PyObject *BPY_app_struct(void)
@@ -477,6 +530,7 @@ PyObject *BPY_app_struct(void)
/* kindof a hack ontop of PyStructSequence */
py_struct_seq_getset_init();
+ py_struct_seq_method_init();
return ret;
}
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index beb78753406..fe5111c37f2 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -43,6 +43,9 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{"mod_oceansim", NULL},
{"mod_remesh", NULL},
{"collada", NULL},
+ {"io_wavefront_obj", NULL},
+ {"io_stl", NULL},
+ {"io_gpencil", NULL},
{"opencolorio", NULL},
{"openmp", NULL},
{"openvdb", NULL},
@@ -251,6 +254,24 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_IO_WAVEFRONT_OBJ
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_IO_STL
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_IO_GPENCIL
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#ifdef WITH_OCIO
SetObjIncref(Py_True);
#else
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index bf427d9639a..641727927ec 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -66,6 +66,12 @@ static PyStructSequence_Field app_cb_info_fields[] = {
{"xr_session_start_pre", "on starting an xr session (before)"},
{"annotation_pre", "on drawing an annotation (before)"},
{"annotation_post", "on drawing an annotation (after)"},
+ {"object_bake_pre", "before starting a bake job"},
+ {"object_bake_complete", "on completing a bake job; will be called in the main thread"},
+ {"object_bake_cancel", "on canceling a bake job; will be called in the main thread"},
+ {"composite_pre", "on a compositing background job (before)"},
+ {"composite_post", "on a compositing background job (after)"},
+ {"composite_cancel", "on a compositing background job (cancel)"},
/* sets the permanent tag */
#define APP_CB_OTHER_FIELDS 1
diff --git a/source/blender/python/intern/bpy_traceback.c b/source/blender/python/intern/bpy_traceback.c
index 45977ba400c..cb93843a6de 100644
--- a/source/blender/python/intern/bpy_traceback.c
+++ b/source/blender/python/intern/bpy_traceback.c
@@ -165,7 +165,7 @@ finally:
bool python_script_error_jump(
const char *filepath, int *r_lineno, int *r_offset, int *r_lineno_end, int *r_offset_end)
{
- /* WARNING(@campbellbarton): The normalized exception is restored (loosing line number info).
+ /* WARNING(@campbellbarton): The normalized exception is restored (losing line number info).
* Ideally this would leave the exception state as it found it, but that needs to be done
* carefully with regards to reference counting, see: T97731. */
diff --git a/source/blender/python/rna_dump.py b/source/blender/python/rna_dump.py
index 61df784336c..b4e23547c62 100644
--- a/source/blender/python/rna_dump.py
+++ b/source/blender/python/rna_dump.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
if 1:
# Print once every 1000
GEN_PATH = True
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index 39820603c98..548e38d3ef3 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -74,10 +74,12 @@ typedef struct RenderPass {
int pad;
} RenderPass;
-/* a renderlayer is a full image, but with all passes and samples */
-/* size of the rects is defined in RenderResult */
-/* after render, the Combined pass is in combined,
- * for renderlayers read from files it is a real pass */
+/**
+ * - A render-layer is a full image, but with all passes and samples.
+ * - The size of the rects is defined in #RenderResult.
+ * - After render, the Combined pass is in combined,
+ * for render-layers read from files it is a real pass.
+ */
typedef struct RenderLayer {
struct RenderLayer *next, *prev;
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index 43497fb8318..075f1ece647 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -981,7 +981,7 @@ static void render_result_uncrop(Render *re)
render_result_free(re->result);
re->result = rres;
- /* weak... the display callback wants an active renderlayer pointer... */
+ /* Weak, the display callback wants an active render-layer pointer. */
re->result->renlay = render_get_active_layer(re, re->result);
BLI_rw_mutex_unlock(&re->resultmutex);
@@ -1313,8 +1313,8 @@ static void do_render_sequencer(Render *re)
true,
&context);
- /* the renderresult gets destroyed during the rendering, so we first collect all ibufs
- * and then we populate the final renderesult */
+ /* The render-result gets destroyed during the rendering, so we first collect all ibufs
+ * and then we populate the final render-result. */
for (view_id = 0; view_id < tot_views; view_id++) {
context.view_id = view_id;
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index 9f4aa642773..9992d1a507f 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -825,7 +825,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
if (rpass->rect == NULL || rpassp->rect == NULL) {
continue;
}
- /* Renderresult have all passes, renderpart only the active view's passes. */
+ /* Render-result have all passes, render-part only the active view's passes. */
if (!STREQ(rpassp->fullname, rpass->fullname)) {
continue;
}
diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h
index 30f49775562..c84e0a04018 100644
--- a/source/blender/render/intern/render_result.h
+++ b/source/blender/render/intern/render_result.h
@@ -44,7 +44,7 @@ struct RenderResult *render_result_new(struct Render *re,
void render_result_passes_allocated_ensure(struct RenderResult *rr);
/**
- * From imbuf, if a handle was returned and
+ * From `imbuf`, if a handle was returned and
* it's not a single-layer multi-view we convert this to render result.
*/
struct RenderResult *render_result_new_from_exr(
diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h
index 93ce6873d3b..31a7399f844 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -46,6 +46,7 @@ bool SEQ_transform_seqbase_shuffle(struct ListBase *seqbasep,
struct Sequence *test,
struct Scene *evil_scene);
bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
+ struct SeqCollection *time_dependent_strips,
struct ListBase *seqbasep,
struct Scene *evil_scene,
struct ListBase *markers,
@@ -54,6 +55,7 @@ bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
void SEQ_transform_handle_overlap(struct Scene *scene,
struct ListBase *seqbasep,
struct SeqCollection *transformed_strips,
+ struct SeqCollection *time_dependent_strips,
bool use_sync_markers);
/**
* Check if the selected seq's reference unselected seq's.
diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c
index 59de24930d6..47306dbbc6c 100644
--- a/source/blender/sequencer/intern/image_cache.c
+++ b/source/blender/sequencer/intern/image_cache.c
@@ -640,13 +640,8 @@ void seq_cache_cleanup_sequence(Scene *scene,
int range_end = SEQ_time_right_handle_frame_get(seq_changed);
if (!force_seq_changed_range) {
- if (seq->startdisp > range_start) {
- range_start = seq->startdisp;
- }
-
- if (seq->enddisp < range_end) {
- range_end = seq->enddisp;
- }
+ range_start = max_ii(range_start, SEQ_time_left_handle_frame_get(seq));
+ range_end = min_ii(range_end, SEQ_time_right_handle_frame_get(seq));
}
int invalidate_composite = invalidate_types & SEQ_CACHE_STORE_FINAL_OUT;
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index 25d4f08be82..4d6efb1639b 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -173,6 +173,10 @@ void SEQ_time_update_meta_strip_range(const Scene *scene, Sequence *seq_meta)
void seq_time_effect_range_set(Sequence *seq)
{
+ if (seq->seq1 == NULL && seq->seq2 == NULL) {
+ return;
+ }
+
if (seq->seq1 && seq->seq2) { /* 2 - input effect. */
seq->startdisp = max_ii(SEQ_time_left_handle_frame_get(seq->seq1),
SEQ_time_left_handle_frame_get(seq->seq2));
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 051dc3961ba..19caf12ff2a 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -13,11 +13,13 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
#include "SEQ_animation.h"
#include "SEQ_channels.h"
+#include "SEQ_edit.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
@@ -25,8 +27,8 @@
#include "SEQ_time.h"
#include "SEQ_transform.h"
-#include "strip_time.h"
#include "sequencer.h"
+#include "strip_time.h"
#include "CLG_log.h"
@@ -198,7 +200,7 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
else { /* All other strip types. */
seq->start += delta;
/* Only to make files usable in older versions. */
- seq->startdisp = SEQ_time_left_handle_frame_get(seq);
+ seq->startdisp = SEQ_time_left_handle_frame_get(seq);
seq->enddisp = SEQ_time_right_handle_frame_get(seq);
}
@@ -307,6 +309,7 @@ static int shuffle_seq_time_offset_get(SeqCollection *strips_to_shuffle,
}
bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
+ SeqCollection *time_dependent_strips,
ListBase *seqbasep,
Scene *evil_scene,
ListBase *markers,
@@ -323,6 +326,12 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
seq->flag &= ~SEQ_OVERLAP;
}
+ if (time_dependent_strips != NULL) {
+ SEQ_ITERATOR_FOREACH (seq, time_dependent_strips) {
+ SEQ_offset_animdata(evil_scene, seq, offset);
+ }
+ }
+
if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) {
TimeMarker *marker;
/* affect selected markers - it's unlikely that we will want to affect all in this way? */
@@ -337,6 +346,296 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
return offset ? false : true;
}
+static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips)
+{
+ SeqCollection *collection = SEQ_collection_create(__func__);
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
+
+/* Query strips positioned after left edge of transformed strips bound-box. */
+static SeqCollection *query_right_side_strips(ListBase *seqbase,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips)
+{
+ int minframe = MAXFRAME;
+ {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ minframe = min_ii(minframe, SEQ_time_left_handle_frame_get(seq));
+ }
+ }
+
+ SeqCollection *collection = SEQ_collection_create(__func__);
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (SEQ_collection_has_strip(seq, time_dependent_strips)) {
+ continue;
+ }
+ if (SEQ_collection_has_strip(seq, transformed_strips)) {
+ continue;
+ }
+
+ if ((seq->flag & SELECT) == 0 && SEQ_time_left_handle_frame_get(seq) >= minframe) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
+
+/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal
+ * to overlap of transformed strips. */
+static void seq_transform_handle_expand_to_fit(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ ListBase *markers = &scene->markers;
+
+ SeqCollection *right_side_strips = query_right_side_strips(
+ seqbasep, transformed_strips, time_dependent_strips);
+
+ /* Temporarily move right side strips beyond timeline boundary. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine += MAXSEQ * 2;
+ }
+
+ /* Shuffle transformed standalone strips. This is because transformed strips can overlap with
+ * strips on left side. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
+
+ /* Move temporarily moved strips back to their original place and tag for shuffling. */
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine -= MAXSEQ * 2;
+ }
+ /* Shuffle again to displace strips on right side. Final effect shuffling is done in
+ * SEQ_transform_handle_overlap. */
+ SEQ_transform_seqbase_shuffle_time(
+ right_side_strips, NULL, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(right_side_strips);
+}
+
+static SeqCollection *query_overwrite_targets(ListBase *seqbasep,
+ SeqCollection *transformed_strips)
+{
+ SeqCollection *collection = SEQ_query_unselected_strips(seqbasep);
+
+ Sequence *seq, *seq_transformed;
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ bool does_overlap = false;
+
+ SEQ_ITERATOR_FOREACH (seq_transformed, transformed_strips) {
+ /* Effects of transformed strips can be unselected. These must not be included. */
+ if (seq == seq_transformed) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ if (SEQ_transform_test_overlap_seq_seq(seq, seq_transformed)) {
+ does_overlap = true;
+ }
+ }
+
+ if (!does_overlap) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ }
+
+ return collection;
+}
+
+typedef enum eOvelapDescrition {
+ /* No overlap. */
+ STRIP_OVERLAP_NONE,
+ /* Overlapping strip covers overlapped completely. */
+ STRIP_OVERLAP_IS_FULL,
+ /* Overlapping strip is inside overlapped. */
+ STRIP_OVERLAP_IS_INSIDE,
+ /* Partial overlap between 2 strips. */
+ STRIP_OVERLAP_LEFT_SIDE,
+ STRIP_OVERLAP_RIGHT_SIDE,
+} eOvelapDescrition;
+
+static eOvelapDescrition overlap_description_get(const Sequence *transformed,
+ const Sequence *target)
+{
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(transformed) >= SEQ_time_right_handle_frame_get(target)) {
+ return STRIP_OVERLAP_IS_FULL;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) > SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(transformed) < SEQ_time_right_handle_frame_get(target)) {
+ return STRIP_OVERLAP_IS_INSIDE;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_left_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
+ return STRIP_OVERLAP_LEFT_SIDE;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_right_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
+ return STRIP_OVERLAP_RIGHT_SIDE;
+ }
+ return STRIP_OVERLAP_NONE;
+}
+
+/* Split strip in 3 parts, remove middle part and fit transformed inside. */
+static void seq_transform_handle_overwrite_split(Scene *scene,
+ ListBase *seqbasep,
+ const Sequence *transformed,
+ Sequence *target)
+{
+ /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass
+ * NULL here. */
+ Main *bmain = NULL;
+
+ Sequence *split_strip = SEQ_edit_strip_split(bmain,
+ scene,
+ seqbasep,
+ target,
+ SEQ_time_left_handle_frame_get(transformed),
+ SEQ_SPLIT_SOFT,
+ NULL);
+ SEQ_edit_strip_split(bmain,
+ scene,
+ seqbasep,
+ split_strip,
+ SEQ_time_right_handle_frame_get(transformed),
+ SEQ_SPLIT_SOFT,
+ NULL);
+ SEQ_edit_flag_for_removal(scene, seqbasep, split_strip);
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+}
+
+/* Trim strips by adjusting handle position.
+ * This is bit more complicated in case overlap happens on effect. */
+static void seq_transform_handle_overwrite_trim(Scene *scene,
+ ListBase *seqbasep,
+ const Sequence *transformed,
+ Sequence *target,
+ const eOvelapDescrition overlap)
+{
+ SeqCollection *targets = SEQ_query_by_reference(target, seqbasep, SEQ_query_strip_effect_chain);
+
+ /* Expand collection by adding all target's children, effects and their children. */
+ if ((target->type & SEQ_TYPE_EFFECT) != 0) {
+ SEQ_collection_expand(seqbasep, targets, SEQ_query_strip_effect_chain);
+ }
+
+ /* Trim all non effects, that have influence on effect length which is overlapping. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, targets) {
+ if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) {
+ continue;
+ }
+ if (overlap == STRIP_OVERLAP_LEFT_SIDE) {
+ SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(transformed));
+ }
+ else {
+ BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE);
+ SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(transformed));
+ }
+ }
+ SEQ_collection_free(targets);
+}
+
+static void seq_transform_handle_overwrite(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips)
+{
+ SeqCollection *targets = query_overwrite_targets(seqbasep, transformed_strips);
+ SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
+
+ Sequence *target;
+ Sequence *transformed;
+ SEQ_ITERATOR_FOREACH (target, targets) {
+ SEQ_ITERATOR_FOREACH (transformed, transformed_strips) {
+ if (transformed->machine != target->machine) {
+ continue;
+ }
+
+ const eOvelapDescrition overlap = overlap_description_get(transformed, target);
+
+ if (overlap == STRIP_OVERLAP_IS_FULL) {
+ SEQ_collection_append_strip(target, strips_to_delete);
+ }
+ else if (overlap == STRIP_OVERLAP_IS_INSIDE) {
+ seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target);
+ }
+ else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) {
+ seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap);
+ }
+ }
+ }
+
+ SEQ_collection_free(targets);
+
+ /* Remove covered strips. This must be done in separate loop, because `SEQ_edit_strip_split()`
+ * also uses `SEQ_edit_remove_flagged_sequences()`. See T91096. */
+ if (SEQ_collection_len(strips_to_delete) > 0) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips_to_delete) {
+ SEQ_edit_flag_for_removal(scene, seqbasep, seq);
+ }
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+ }
+ SEQ_collection_free(strips_to_delete);
+}
+
+static void seq_transform_handle_overlap_shuffle(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ ListBase *markers = &scene->markers;
+
+ /* Shuffle non strips with no effects attached. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
+}
+
+void SEQ_transform_handle_overlap(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene);
+
+ switch (overlap_mode) {
+ case SEQ_OVERLAP_EXPAND:
+ seq_transform_handle_expand_to_fit(
+ scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
+ break;
+ case SEQ_OVERLAP_OVERWRITE:
+ seq_transform_handle_overwrite(scene, seqbasep, transformed_strips);
+ break;
+ case SEQ_OVERLAP_SHUFFLE:
+ seq_transform_handle_overlap_shuffle(
+ scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
+ break;
+ }
+
+ /* If any effects still overlap, we need to move them up.
+ * In some cases other strips can be overlapping still, see T90646. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if (SEQ_transform_test_overlap(seqbasep, seq)) {
+ SEQ_transform_seqbase_shuffle(seqbasep, seq, scene);
+ }
+ seq->flag &= ~SEQ_OVERLAP;
+ }
+}
+
void SEQ_transform_offset_after_frame(Scene *scene,
ListBase *seqbase,
const int delta,
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index 260f82310fb..3cfe63e284f 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -217,7 +217,7 @@ void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
(scene->r.scemode & R_MULTIVIEW) != 0;
- if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) {
+ if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL) && !openfile) {
return;
}
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 73a5f1e6f8d..4c553d0edfe 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -39,7 +39,7 @@ set(SRC
intern/wm_dragdrop.c
intern/wm_draw.c
intern/wm_event_query.c
- intern/wm_event_system.c
+ intern/wm_event_system.cc
intern/wm_files.c
intern/wm_files_link.c
intern/wm_gesture.c
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 890872a06bc..60cded3b869 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -388,6 +388,12 @@ struct wmEventHandler_UI *WM_event_add_ui_handler(const struct bContext *C,
wmUIHandlerRemoveFunc remove_fn,
void *user_data,
char flag);
+
+/**
+ * Return the first modal operator of type \a ot or NULL.
+ */
+wmOperator *WM_operator_find_modal_by_type(wmWindow *win, const wmOperatorType *ot);
+
/**
* \param postpone: Enable for `win->modalhandlers`,
* this is in a running for () loop in wm_handlers_do().
@@ -732,6 +738,7 @@ void WM_operator_last_properties_ensure(struct wmOperatorType *ot, struct Pointe
wmOperator *WM_operator_last_redo(const struct bContext *C);
/**
* Use for drag & drop a path or name with operators invoke() function.
+ * Returns null if no operator property is set to identify the file or ID to use.
*/
ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, short idcode);
@@ -1400,6 +1407,14 @@ void WM_jobs_callbacks(struct wmJob *,
void (*update)(void *),
void (*endjob)(void *));
+void WM_jobs_callbacks_ex(wmJob *wm_job,
+ wm_jobs_start_callback startjob,
+ void (*initjob)(void *),
+ void (*update)(void *),
+ void (*endjob)(void *),
+ void (*completed)(void *),
+ void (*canceled)(void *));
+
/**
* If job running, the same owner gave it a new job.
* if different owner starts existing startjob, it suspends itself
@@ -1426,6 +1441,7 @@ void WM_jobs_kill_all_except(struct wmWindowManager *wm, const void *owner);
void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_type);
bool WM_jobs_has_running(const struct wmWindowManager *wm);
+bool WM_jobs_has_running_type(const struct wmWindowManager *wm, int job_type);
void WM_job_main_thread_lock_acquire(struct wmJob *job);
void WM_job_main_thread_lock_release(struct wmJob *job);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 163b1fc6c06..ba73b2e9030 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -616,6 +616,7 @@ typedef enum eWM_EventFlag {
*/
WM_EVENT_FORCE_DRAG_THRESHOLD = (1 << 2),
} eWM_EventFlag;
+ENUM_OPERATORS(eWM_EventFlag, WM_EVENT_FORCE_DRAG_THRESHOLD);
typedef struct wmTabletData {
/** 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER. */
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index 80d29bb8c40..663c8a0baed 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -388,6 +388,8 @@ void WM_gizmomap_message_subscribe(const struct bContext *C,
struct ARegion *region,
struct wmMsgBus *mbus);
bool WM_gizmomap_is_any_selected(const struct wmGizmoMap *gzmap);
+struct wmGizmo *WM_gizmomap_get_modal(const struct wmGizmoMap *gzmap);
+
/**
* \note We could use a callback to define bounds, for now just use matrix location.
*/
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index f481f19045d..f5974a2176b 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -229,6 +229,11 @@ bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap)
return gzmap->gzmap_context.select.len != 0;
}
+wmGizmo *WM_gizmomap_get_modal(const wmGizmoMap *gzmap)
+{
+ return gzmap->gzmap_context.modal;
+}
+
bool WM_gizmomap_minmax(const wmGizmoMap *gzmap,
bool UNUSED(use_hidden),
bool use_select,
@@ -669,7 +674,7 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
* This way we always use the first hit. */
if (has_3d) {
- /* The depth buffer is needed for for gizmos to obscure eachother. */
+ /* The depth buffer is needed for for gizmos to obscure each other. */
GPUViewport *viewport = WM_draw_region_get_viewport(CTX_wm_region(C));
/* When switching between modes and the mouse pointer is over a gizmo, the highlight test is
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
index af083630623..1c257424297 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
@@ -345,7 +345,7 @@ void WM_gizmo_target_property_anim_autokey(bContext *C,
Scene *scene = CTX_data_scene(C);
const float cfra = (float)CFRA;
const int index = gz_prop->index == -1 ? 0 : gz_prop->index;
- ED_autokeyframe_property(C, scene, &gz_prop->ptr, gz_prop->prop, index, cfra);
+ ED_autokeyframe_property(C, scene, &gz_prop->ptr, gz_prop->prop, index, cfra, false);
}
}
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index b7066178abd..fc992ef069d 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -383,7 +383,7 @@ void WM_cursor_time(wmWindow *win, int nr)
/**
* Because defining a cursor mixes declarations and executable code
* each cursor needs its own scoping block or it would be split up
- * over several hundred lines of code. To enforce/document this better
+ * over several hundred lines of code. To enforce/document this better
* I define 2 pretty brain-dead macros so it's obvious what the extra "[]"
* are for */
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 8f96080c810..09ef4e15012 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -827,7 +827,7 @@ static void wm_drag_draw_icon(bContext *UNUSED(C),
x = xy[0] - (wm_drag_imbuf_icon_width_get(drag) / 2);
y = xy[1] - (wm_drag_imbuf_icon_height_get(drag) / 2);
- float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
+ const float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
immDrawPixelsTexTiled_scaling(&state,
x,
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index d2ade7b0376..63a7fb5ddaa 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -119,6 +119,125 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Draw Software Cursor
+ *
+ * Draw the cursor instead of relying on the graphical environment.
+ * Needed when setting the cursor position (warping) isn't supported (GHOST/WAYLAND).
+ * \{ */
+
+/**
+ * Track the state of the last drawn cursor.
+ */
+static struct {
+ int8_t enabled;
+ int winid;
+ int xy[2];
+} g_software_cursor = {
+ .enabled = -1,
+ .winid = -1,
+};
+
+/** Reuse the result from #GHOST_GetCursorGrabState. */
+struct GrabState {
+ GHOST_TGrabCursorMode mode;
+ GHOST_TAxisFlag wrap_axis;
+ int bounds[4];
+};
+
+static bool wm_software_cursor_needed(void)
+{
+ if (UNLIKELY(g_software_cursor.enabled == -1)) {
+ g_software_cursor.enabled = !GHOST_SupportsCursorWarp();
+ }
+ return g_software_cursor.enabled;
+}
+
+static bool wm_software_cursor_needed_for_window(const wmWindow *win, struct GrabState *grab_state)
+{
+ BLI_assert(wm_software_cursor_needed());
+ if (GHOST_GetCursorVisibility(win->ghostwin)) {
+ /* NOTE: The value in `win->grabcursor` can't be used as it
+ * doesn't always match GHOST's value in the case of tablet events. */
+ GHOST_GetCursorGrabState(
+ win->ghostwin, &grab_state->mode, &grab_state->wrap_axis, grab_state->bounds);
+ if (grab_state->mode == GHOST_kGrabWrap) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool wm_software_cursor_motion_test(const wmWindow *win)
+{
+ return (g_software_cursor.winid != win->winid) ||
+ (g_software_cursor.xy[0] != win->eventstate->xy[0]) ||
+ (g_software_cursor.xy[1] != win->eventstate->xy[1]);
+}
+
+static void wm_software_cursor_motion_update(const wmWindow *win)
+{
+
+ g_software_cursor.winid = win->winid;
+ g_software_cursor.xy[0] = win->eventstate->xy[0];
+ g_software_cursor.xy[1] = win->eventstate->xy[1];
+}
+
+static void wm_software_cursor_motion_clear(void)
+{
+ g_software_cursor.winid = -1;
+ g_software_cursor.xy[0] = -1;
+ g_software_cursor.xy[1] = -1;
+}
+
+static void wm_software_cursor_draw(wmWindow *win, const struct GrabState *grab_state)
+{
+ int x = win->eventstate->xy[0];
+ int y = win->eventstate->xy[1];
+
+ if (grab_state->wrap_axis & GHOST_kAxisX) {
+ const int min = grab_state->bounds[0];
+ const int max = grab_state->bounds[2];
+ if (min != max) {
+ x = mod_i(x - min, max - min) + min;
+ }
+ }
+ if (grab_state->wrap_axis & GHOST_kGrabAxisY) {
+ const int height = WM_window_pixels_y(win);
+ const int min = height - grab_state->bounds[1];
+ const int max = height - grab_state->bounds[3];
+ if (min != max) {
+ y = mod_i(y - max, min - max) + max;
+ }
+ }
+
+ /* Draw a primitive cross-hair cursor.
+ * NOTE: the `win->cursor` could be used for drawing although it's complicated as some cursors
+ * are set by the operating-system, where the pixel information isn't easily available. */
+ const float unit = max_ff(U.dpi_fac, 1.0f);
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1, 1, 1, 1);
+ {
+ const int ofs_line = (8 * unit);
+ const int ofs_size = (2 * unit);
+ immRecti(pos, x - ofs_line, y - ofs_size, x + ofs_line, y + ofs_size);
+ immRecti(pos, x - ofs_size, y - ofs_line, x + ofs_size, y + ofs_line);
+ }
+ immUniformColor4f(0, 0, 0, 1);
+ {
+ const int ofs_line = (7 * unit);
+ const int ofs_size = (1 * unit);
+ immRecti(pos, x - ofs_line, y - ofs_size, x + ofs_line, y + ofs_size);
+ immRecti(pos, x - ofs_size, y - ofs_line, x + ofs_size, y + ofs_line);
+ }
+ immUnbindProgram();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Post Draw Region on display handlers
* \{ */
@@ -862,6 +981,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
/* always draw, not only when screen tagged */
if (win->gesture.first) {
wm_gesture_draw(win);
+ wmWindowViewport(win);
}
/* Needs pixel coords in screen. */
@@ -870,6 +990,17 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
wmWindowViewport(win);
}
+ if (wm_software_cursor_needed()) {
+ struct GrabState grab_state;
+ if (wm_software_cursor_needed_for_window(win, &grab_state)) {
+ wm_software_cursor_draw(win, &grab_state);
+ wm_software_cursor_motion_update(win);
+ }
+ else {
+ wm_software_cursor_motion_clear();
+ }
+ }
+
GPU_debug_group_end();
}
@@ -1020,6 +1151,22 @@ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win)
return true;
}
+ if (wm_software_cursor_needed()) {
+ struct GrabState grab_state;
+ if (wm_software_cursor_needed_for_window(win, &grab_state)) {
+ if (wm_software_cursor_motion_test(win)) {
+ return true;
+ }
+ }
+ else {
+ /* Detect the edge case when the previous draw used the software cursor but this one doesn't,
+ * it's important to redraw otherwise the software cursor will remain displayed. */
+ if (g_software_cursor.winid != -1) {
+ return true;
+ }
+ }
+ }
+
#ifndef WITH_XR_OPENXR
UNUSED_VARS(wm);
#endif
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.cc
index 3ff3117dafe..d3ae4177e4d 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.cc
@@ -9,9 +9,9 @@
* Also some operator reports utility functions.
*/
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
#include "DNA_listBase.h"
#include "DNA_scene_types.h"
@@ -116,11 +116,11 @@ wmEvent *wm_event_add_ex(wmWindow *win,
const wmEvent *event_to_add,
const wmEvent *event_to_add_after)
{
- wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent");
+ wmEvent *event = MEM_new<wmEvent>(__func__);
*event = *event_to_add;
- if (event_to_add_after == NULL) {
+ if (event_to_add_after == nullptr) {
BLI_addtail(&win->event_queue, event);
}
else {
@@ -133,14 +133,14 @@ wmEvent *wm_event_add_ex(wmWindow *win,
wmEvent *wm_event_add(wmWindow *win, const wmEvent *event_to_add)
{
- return wm_event_add_ex(win, event_to_add, NULL);
+ return wm_event_add_ex(win, event_to_add, nullptr);
}
wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add)
{
if ((G.f & G_FLAG_EVENT_SIMULATE) == 0) {
BLI_assert_unreachable();
- return NULL;
+ return nullptr;
}
wmEvent *event = wm_event_add(win, event_to_add);
@@ -166,7 +166,7 @@ static void wm_event_custom_free(wmEvent *event)
/* NOTE: pointer to #ListBase struct elsewhere. */
if (event->custom == EVT_DATA_DRAGDROP) {
- ListBase *lb = event->customdata;
+ ListBase *lb = static_cast<ListBase *>(event->customdata);
WM_drag_free_list(lb);
}
else {
@@ -177,7 +177,7 @@ static void wm_event_custom_free(wmEvent *event)
static void wm_event_custom_clear(wmEvent *event)
{
event->custom = 0;
- event->customdata = NULL;
+ event->customdata = nullptr;
event->customdata_free = false;
}
@@ -209,7 +209,7 @@ static void wm_event_free_last_handled(wmWindow *win, wmEvent *event)
* As this function should be interchangeable with #wm_event_free. */
#ifndef NDEBUG
{
- wmEvent *event_copy = MEM_dupallocN(event);
+ wmEvent *event_copy = static_cast<wmEvent *>(MEM_dupallocN(event));
MEM_freeN(event);
event = event_copy;
}
@@ -227,8 +227,8 @@ static void wm_event_free_last_handled(wmWindow *win, wmEvent *event)
static void wm_event_free_last(wmWindow *win)
{
- wmEvent *event = BLI_poptail(&win->event_queue);
- if (event != NULL) {
+ wmEvent *event = static_cast<wmEvent *>(BLI_poptail(&win->event_queue));
+ if (event != nullptr) {
wm_event_free(event);
}
}
@@ -236,7 +236,7 @@ static void wm_event_free_last(wmWindow *win)
void wm_event_free_all(wmWindow *win)
{
wmEvent *event;
- while ((event = BLI_pophead(&win->event_queue))) {
+ while ((event = static_cast<wmEvent *>(BLI_pophead(&win->event_queue)))) {
wm_event_free(event);
}
}
@@ -270,7 +270,7 @@ void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint typ
return;
}
- wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier");
+ wmNotifier *note = MEM_cnew<wmNotifier>(__func__);
BLI_addtail(&wm->notifier_queue, note);
@@ -293,13 +293,13 @@ void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_main_add_notifier(unsigned int type, void *reference)
{
Main *bmain = G_MAIN;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (!wm || wm_test_duplicate_notifier(wm, type, reference)) {
return;
}
- wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier");
+ wmNotifier *note = MEM_cnew<wmNotifier>(__func__);
BLI_addtail(&wm->notifier_queue, note);
@@ -314,7 +314,7 @@ void WM_main_add_notifier(unsigned int type, void *reference)
void WM_main_remove_notifier_reference(const void *reference)
{
Main *bmain = G_MAIN;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (wm) {
LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) {
@@ -341,8 +341,8 @@ static void wm_main_remap_assetlist(ID *old_id, ID *new_id, void *UNUSED(user_da
static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data)
{
- struct wmMsgBus *mbus = user_data;
- if (new_id != NULL) {
+ wmMsgBus *mbus = static_cast<wmMsgBus *>(user_data);
+ if (new_id != nullptr) {
WM_msg_id_update(mbus, old_id, new_id);
}
else {
@@ -350,7 +350,7 @@ static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data)
}
}
-void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
+void WM_main_remap_editor_id_reference(const IDRemapper *mappings)
{
Main *bmain = G_MAIN;
@@ -362,9 +362,9 @@ void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
}
}
- BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, NULL);
+ BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, nullptr);
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (wm && wm->message_bus) {
BKE_id_remapper_iter(mappings, wm_main_remap_msgbus_notify, wm->message_bus);
}
@@ -372,7 +372,7 @@ void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
static void wm_notifier_clear(wmNotifier *note)
{
- /* NULL the entire notifier, only leaving (`next`, `prev`) members intact. */
+ /* nullptr the entire notifier, only leaving (`next`, `prev`) members intact. */
memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
}
@@ -435,22 +435,22 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
wm_event_do_depsgraph(C, false);
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
static void wm_event_execute_timers(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
- if (UNLIKELY(wm == NULL)) {
+ if (UNLIKELY(wm == nullptr)) {
return;
}
/* Set the first window as context, so that there is some minimal context. This avoids crashes
* when calling code that assumes that there is always a window in the context (which many
* operators do). */
- CTX_wm_window_set(C, wm->windows.first);
+ CTX_wm_window_set(C, static_cast<wmWindow *>(wm->windows.first));
BLI_timer_execute();
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
void wm_event_do_notifiers(bContext *C)
@@ -459,7 +459,7 @@ void wm_event_do_notifiers(bContext *C)
wm_event_execute_timers(C);
wmWindowManager *wm = CTX_wm_manager(C);
- if (wm == NULL) {
+ if (wm == nullptr) {
return;
}
@@ -489,7 +489,7 @@ void wm_event_do_notifiers(bContext *C)
if (note->window == win) {
if (note->category == NC_SCREEN) {
if (note->data == ND_WORKSPACE_SET) {
- WorkSpace *ref_ws = note->reference;
+ WorkSpace *ref_ws = static_cast<WorkSpace *>(note->reference);
UI_popup_handlers_remove_all(C, &win->modalhandlers);
@@ -499,7 +499,7 @@ void wm_event_do_notifiers(bContext *C)
}
}
else if (note->data == ND_WORKSPACE_DELETE) {
- WorkSpace *workspace = note->reference;
+ WorkSpace *workspace = static_cast<WorkSpace *>(note->reference);
ED_workspace_delete(
workspace, CTX_data_main(C), C, wm); /* XXX: hum, think this over! */
@@ -508,7 +508,8 @@ void wm_event_do_notifiers(bContext *C)
}
}
else if (note->data == ND_LAYOUTBROWSE) {
- bScreen *ref_screen = BKE_workspace_layout_screen_get(note->reference);
+ bScreen *ref_screen = BKE_workspace_layout_screen_get(
+ static_cast<WorkSpaceLayout *>(note->reference));
/* Free popup handlers only T35434. */
UI_popup_handlers_remove_all(C, &win->modalhandlers);
@@ -520,7 +521,7 @@ void wm_event_do_notifiers(bContext *C)
}
else if (note->data == ND_LAYOUTDELETE) {
WorkSpace *workspace = WM_window_get_active_workspace(win);
- WorkSpaceLayout *layout = note->reference;
+ WorkSpaceLayout *layout = static_cast<WorkSpaceLayout *>(note->reference);
ED_workspace_layout_delete(workspace, layout, C); /* XXX: hum, think this over! */
if (G.debug & G_DEBUG_EVENTS) {
@@ -530,7 +531,8 @@ void wm_event_do_notifiers(bContext *C)
}
}
- if (note->window == win || (note->window == NULL && (ELEM(note->reference, NULL, scene)))) {
+ if (note->window == win ||
+ (note->window == nullptr && (ELEM(note->reference, nullptr, scene)))) {
if (note->category == NC_SCENE) {
if (note->data == ND_FRAME) {
do_anim = true;
@@ -546,7 +548,7 @@ void wm_event_do_notifiers(bContext *C)
/* Only do once since adding notifiers is slow when there are many. */
ViewLayer *view_layer = CTX_data_view_layer(C);
ED_info_stats_clear(wm, view_layer);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, nullptr);
}
if (do_anim) {
@@ -564,7 +566,7 @@ void wm_event_do_notifiers(bContext *C)
/* The notifiers are sent without context, to keep it clean. */
wmNotifier *note;
- while ((note = BLI_pophead(&wm->notifier_queue))) {
+ while ((note = static_cast<wmNotifier *>(BLI_pophead(&wm->notifier_queue)))) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
Scene *scene = WM_window_get_active_scene(win);
bScreen *screen = WM_window_get_active_screen(win);
@@ -591,13 +593,13 @@ void wm_event_do_notifiers(bContext *C)
ED_screen_do_listen(C, note);
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
- wmRegionListenerParams region_params = {
- .window = win,
- .area = NULL,
- .region = region,
- .scene = scene,
- .notifier = note,
- };
+ wmRegionListenerParams region_params{};
+ region_params.window = win;
+ region_params.area = nullptr;
+ region_params.region = region;
+ region_params.scene = scene;
+ region_params.notifier = note;
+
ED_region_do_listen(&region_params);
}
@@ -609,21 +611,19 @@ void wm_event_do_notifiers(bContext *C)
continue;
}
}
- wmSpaceTypeListenerParams area_params = {
- .window = win,
- .area = area,
- .notifier = note,
- .scene = scene,
- };
+ wmSpaceTypeListenerParams area_params{};
+ area_params.window = win;
+ area_params.area = area;
+ area_params.notifier = note;
+ area_params.scene = scene;
ED_area_do_listen(&area_params);
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- wmRegionListenerParams region_params = {
- .window = win,
- .area = area,
- .region = region,
- .scene = scene,
- .notifier = note,
- };
+ wmRegionListenerParams region_params{};
+ region_params.window = win;
+ region_params.area = area;
+ region_params.region = region;
+ region_params.scene = scene;
+ region_params.notifier = note;
ED_region_do_listen(&region_params);
}
}
@@ -640,7 +640,7 @@ void wm_event_do_notifiers(bContext *C)
CTX_wm_window_set(C, win);
WM_msgbus_handle(wm->message_bus, C);
}
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
wm_event_do_refresh_wm_and_depsgraph(C);
@@ -650,7 +650,7 @@ void wm_event_do_notifiers(bContext *C)
wmWindow *win = wm->winactive;
CTX_wm_window_set(C, win);
WM_window_cursor_keymap_status_refresh(C, win);
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
/* Auto-run warning. */
@@ -668,7 +668,7 @@ static int wm_event_always_pass(const wmEvent *event)
* don't cause non-passing handler return values, and thus actually pass.
*
* Can't be executed if the handler just loaded a file (typically identified by `CTX_wm_window(C)`
- * returning `NULL`), because the event will have been freed then.
+ * returning `nullptr`), because the event will have been freed then.
*/
BLI_INLINE void wm_event_handler_return_value_check(const wmEvent *event, const int action)
{
@@ -739,9 +739,9 @@ static int wm_handler_ui_call(bContext *C,
}
else {
/* This special cases is for areas and regions that get removed. */
- CTX_wm_area_set(C, NULL);
- CTX_wm_region_set(C, NULL);
- CTX_wm_menu_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
+ CTX_wm_region_set(C, nullptr);
+ CTX_wm_menu_set(C, nullptr);
}
if (retval == WM_UI_HANDLER_BREAK) {
@@ -768,12 +768,12 @@ void wm_event_handler_ui_cancel_ex(bContext *C,
LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &region->handlers) {
if (handler_base->type == WM_HANDLER_TYPE_UI) {
wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
- BLI_assert(handler->handle_fn != NULL);
+ BLI_assert(handler->handle_fn != nullptr);
wmEvent event;
wm_event_init_from_window(win, &event);
event.type = EVT_BUT_CANCEL;
event.val = reactivate_button ? 0 : 1;
- event.flag = 0;
+ event.flag = (eWM_EventFlag)0;
handler->handle_fn(C, &event, handler->user_data);
}
}
@@ -796,24 +796,24 @@ static void wm_event_handler_ui_cancel(bContext *C)
void WM_report_banner_show(void)
{
- wmWindowManager *wm = G_MAIN->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
ReportList *wm_reports = &wm->reports;
/* After adding reports to the global list, reset the report timer. */
- WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
+ WM_event_remove_timer(wm, nullptr, wm_reports->reporttimer);
/* Records time since last report was added. */
wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05);
- ReportTimerInfo *rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
+ ReportTimerInfo *rti = MEM_cnew<ReportTimerInfo>(__func__);
wm_reports->reporttimer->customdata = rti;
}
void WM_report_banners_cancel(Main *bmain)
{
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
BKE_reports_clear(&wm->reports);
- WM_event_remove_timer(wm, NULL, wm->reports.reporttimer);
+ WM_event_remove_timer(wm, nullptr, wm->reports.reporttimer);
}
#ifdef WITH_INPUT_NDOF
@@ -827,7 +827,7 @@ static void wm_add_reports(ReportList *reports)
{
/* If the caller owns them, handle this. */
if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
- wmWindowManager *wm = G_MAIN->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
/* Add reports to the global list, otherwise they are not seen. */
BLI_movelisttolist(&wm->reports.list, &reports->list);
@@ -873,7 +873,7 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot)
{
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *ot_macro = WM_operatortype_find(macro->idname, 0);
+ wmOperatorType *ot_macro = WM_operatortype_find(macro->idname, false);
if (!WM_operator_poll(C, ot_macro)) {
return false;
@@ -894,15 +894,16 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot)
bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
{
/* Sets up the new context and calls #wm_operator_invoke() with poll_only. */
- return wm_operator_call_internal(C, ot, NULL, NULL, context, true, NULL);
+ return wm_operator_call_internal(
+ C, ot, nullptr, nullptr, static_cast<wmOperatorCallContext>(context), true, nullptr);
}
bool WM_operator_check_ui_empty(wmOperatorType *ot)
{
- if (ot->macro.first != NULL) {
+ if (ot->macro.first != nullptr) {
/* For macros, check all have exec() we can call. */
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
if (otm && !WM_operator_check_ui_empty(otm)) {
return false;
}
@@ -951,8 +952,8 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (win_prev == NULL) {
- CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
+ if (win_prev == nullptr) {
+ CTX_wm_window_set(C, static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first));
}
UI_popup_menu_reports(C, op->reports);
@@ -982,7 +983,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
/* Refresh Info Editor with reports immediately, even if op returned #OPERATOR_CANCELLED. */
if ((retval & OPERATOR_CANCELLED) && !BLI_listbase_is_empty(&op->reports->list)) {
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, nullptr);
}
/* If the caller owns them, handle this. */
wm_add_reports(op->reports);
@@ -1008,7 +1009,7 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
CLEAR,
} hud_status = NOP;
- op->customdata = NULL;
+ op->customdata = nullptr;
if (store) {
WM_operator_last_properties_store(op);
@@ -1064,7 +1065,7 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
}
}
else if (hud_status == CLEAR) {
- ED_area_type_hud_clear(wm, NULL);
+ ED_area_type_hud_clear(wm, nullptr);
}
else {
BLI_assert_unreachable();
@@ -1082,7 +1083,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
CTX_wm_operator_poll_msg_clear(C);
- if (op == NULL || op->type == NULL) {
+ if (op == nullptr || op->type == nullptr) {
return retval;
}
@@ -1130,7 +1131,7 @@ static int wm_operator_exec_notest(bContext *C, wmOperator *op)
{
int retval = OPERATOR_CANCELLED;
- if (op == NULL || op->type == NULL || op->type->exec == NULL) {
+ if (op == nullptr || op->type == nullptr || op->type->exec == nullptr) {
return retval;
}
@@ -1173,14 +1174,14 @@ int WM_operator_repeat_last(bContext *C, wmOperator *op)
}
bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
{
- if (op->type->exec != NULL) {
+ if (op->type->exec != nullptr) {
return true;
}
if (op->opm) {
/* For macros, check all have exec() we can call. */
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &op->opm->type->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
- if (otm && otm->exec == NULL) {
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
+ if (otm && otm->exec == nullptr) {
return false;
}
}
@@ -1194,9 +1195,9 @@ bool WM_operator_is_repeat(const bContext *C, const wmOperator *op)
{
/* May be in the operators list or not. */
wmOperator *op_prev;
- if (op->prev == NULL && op->next == NULL) {
+ if (op->prev == nullptr && op->next == nullptr) {
wmWindowManager *wm = CTX_wm_manager(C);
- op_prev = wm->operators.last;
+ op_prev = static_cast<wmOperator *>(wm->operators.last);
}
else {
op_prev = op->prev;
@@ -1210,16 +1211,16 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
ReportList *reports)
{
/* Operator-type names are static still. pass to allocation name for debugging. */
- wmOperator *op = MEM_callocN(sizeof(wmOperator), ot->idname);
+ wmOperator *op = MEM_cnew<wmOperator>(ot->idname);
/* Adding new operator could be function, only happens here now. */
op->type = ot;
BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
/* Initialize properties, either copy or create. */
- op->ptr = MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
+ op->ptr = MEM_cnew<PointerRNA>("wmOperatorPtrRNA");
if (properties && properties->data) {
- op->properties = IDP_CopyProperty(properties->data);
+ op->properties = IDP_CopyProperty(static_cast<const IDProperty *>(properties->data));
}
else {
IDPropertyTemplate val = {0};
@@ -1232,36 +1233,36 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
op->reports = reports; /* Must be initialized already. */
}
else {
- op->reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
+ op->reports = MEM_cnew<ReportList>("wmOperatorReportList");
BKE_reports_init(op->reports, RPT_STORE | RPT_FREE);
}
/* Recursive filling of operator macro list. */
if (ot->macro.first) {
- static wmOperator *motherop = NULL;
+ static wmOperator *motherop = nullptr;
int root = 0;
/* Ensure all ops are in execution order in 1 list. */
- if (motherop == NULL) {
+ if (motherop == nullptr) {
motherop = op;
root = 1;
}
/* If properties exist, it will contain everything needed. */
if (properties) {
- wmOperatorTypeMacro *otmacro = ot->macro.first;
+ wmOperatorTypeMacro *otmacro = static_cast<wmOperatorTypeMacro *>(ot->macro.first);
RNA_STRUCT_BEGIN (properties, prop) {
- if (otmacro == NULL) {
+ if (otmacro == nullptr) {
break;
}
/* Skip invalid properties. */
if (STREQ(RNA_property_identifier(prop), otmacro->idname)) {
- wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0);
+ wmOperatorType *otm = WM_operatortype_find(otmacro->idname, false);
PointerRNA someptr = RNA_property_pointer_get(properties, prop);
- wmOperator *opm = wm_operator_create(wm, otm, &someptr, NULL);
+ wmOperator *opm = wm_operator_create(wm, otm, &someptr, nullptr);
IDP_ReplaceGroupInGroup(opm->properties, otmacro->properties);
@@ -1275,8 +1276,8 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
}
else {
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
- wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, NULL);
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
+ wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, nullptr);
BLI_addtail(&motherop->macro, opm);
opm->opm = motherop; /* Pointer to mom, for modal(). */
@@ -1284,11 +1285,11 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
}
if (root) {
- motherop = NULL;
+ motherop = nullptr;
}
}
- WM_operator_properties_sanitize(op->ptr, 0);
+ WM_operator_properties_sanitize(op->ptr, false);
return op;
}
@@ -1302,12 +1303,12 @@ static void wm_region_tag_draw_on_gizmo_delay_refresh_for_tweak(wmWindow *win)
bScreen *screen = WM_window_get_active_screen(win);
/* Unlikely but not impossible as this runs after events have been handled. */
- if (UNLIKELY(screen == NULL)) {
+ if (UNLIKELY(screen == nullptr)) {
return;
}
ED_screen_areas_iter (win, screen, area) {
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- if (region->gizmo_map != NULL) {
+ if (region->gizmo_map != nullptr) {
if (WM_gizmomap_tag_delay_refresh_for_tweak_check(region->gizmo_map)) {
ED_region_tag_redraw(region);
}
@@ -1332,7 +1333,7 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event)
}
/**
- * Also used for exec when 'event' is NULL.
+ * Also used for exec when 'event' is nullptr.
*/
static int wm_operator_invoke(bContext *C,
wmOperatorType *ot,
@@ -1353,12 +1354,12 @@ static int wm_operator_invoke(bContext *C,
if (WM_operator_poll(C, ot)) {
wmWindowManager *wm = CTX_wm_manager(C);
- /* If `reports == NULL`, they'll be initialized. */
+ /* If `reports == nullptr`, they'll be initialized. */
wmOperator *op = wm_operator_create(wm, ot, properties, reports);
const bool is_nested_call = (wm->op_undo_depth != 0);
- if (event != NULL) {
+ if (event != nullptr) {
op->flag |= OP_IS_INVOKE;
}
@@ -1367,7 +1368,7 @@ static int wm_operator_invoke(bContext *C,
WM_operator_last_properties_init(op);
}
- if ((event == NULL) || (event->type != MOUSEMOVE)) {
+ if ((event == nullptr) || (event->type != MOUSEMOVE)) {
CLOG_INFO(WM_LOG_HANDLERS,
2,
"handle evt %d win %p op %s",
@@ -1378,7 +1379,7 @@ static int wm_operator_invoke(bContext *C,
if (op->type->invoke && event) {
/* Temporarily write into `mval` (not technically `const` correct) but this is restored. */
- int mval_prev[2] = {UNPACK2(event->mval)};
+ const int mval_prev[2] = {UNPACK2(event->mval)};
wm_region_mouse_co(C, (wmEvent *)event);
if (op->type->flag & OPTYPE_UNDO) {
@@ -1415,7 +1416,7 @@ static int wm_operator_invoke(bContext *C,
* them currently Python only uses this. */
if (!(retval & OPERATOR_HANDLED) && (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED))) {
/* Only show the report if the report list was not given in the function. */
- wm_operator_reports(C, op, retval, (reports != NULL));
+ wm_operator_reports(C, op, retval, (reports != nullptr));
}
if (retval & OPERATOR_HANDLED) {
@@ -1451,7 +1452,7 @@ static int wm_operator_invoke(bContext *C,
}
if (wrap) {
- const rcti *winrect = NULL;
+ const rcti *winrect = nullptr;
ARegion *region = CTX_wm_region(C);
ScrArea *area = CTX_wm_area(C);
@@ -1514,7 +1515,7 @@ static int wm_operator_call_internal(bContext *C,
if (ot) {
wmWindow *window = CTX_wm_window(C);
- if (event == NULL) {
+ if (event == nullptr) {
switch (context) {
case WM_OP_INVOKE_DEFAULT:
case WM_OP_INVOKE_REGION_WIN:
@@ -1523,7 +1524,7 @@ static int wm_operator_call_internal(bContext *C,
case WM_OP_INVOKE_AREA:
case WM_OP_INVOKE_SCREEN:
/* Window is needed for invoke and cancel operators. */
- if (window == NULL) {
+ if (window == nullptr) {
if (poll_only) {
CTX_wm_operator_poll_msg_set(C, "Missing 'window' in context");
}
@@ -1534,7 +1535,7 @@ static int wm_operator_call_internal(bContext *C,
}
break;
default:
- event = NULL;
+ event = nullptr;
break;
}
}
@@ -1546,7 +1547,7 @@ static int wm_operator_call_internal(bContext *C,
case WM_OP_EXEC_REGION_CHANNELS:
case WM_OP_EXEC_AREA:
case WM_OP_EXEC_SCREEN:
- event = NULL;
+ event = nullptr;
default:
break;
}
@@ -1604,7 +1605,7 @@ static int wm_operator_call_internal(bContext *C,
/* Remove region from context. */
ARegion *region = CTX_wm_region(C);
- CTX_wm_region_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
CTX_wm_region_set(C, region);
@@ -1616,8 +1617,8 @@ static int wm_operator_call_internal(bContext *C,
ARegion *region = CTX_wm_region(C);
ScrArea *area = CTX_wm_area(C);
- CTX_wm_region_set(C, NULL);
- CTX_wm_area_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
+ CTX_wm_area_set(C, nullptr);
retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
@@ -1640,7 +1641,7 @@ int WM_operator_name_call_ptr(bContext *C,
const wmEvent *event)
{
BLI_assert(ot == WM_operatortype_find(ot->idname, true));
- return wm_operator_call_internal(C, ot, properties, NULL, context, false, event);
+ return wm_operator_call_internal(C, ot, properties, nullptr, context, false, event);
}
int WM_operator_name_call(bContext *C,
const char *opstring,
@@ -1648,7 +1649,7 @@ int WM_operator_name_call(bContext *C,
PointerRNA *properties,
const wmEvent *event)
{
- wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
if (ot) {
return WM_operator_name_call_ptr(C, ot, context, properties, event);
}
@@ -1658,7 +1659,7 @@ int WM_operator_name_call(bContext *C,
bool WM_operator_name_poll(bContext *C, const char *opstring)
{
- wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
if (!ot) {
return false;
}
@@ -1666,15 +1667,16 @@ bool WM_operator_name_poll(bContext *C, const char *opstring)
return WM_operator_poll(C, ot);
}
-int WM_operator_name_call_with_properties(struct bContext *C,
+int WM_operator_name_call_with_properties(bContext *C,
const char *opstring,
wmOperatorCallContext context,
- struct IDProperty *properties,
+ IDProperty *properties,
const wmEvent *event)
{
PointerRNA props_ptr;
wmOperatorType *ot = WM_operatortype_find(opstring, false);
- RNA_pointer_create(G_MAIN->wm.first, ot->srna, properties, &props_ptr);
+ RNA_pointer_create(
+ &static_cast<wmWindowManager *>(G_MAIN->wm.first)->id, ot->srna, properties, &props_ptr);
return WM_operator_name_call_ptr(C, ot, context, &props_ptr, event);
}
@@ -1684,7 +1686,7 @@ void WM_menu_name_call(bContext *C, const char *menu_name, short context)
PointerRNA ptr;
WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, "name", menu_name);
- WM_operator_name_call_ptr(C, ot, context, &ptr, NULL);
+ WM_operator_name_call_ptr(C, ot, static_cast<wmOperatorCallContext>(context), &ptr, nullptr);
WM_operator_properties_free(&ptr);
}
@@ -1703,7 +1705,7 @@ int WM_operator_call_py(bContext *C,
wm->op_undo_depth++;
}
- retval = wm_operator_call_internal(C, ot, properties, reports, context, false, NULL);
+ retval = wm_operator_call_internal(C, ot, properties, reports, context, false, nullptr);
if (!is_undo && wm && (wm == CTX_wm_manager(C))) {
wm->op_undo_depth--;
@@ -1722,18 +1724,18 @@ int WM_operator_call_py(bContext *C,
* See: #OPTYPE_DEPENDS_ON_CURSOR doc-string for more information.
* \{ */
-typedef struct uiOperatorWaitForInput {
+struct uiOperatorWaitForInput {
ScrArea *area;
wmOperatorCallParams optype_params;
bContextStore *context;
-} uiOperatorWaitForInput;
+};
static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
{
- uiOperatorWaitForInput *opwait = userdata;
+ uiOperatorWaitForInput *opwait = static_cast<uiOperatorWaitForInput *>(userdata);
if (opwait->optype_params.opptr) {
if (opwait->optype_params.opptr->data) {
- IDP_FreeProperty(opwait->optype_params.opptr->data);
+ IDP_FreeProperty(static_cast<IDProperty *>(opwait->optype_params.opptr->data));
}
MEM_freeN(opwait->optype_params.opptr);
}
@@ -1741,11 +1743,11 @@ static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
CTX_store_free(opwait->context);
}
- if (opwait->area != NULL) {
- ED_area_status_text(opwait->area, NULL);
+ if (opwait->area != nullptr) {
+ ED_area_status_text(opwait->area, nullptr);
}
else {
- ED_workspace_status_text(C, NULL);
+ ED_workspace_status_text(C, nullptr);
}
MEM_freeN(opwait);
@@ -1753,7 +1755,7 @@ static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *userdata)
{
- uiOperatorWaitForInput *opwait = userdata;
+ uiOperatorWaitForInput *opwait = static_cast<uiOperatorWaitForInput *>(userdata);
enum { CONTINUE = 0, EXECUTE, CANCEL } state = CONTINUE;
state = CONTINUE;
@@ -1798,7 +1800,7 @@ static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *us
opwait->optype_params.opcontext,
opwait->optype_params.opptr,
event);
- CTX_store_set(C, NULL);
+ CTX_store_set(C, nullptr);
}
WM_event_remove_ui_handler(&win->modalhandlers,
@@ -1825,8 +1827,8 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
int flag = ot->flag;
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
- if (otm != NULL) {
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
+ if (otm != nullptr) {
flag |= otm->flag;
}
}
@@ -1840,7 +1842,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
/* The operator context is applied when the operator is called,
* the check for the area needs to be explicitly limited here.
* Useful so it's possible to screen-shot an area without drawing into it's header. */
- ScrArea *area = WM_OP_CONTEXT_HAS_AREA(opcontext) ? CTX_wm_area(C) : NULL;
+ ScrArea *area = WM_OP_CONTEXT_HAS_AREA(opcontext) ? CTX_wm_area(C) : nullptr;
{
char header_text[UI_MAX_DRAW_STR];
@@ -1848,7 +1850,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
"%s %s",
IFACE_("Input pending "),
(drawstr && drawstr[0]) ? drawstr : CTX_IFACE_(ot->translation_context, ot->name));
- if (area != NULL) {
+ if (area != nullptr) {
ED_area_status_text(area, header_text);
}
else {
@@ -1858,7 +1860,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
WM_cursor_modal_set(win, ot->cursor_pending);
- uiOperatorWaitForInput *opwait = MEM_callocN(sizeof(*opwait), __func__);
+ uiOperatorWaitForInput *opwait = MEM_cnew<uiOperatorWaitForInput>(__func__);
opwait->optype_params.optype = ot;
opwait->optype_params.opcontext = opcontext;
opwait->optype_params.opptr = properties;
@@ -1866,10 +1868,11 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
opwait->area = area;
if (properties) {
- opwait->optype_params.opptr = MEM_mallocN(sizeof(*opwait->optype_params.opptr), __func__);
+ opwait->optype_params.opptr = MEM_cnew<PointerRNA>(__func__);
*opwait->optype_params.opptr = *properties;
- if (properties->data != NULL) {
- opwait->optype_params.opptr->data = IDP_CopyProperty(properties->data);
+ if (properties->data != nullptr) {
+ opwait->optype_params.opptr->data = IDP_CopyProperty(
+ static_cast<IDProperty *>(properties->data));
}
}
@@ -1916,18 +1919,18 @@ static void wm_handler_op_context_get_if_valid(bContext *C,
* possible. */
bScreen *screen = handler->context.win ? WM_window_get_active_screen(win) : CTX_wm_screen(C);
- *r_area = NULL;
- *r_region = NULL;
+ *r_area = nullptr;
+ *r_region = nullptr;
- if (screen == NULL || handler->op == NULL) {
+ if (screen == nullptr || handler->op == nullptr) {
return;
}
- if (handler->context.area == NULL) {
+ if (handler->context.area == nullptr) {
/* Pass */
}
else {
- ScrArea *area = NULL;
+ ScrArea *area = nullptr;
ED_screen_areas_iter (win, screen, area_iter) {
if (area_iter == handler->context.area) {
@@ -1936,10 +1939,10 @@ static void wm_handler_op_context_get_if_valid(bContext *C,
}
}
- if (area == NULL) {
+ if (area == nullptr) {
/* When changing screen layouts with running modal handlers (like render display), this
* is not an error to print. */
- if (handler->op == NULL) {
+ if (handler->op == nullptr) {
CLOG_ERROR(WM_LOG_HANDLERS,
"internal error: handler (%s) has invalid area",
handler->op->type->idname);
@@ -1947,7 +1950,7 @@ static void wm_handler_op_context_get_if_valid(bContext *C,
}
else {
ARegion *region;
- wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL;
+ wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : nullptr;
*r_area = area;
if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
@@ -1957,10 +1960,10 @@ static void wm_handler_op_context_get_if_valid(bContext *C,
}
}
else {
- region = NULL;
+ region = nullptr;
}
- if ((region == NULL) && handler->context.region) {
+ if ((region == nullptr) && handler->context.region) {
if (BLI_findindex(&area->regionbase, handler->context.region) != -1) {
region = handler->context.region;
}
@@ -1976,8 +1979,8 @@ static void wm_handler_op_context_get_if_valid(bContext *C,
static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event)
{
- ScrArea *area = NULL;
- ARegion *region = NULL;
+ ScrArea *area = nullptr;
+ ARegion *region = nullptr;
wm_handler_op_context_get_if_valid(C, handler, event, &area, &region);
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
@@ -1989,7 +1992,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
/* C is zero on freeing database, modal handlers then already were freed. */
wmEventHandler *handler_base;
- while ((handler_base = BLI_pophead(handlers))) {
+ while ((handler_base = static_cast<wmEventHandler *>(BLI_pophead(handlers)))) {
BLI_assert(handler_base->type != 0);
if (handler_base->type == WM_HANDLER_TYPE_OP) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
@@ -2028,7 +2031,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
CTX_wm_region_set(C, region);
}
- WM_cursor_grab_disable(win, NULL);
+ WM_cursor_grab_disable(win, nullptr);
if (handler->is_fileselect) {
wm_operator_free_for_fileselect(handler->op);
@@ -2132,25 +2135,26 @@ static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
/* Account for rare case of when these keys are used as the 'type' not as modifiers. */
if (kmi->shift != KM_ANY) {
const bool shift = (winevent->modifier & KM_SHIFT) != 0;
- if ((shift != kmi->shift) && !ELEM(winevent->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY)) {
+ if ((shift != (bool)kmi->shift) &&
+ !ELEM(winevent->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY)) {
return false;
}
}
if (kmi->ctrl != KM_ANY) {
const bool ctrl = (winevent->modifier & KM_CTRL) != 0;
- if (ctrl != kmi->ctrl && !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
+ if (ctrl != (bool)kmi->ctrl && !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
return false;
}
}
if (kmi->alt != KM_ANY) {
const bool alt = (winevent->modifier & KM_ALT) != 0;
- if (alt != kmi->alt && !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
+ if (alt != (bool)kmi->alt && !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
return false;
}
}
if (kmi->oskey != KM_ANY) {
const bool oskey = (winevent->modifier & KM_OSKEY) != 0;
- if ((oskey != kmi->oskey) && (winevent->type != EVT_OSKEY)) {
+ if ((oskey != (bool)kmi->oskey) && (winevent->type != EVT_OSKEY)) {
return false;
}
}
@@ -2175,12 +2179,12 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap,
/* Should already be handled by #wm_user_modal_keymap_set_items. */
BLI_assert(kmi->propvalue_str[0] == '\0');
if (wm_eventmatch(event, kmi)) {
- if ((keymap->poll_modal_item == NULL) || (keymap->poll_modal_item(op, kmi->propvalue))) {
+ if ((keymap->poll_modal_item == nullptr) || (keymap->poll_modal_item(op, kmi->propvalue))) {
return kmi;
}
}
}
- return NULL;
+ return nullptr;
}
struct wmEvent_ModalMapStore {
@@ -2203,7 +2207,7 @@ struct wmEvent_ModalMapStore {
static void wm_event_modalkeymap_begin(const bContext *C,
wmOperator *op,
wmEvent *event,
- struct wmEvent_ModalMapStore *event_backup)
+ wmEvent_ModalMapStore *event_backup)
{
BLI_assert(event->type != EVT_MODAL_MAP);
@@ -2216,9 +2220,9 @@ static void wm_event_modalkeymap_begin(const bContext *C,
if (op->type->modalkeymap) {
wmKeyMap *keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
- wmKeyMapItem *kmi = NULL;
+ wmKeyMapItem *kmi = nullptr;
- const wmEvent *event_match = NULL;
+ const wmEvent *event_match = nullptr;
wmEvent event_no_dbl_click;
if ((kmi = wm_eventmatch_modal_keymap_items(keymap, op, event))) {
@@ -2232,7 +2236,7 @@ static void wm_event_modalkeymap_begin(const bContext *C,
}
}
- if (event_match != NULL) {
+ if (event_match != nullptr) {
event_backup->prev_type = event->prev_type;
event_backup->prev_val = event->prev_val;
@@ -2267,8 +2271,7 @@ static void wm_event_modalkeymap_begin(const bContext *C,
* better restore event type for checking of #KM_CLICK for example.
* Modal maps could use different method (ton).
*/
-static void wm_event_modalkeymap_end(wmEvent *event,
- const struct wmEvent_ModalMapStore *event_backup)
+static void wm_event_modalkeymap_end(wmEvent *event, const wmEvent_ModalMapStore *event_backup)
{
if (event->type == EVT_MODAL_MAP) {
event->type = event->prev_type;
@@ -2297,7 +2300,7 @@ static int wm_handler_operator_call(bContext *C,
/* Derived, modal or blocking operator. */
if ((handler_base->type == WM_HANDLER_TYPE_OP) &&
- (((wmEventHandler_Op *)handler_base)->op != NULL)) {
+ (((wmEventHandler_Op *)handler_base)->op != nullptr)) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
wmOperator *op = handler->op;
wmOperatorType *ot = op->type;
@@ -2316,7 +2319,7 @@ static int wm_handler_operator_call(bContext *C,
wm_handler_op_context(C, handler, event);
wm_region_mouse_co(C, event);
- struct wmEvent_ModalMapStore event_backup;
+ wmEvent_ModalMapStore event_backup;
wm_event_modalkeymap_begin(C, op, event, &event_backup);
if (ot->flag & OPTYPE_UNDO) {
@@ -2352,14 +2355,14 @@ static int wm_handler_operator_call(bContext *C,
}
}
- /* Important to run 'wm_operator_finished' before NULL-ing the context members. */
+ /* Important to run 'wm_operator_finished' before nullptr-ing the context members. */
if (retval & OPERATOR_FINISHED) {
wm_operator_finished(C, op, false, true);
- handler->op = NULL;
+ handler->op = nullptr;
}
else if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
WM_operator_free(op);
- handler->op = NULL;
+ handler->op = nullptr;
}
/* Putting back screen context, `reval` can pass through after modal failures! */
@@ -2369,8 +2372,8 @@ static int wm_handler_operator_call(bContext *C,
}
else {
/* This special cases is for areas and regions that get removed. */
- CTX_wm_area_set(C, NULL);
- CTX_wm_region_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
+ CTX_wm_region_set(C, nullptr);
}
/* Update gizmos during modal handlers. */
@@ -2378,7 +2381,7 @@ static int wm_handler_operator_call(bContext *C,
/* Remove modal handler, operator itself should have been canceled and freed. */
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
- WM_cursor_grab_disable(CTX_wm_window(C), NULL);
+ WM_cursor_grab_disable(CTX_wm_window(C), nullptr);
BLI_remlink(handlers, handler);
wm_event_free_handler(&handler->head);
@@ -2393,13 +2396,13 @@ static int wm_handler_operator_call(bContext *C,
}
}
else {
- wmOperatorType *ot = WM_operatortype_find(kmi_idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi_idname, false);
if (ot && wm_operator_check_locked_interface(C, ot)) {
bool use_last_properties = true;
- PointerRNA tool_properties = {0};
+ PointerRNA tool_properties = {nullptr};
- bToolRef *keymap_tool = NULL;
+ bToolRef *keymap_tool = nullptr;
if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
keymap_tool = ((wmEventHandler_Keymap *)handler_base)->keymap_tool;
}
@@ -2411,7 +2414,7 @@ static int wm_handler_operator_call(bContext *C,
}
}
- const bool is_tool = (keymap_tool != NULL);
+ const bool is_tool = (keymap_tool != nullptr);
const bool use_tool_properties = is_tool;
if (use_tool_properties) {
@@ -2421,7 +2424,7 @@ static int wm_handler_operator_call(bContext *C,
use_last_properties = false;
}
- retval = wm_operator_invoke(C, ot, event, properties, NULL, false, use_last_properties);
+ retval = wm_operator_invoke(C, ot, event, properties, nullptr, false, use_last_properties);
if (use_tool_properties) {
WM_operator_properties_free(&tool_properties);
@@ -2434,10 +2437,10 @@ static int wm_handler_operator_call(bContext *C,
if (tref_rt->gizmo_group[0]) {
const char *idname = tref_rt->gizmo_group;
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
- if (gzgt != NULL) {
+ if (gzgt != nullptr) {
if ((gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_INIT) != 0) {
ARegion *region = CTX_wm_region(C);
- if (region != NULL) {
+ if (region != nullptr) {
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
WM_gizmo_group_type_ensure_ptr_ex(gzgt, gzmap_type);
wmGizmoGroup *gzgroup = WM_gizmomaptype_group_init_runtime_with_region(
@@ -2477,9 +2480,9 @@ static void wm_operator_free_for_fileselect(wmOperator *file_operator)
LISTBASE_FOREACH (bScreen *, screen, &G_MAIN->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype == SPACE_FILE) {
- SpaceFile *sfile = area->spacedata.first;
+ SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
if (sfile->op == file_operator) {
- sfile->op = NULL;
+ sfile->op = nullptr;
}
}
}
@@ -2551,16 +2554,16 @@ static int wm_handler_fileselect_do(bContext *C,
if (val == EVT_FILESELECT_EXTERNAL_CANCEL) {
/* The window might have been freed already. */
if (BLI_findindex(&wm->windows, handler->context.win) == -1) {
- handler->context.win = NULL;
+ handler->context.win = nullptr;
}
}
else {
ScrArea *ctx_area = CTX_wm_area(C);
- wmWindow *temp_win = NULL;
+ wmWindow *temp_win = nullptr;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
- ScrArea *file_area = screen->areabase.first;
+ ScrArea *file_area = static_cast<ScrArea *>(screen->areabase.first);
if ((file_area->spacetype != SPACE_FILE) || !WM_window_is_temp_screen(win)) {
continue;
@@ -2576,14 +2579,15 @@ static int wm_handler_fileselect_do(bContext *C,
int win_size[2];
bool is_maximized;
ED_fileselect_window_params_get(win, win_size, &is_maximized);
- ED_fileselect_params_to_userdef(file_area->spacedata.first, win_size, is_maximized);
+ ED_fileselect_params_to_userdef(
+ static_cast<SpaceFile *>(file_area->spacedata.first), win_size, is_maximized);
if (BLI_listbase_is_single(&file_area->spacedata)) {
BLI_assert(root_win != win);
wm_window_close(C, wm, win);
- CTX_wm_window_set(C, root_win); /* #wm_window_close() NULLs. */
+ CTX_wm_window_set(C, root_win); /* #wm_window_close() nullptrs. */
/* Some operators expect a drawable context (for #EVT_FILESELECT_EXEC). */
wm_window_make_drawable(wm, root_win);
/* Ensure correct cursor position, otherwise, popups may close immediately after
@@ -2603,7 +2607,8 @@ static int wm_handler_fileselect_do(bContext *C,
}
if (!temp_win && ctx_area->full) {
- ED_fileselect_params_to_userdef(ctx_area->spacedata.first, NULL, false);
+ ED_fileselect_params_to_userdef(
+ static_cast<SpaceFile *>(ctx_area->spacedata.first), nullptr, false);
ED_screen_full_prevspace(C, ctx_area);
}
}
@@ -2656,8 +2661,8 @@ static int wm_handler_fileselect_do(bContext *C,
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (win_prev == NULL) {
- CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
+ if (win_prev == nullptr) {
+ CTX_wm_window_set(C, static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first));
}
BKE_report_print_level_set(handler->op->reports, RPT_WARNING);
@@ -2701,7 +2706,7 @@ static int wm_handler_fileselect_do(bContext *C,
wm_operator_free_for_fileselect(handler->op);
}
- CTX_wm_area_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
wm_event_free_handler(&handler->head);
@@ -2763,18 +2768,18 @@ static const char *keymap_handler_log_kmi_op_str(bContext *C,
size_t buf_maxlen)
{
/* The key-map item properties can further help distinguish this item from others. */
- char *kmi_props = NULL;
- if (kmi->properties != NULL) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ char *kmi_props = nullptr;
+ if (kmi->properties != nullptr) {
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
if (ot) {
kmi_props = RNA_pointer_as_string_keywords(C, kmi->ptr, false, false, true, 512);
}
else { /* Fallback. */
- kmi_props = IDP_reprN(kmi->properties, NULL);
+ kmi_props = IDP_reprN(kmi->properties, nullptr);
}
}
BLI_snprintf(buf, buf_maxlen, "%s(%s)", kmi->idname, kmi_props ? kmi_props : "");
- if (kmi_props != NULL) {
+ if (kmi_props != nullptr) {
MEM_freeN(kmi_props);
}
return buf;
@@ -2796,8 +2801,8 @@ static int wm_handlers_do_keymap_with_keymap_handler(
{
int action = WM_HANDLER_CONTINUE;
- if (keymap == NULL) {
- /* Only callback is allowed to have NULL key-maps. */
+ if (keymap == nullptr) {
+ /* Only callback is allowed to have nullptr key-maps. */
BLI_assert(handler->dynamic.keymap_fn);
}
else {
@@ -2809,7 +2814,7 @@ static int wm_handlers_do_keymap_with_keymap_handler(
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if (wm_eventmatch(event, kmi)) {
- struct wmEventHandler_KeymapPost keymap_post = handler->post;
+ wmEventHandler_KeymapPost keymap_post = handler->post;
action |= wm_handler_operator_call(
C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
@@ -2826,7 +2831,7 @@ static int wm_handlers_do_keymap_with_keymap_handler(
if (action & WM_HANDLER_BREAK) {
/* Not always_pass here, it denotes removed handler_base. */
- if (keymap_post.post_fn != NULL) {
+ if (keymap_post.post_fn != nullptr) {
keymap_post.post_fn(keymap, kmi, keymap_post.user_data);
}
break;
@@ -2872,7 +2877,7 @@ static int wm_handlers_do_keymap_with_gizmo_handler(
action |= wm_handler_operator_call(
C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
- CTX_wm_gizmo_group_set(C, NULL);
+ CTX_wm_gizmo_group_set(C, nullptr);
if (action & WM_HANDLER_BREAK) {
if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
@@ -2922,7 +2927,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
wmGizmoMap *gzmap = handler->gizmo_map;
- BLI_assert(gzmap != NULL);
+ BLI_assert(gzmap != nullptr);
wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
/* Needed so UI blocks over gizmos don't let events fall through to the gizmos,
@@ -2930,25 +2935,25 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
* note we still allow for starting the gizmo drag outside, then travel 'inside' the node. */
if (region->type->clip_gizmo_events_by_ui) {
if (UI_region_block_find_mouse_over(region, event->xy, true)) {
- if (gz != NULL && event->type != EVT_GIZMO_UPDATE) {
+ if (gz != nullptr && event->type != EVT_GIZMO_UPDATE) {
if (restore_highlight_unless_activated == false) {
WM_tooltip_clear(C, CTX_wm_window(C));
- wm_gizmomap_highlight_set(gzmap, C, NULL, 0);
+ wm_gizmomap_highlight_set(gzmap, C, nullptr, 0);
}
}
return action;
}
}
- struct {
+ struct PrevGizmoData {
wmGizmo *gz_modal;
wmGizmo *gz;
int part;
- } prev = {
- .gz_modal = wm_gizmomap_modal_get(gzmap),
- .gz = gz,
- .part = gz ? gz->highlight_part : 0,
};
+ PrevGizmoData prev{};
+ prev.gz_modal = wm_gizmomap_modal_get(gzmap);
+ prev.gz = gz;
+ prev.part = gz ? gz->highlight_part : 0;
if (region->gizmo_map != handler->gizmo_map) {
WM_gizmomap_tag_refresh(handler->gizmo_map);
@@ -2961,7 +2966,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
bool handle_keymap = false;
/* Handle gizmo highlighting. */
- if ((prev.gz_modal == NULL) &&
+ if ((prev.gz_modal == nullptr) &&
((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) {
handle_highlight = true;
if (is_event_modifier || is_event_drag) {
@@ -2992,7 +2997,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
}
if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) {
- if (gz != NULL) {
+ if (gz != nullptr) {
if ((U.flag & USER_TOOLTIPS) && (gz->flag & WM_GIZMO_NO_TOOLTIP) == 0) {
WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init);
}
@@ -3005,7 +3010,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if (handle_keymap) {
/* Handle highlight gizmo. */
- if ((gz != NULL) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) {
+ if ((gz != nullptr) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) {
bool keymap_poll = false;
wmGizmoGroup *gzgroup = gz->parent_gzgroup;
wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap);
@@ -3026,7 +3031,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if ((kmi->flag & KMI_INACTIVE) == 0) {
if (wm_eventmatch(&event_test_click, kmi) ||
wm_eventmatch(&event_test_click_drag, kmi)) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) {
is_event_handle_all = true;
break;
@@ -3040,7 +3045,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
}
/* Don't use from now on. */
- gz = NULL;
+ gz = nullptr;
/* Fallback to selected gizmo (when un-handled). */
if ((action & WM_HANDLER_BREAK) == 0) {
@@ -3050,7 +3055,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if (wm_gizmogroup_is_any_selected(gzgroup)) {
wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap);
action |= wm_handlers_do_keymap_with_gizmo_handler(
- C, event, handlers, handler, gzgroup, keymap, do_debug_handler, NULL);
+ C, event, handlers, handler, gzgroup, keymap, do_debug_handler, nullptr);
if (action & WM_HANDLER_BREAK) {
break;
}
@@ -3099,7 +3104,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
wmWindowManager *wm = CTX_wm_manager(C);
int action = WM_HANDLER_CONTINUE;
- if (handlers == NULL) {
+ if (handlers == nullptr) {
wm_event_handler_return_value_check(event, action);
return action;
}
@@ -3110,7 +3115,8 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
* by the event that's called, for eg:
*
* Calling a python script which changes the area.type, see T32232. */
- for (wmEventHandler *handler_base = handlers->first, *handler_base_next;
+ for (wmEventHandler *handler_base = static_cast<wmEventHandler *>(handlers->first),
+ *handler_base_next;
handler_base && handlers->first;
handler_base = handler_base_next) {
handler_base_next = handler_base->next;
@@ -3119,7 +3125,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
if (handler_base->flag & WM_HANDLER_DO_FREE) {
/* Pass. */
}
- else if (handler_base->poll == NULL || handler_base->poll(CTX_wm_region(C), event)) {
+ else if (handler_base->poll == nullptr || handler_base->poll(CTX_wm_region(C), event)) {
/* In advance to avoid access to freed event on window close. */
const int always_pass = wm_event_always_pass(event);
@@ -3148,14 +3154,14 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
* are kept when a modal operators starts (annoying but otherwise harmless). */
if (action & WM_HANDLER_BREAK) {
/* Window may be gone after file read. */
- if (CTX_wm_window(C) != NULL) {
+ if (CTX_wm_window(C) != nullptr) {
WM_tooltip_clear(C, CTX_wm_window(C));
}
}
}
else if (handler_base->type == WM_HANDLER_TYPE_UI) {
wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
- BLI_assert(handler->handle_fn != NULL);
+ BLI_assert(handler->handle_fn != nullptr);
if (!wm->is_interface_locked) {
action |= wm_handler_ui_call(C, handler, event, always_pass);
}
@@ -3173,13 +3179,13 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
/* Pass single matched #wmDrag onto the operator. */
BLI_remlink(lb, drag);
- ListBase single_lb = {0};
+ ListBase single_lb = {nullptr};
BLI_addtail(&single_lb, drag);
event->customdata = &single_lb;
const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop);
int op_retval = wm_operator_call_internal(
- C, drop->ot, drop->ptr, NULL, opcontext, false, event);
+ C, drop->ot, drop->ptr, nullptr, opcontext, false, event);
OPERATOR_RETVAL_CHECK(op_retval);
if ((op_retval & OPERATOR_CANCELLED) && drop->cancel) {
@@ -3197,7 +3203,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
wm_drop_end(C, drag, drop);
/* XXX file-read case. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
return action;
}
@@ -3224,7 +3230,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
}
}
else {
- action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL, NULL);
+ action |= wm_handler_operator_call(C, handlers, handler_base, event, nullptr, nullptr);
}
}
else {
@@ -3244,7 +3250,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
/* File-read case, if the wm is freed then the handler's
* will have been too so the code below need not run. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
return action;
}
@@ -3265,7 +3271,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
}
/* Do some extra sanity checking before returning the action. */
- if (CTX_wm_window(C) != NULL) {
+ if (CTX_wm_window(C) != nullptr) {
wm_event_handler_return_value_check(event, action);
}
return action;
@@ -3278,9 +3284,9 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
{
int action = wm_handlers_do_intern(C, CTX_wm_window(C), event, handlers);
- /* Will be NULL in the file read case. */
+ /* Will be nullptr in the file read case. */
wmWindow *win = CTX_wm_window(C);
- if (win == NULL) {
+ if (win == nullptr) {
return action;
}
@@ -3374,7 +3380,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
if (event->val == KM_RELEASE) {
if (event->prev_val == KM_PRESS) {
- if (win->event_queue_check_click == true) {
+ if (win->event_queue_check_click) {
if (WM_event_drag_test(event, event->prev_press_xy)) {
win->event_queue_check_click = false;
if (win->event_queue_check_drag) {
@@ -3387,7 +3393,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
else {
/* Position is where the actual click happens, for more
* accurate selecting in case the mouse drifts a little. */
- int xy[2] = {UNPACK2(event->xy)};
+ const int xy[2] = {UNPACK2(event->xy)};
copy_v2_v2_int(event->xy, event->prev_press_xy);
event->val = KM_CLICK;
@@ -3474,7 +3480,7 @@ static ScrArea *area_event_inside(bContext *C, const int xy[2])
}
}
}
- return NULL;
+ return nullptr;
}
static ARegion *region_event_inside(bContext *C, const int xy[2])
@@ -3489,14 +3495,14 @@ static ARegion *region_event_inside(bContext *C, const int xy[2])
}
}
}
- return NULL;
+ return nullptr;
}
static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *region)
{
if (region) {
for (; pc; pc = pc->next) {
- if (pc->poll == NULL || pc->poll(C)) {
+ if (pc->poll == nullptr || pc->poll(C)) {
wmWindow *win = CTX_wm_window(C);
WM_paint_cursor_tag_redraw(win, region);
}
@@ -3517,17 +3523,18 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event)
ARegion *region = CTX_wm_region(C);
if (region) {
- wm_paintcursor_tag(C, wm->paintcursors.first, region);
+ wm_paintcursor_tag(C, static_cast<wmPaintCursor *>(wm->paintcursors.first), region);
}
/* If previous position was not in current region, we have to set a temp new context. */
- if (region == NULL || !BLI_rcti_isect_pt_v(&region->winrct, event->prev_xy)) {
+ if (region == nullptr || !BLI_rcti_isect_pt_v(&region->winrct, event->prev_xy)) {
ScrArea *area = CTX_wm_area(C);
CTX_wm_area_set(C, area_event_inside(C, event->prev_xy));
CTX_wm_region_set(C, region_event_inside(C, event->prev_xy));
- wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
+ wm_paintcursor_tag(
+ C, static_cast<wmPaintCursor *>(wm->paintcursors.first), CTX_wm_region(C));
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
@@ -3644,27 +3651,29 @@ static void wm_event_handle_xrevent(bContext *C,
int action = wm_handlers_do(C, event, &win->modalhandlers);
if ((action & WM_HANDLER_BREAK) == 0) {
- wmXrActionData *actiondata = event->customdata;
+ wmXrActionData *actiondata = static_cast<wmXrActionData *>(event->customdata);
if (actiondata->ot->modal && event->val == KM_RELEASE) {
/* Don't execute modal operators on release. */
}
else {
- PointerRNA properties = {.type = actiondata->ot->srna, .data = actiondata->op_properties};
+ PointerRNA properties{};
+ properties.type = actiondata->ot->srna;
+ properties.data = actiondata->op_properties;
if (actiondata->ot->invoke) {
/* Invoke operator, either executing operator or transferring responsibility to window
* modal handlers. */
wm_operator_invoke(C,
actiondata->ot,
event,
- actiondata->op_properties ? &properties : NULL,
- NULL,
+ actiondata->op_properties ? &properties : nullptr,
+ nullptr,
false,
false);
}
else {
/* Execute operator. */
wmOperator *op = wm_operator_create(
- wm, actiondata->ot, actiondata->op_properties ? &properties : NULL, NULL);
+ wm, actiondata->ot, actiondata->op_properties ? &properties : nullptr, nullptr);
if ((WM_operator_call(C, op) & OPERATOR_HANDLED) == 0) {
WM_operator_free(op);
}
@@ -3672,8 +3681,8 @@ static void wm_event_handle_xrevent(bContext *C,
}
}
- CTX_wm_region_set(C, NULL);
- CTX_wm_area_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
+ CTX_wm_area_set(C, nullptr);
}
#endif /* WITH_XR_OPENXR */
@@ -3743,16 +3752,16 @@ void wm_event_do_handlers(bContext *C)
BLI_assert(WM_window_get_active_screen(win));
BLI_assert(WM_window_get_active_workspace(win));
- if (screen == NULL) {
+ if (screen == nullptr) {
wm_event_free_all(win);
}
else {
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
- Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL;
+ Scene *scene_eval = (depsgraph != nullptr) ? DEG_get_evaluated_scene(depsgraph) : nullptr;
- if (scene_eval != NULL) {
+ if (scene_eval != nullptr) {
const int is_playing_sound = BKE_sound_scene_playing(scene_eval);
if (scene_eval->id.recalc & ID_RECALC_FRAME_CHANGE) {
@@ -3762,7 +3771,7 @@ void wm_event_do_handlers(bContext *C)
else if (is_playing_sound != -1) {
bool is_playing_screen;
- is_playing_screen = (ED_screen_animation_playing(wm) != NULL);
+ is_playing_screen = (ED_screen_animation_playing(wm) != nullptr);
if (((is_playing_sound == 1) && (is_playing_screen == 0)) ||
((is_playing_sound == 0) && (is_playing_screen == 1))) {
@@ -3788,7 +3797,7 @@ void wm_event_do_handlers(bContext *C)
if (ncfra != scene->r.cfra) {
scene->r.cfra = ncfra;
ED_update_for_newframe(CTX_data_main(C), depsgraph);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
}
}
@@ -3797,7 +3806,7 @@ void wm_event_do_handlers(bContext *C)
}
wmEvent *event;
- while ((event = win->event_queue.first)) {
+ while ((event = static_cast<wmEvent *>(win->event_queue.first))) {
int action = WM_HANDLER_CONTINUE;
/* Force handling drag if a key is pressed even if the drag threshold has not been met.
@@ -3869,7 +3878,7 @@ void wm_event_do_handlers(bContext *C)
action |= wm_handlers_do(C, event, &win->modalhandlers);
/* File-read case. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
@@ -3905,7 +3914,7 @@ void wm_event_do_handlers(bContext *C)
ED_screen_areas_iter (win, screen, area) {
/* After restoring a screen from SCREENMAXIMIZED we have to wait
* with the screen handling till the region coordinates are updated. */
- if (screen->skip_handling == true) {
+ if (screen->skip_handling) {
/* Restore for the next iteration of wm_event_do_handlers. */
screen->skip_handling = false;
break;
@@ -3923,18 +3932,18 @@ void wm_event_do_handlers(bContext *C)
action |= wm_event_do_handlers_area_regions(C, event, area);
/* File-read case (Python), T29489. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
- CTX_wm_region_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
if ((action & WM_HANDLER_BREAK) == 0) {
wm_region_mouse_co(C, event); /* Only invalidates `event->mval` in this case. */
action |= wm_handlers_do(C, event, &area->handlers);
}
- CTX_wm_area_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
/* NOTE: do not escape on #WM_HANDLER_BREAK,
* mouse-move needs handled for previous area. */
@@ -3951,7 +3960,7 @@ void wm_event_do_handlers(bContext *C)
action |= wm_handlers_do(C, event, &win->handlers);
/* File-read case. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
@@ -3992,12 +4001,12 @@ void wm_event_do_handlers(bContext *C)
tevent.val = KM_NOTHING;
tevent.prev_xy[0] = tevent.xy[0];
tevent.prev_xy[1] = tevent.xy[1];
- tevent.flag = 0;
+ tevent.flag = (eWM_EventFlag)0;
wm_event_add(win, &tevent);
win->addmousemove = 0;
}
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
/* Update key configuration after handling events. */
@@ -4019,7 +4028,7 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval
event.type = EVT_FILESELECT;
event.val = eventval;
- event.flag = 0;
+ event.flag = (eWM_EventFlag)0;
event.customdata = ophandle; /* Only as void pointer type check. */
wm_event_add(win, &event);
@@ -4063,8 +4072,9 @@ static wmWindow *wm_event_find_fileselect_root_window_from_context(const bContex
/* Fallback to the first window. */
const wmWindowManager *wm = CTX_wm_manager(C);
- BLI_assert(!ED_fileselect_handler_area_find_any_with_op(wm->windows.first));
- return wm->windows.first;
+ BLI_assert(!ED_fileselect_handler_area_find_any_with_op(
+ static_cast<const wmWindow *>(wm->windows.first)));
+ return static_cast<wmWindow *>(wm->windows.first);
}
/* Operator is supposed to have a filled "path" property. */
@@ -4079,8 +4089,8 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
* File Browser operation, to be restored for eventually executing the file operation. */
wmWindow *root_win = wm_event_find_fileselect_root_window_from_context(C);
/* Determined later. */
- ScrArea *root_area = NULL;
- ARegion *root_region = NULL;
+ ScrArea *root_area = nullptr;
+ ARegion *root_region = nullptr;
/* Close any popups, like when opening a file browser from the splash. */
UI_popup_handlers_remove_all(C, &root_win->modalhandlers);
@@ -4117,7 +4127,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
}
}
- BLI_assert(root_win != NULL);
+ BLI_assert(root_win != nullptr);
/* When not reusing the root context from a previous file browsing operation, use the current
* area & region, if they are inside the root window. */
if (!root_area && ctx_win == root_win) {
@@ -4125,7 +4135,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
root_region = CTX_wm_region(C);
}
- wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Op *handler = MEM_cnew<wmEventHandler_Op>(__func__);
handler->head.type = WM_HANDLER_TYPE_OP;
handler->is_fileselect = true;
@@ -4165,7 +4175,7 @@ static void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
wmEventHandler_Op *WM_event_add_modal_handler(bContext *C, wmOperator *op)
{
- wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Op *handler = MEM_cnew<wmEventHandler_Op>(__func__);
handler->head.type = WM_HANDLER_TYPE_OP;
wmWindow *win = CTX_wm_window(C);
@@ -4219,7 +4229,7 @@ void WM_event_modal_handler_region_replace(wmWindow *win,
* it needs to keep old region stored in handler, so don't change it. */
if ((handler->context.region == old_region) && (handler->is_fileselect == false)) {
handler->context.region = new_region;
- handler->context.region_type = new_region ? new_region->regiontype : RGN_TYPE_WINDOW;
+ handler->context.region_type = new_region ? new_region->regiontype : (int)RGN_TYPE_WINDOW;
}
}
}
@@ -4228,8 +4238,8 @@ void WM_event_modal_handler_region_replace(wmWindow *win,
wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
{
if (!keymap) {
- CLOG_WARN(WM_LOG_HANDLERS, "called with NULL key-map");
- return NULL;
+ CLOG_WARN(WM_LOG_HANDLERS, "called with nullptr key-map");
+ return nullptr;
}
/* Only allow same key-map once. */
@@ -4242,7 +4252,7 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap
}
}
- wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>(__func__);
handler->head.type = WM_HANDLER_TYPE_KEYMAP;
BLI_addtail(handlers, handler);
handler->keymap = keymap;
@@ -4274,16 +4284,16 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
const char *keymap_id_list[ARRAY_SIZE(km_result->keymaps)];
int keymap_id_list_len = 0;
- /* NOTE(@campbellbarton): If `win` is NULL, this function may not behave as expected.
+ /* NOTE(@campbellbarton): If `win` is nullptr, this function may not behave as expected.
* Assert since this should not happen in practice.
* If it does, the window could be looked up in `wm` using the `area`.
- * Keep NULL checks in run-time code since any crashes here are difficult to redo. */
- BLI_assert_msg(win != NULL, "The window should always be set for tool interactions!");
- const Scene *scene = win ? win->scene : NULL;
+ * Keep nullptr checks in run-time code since any crashes here are difficult to redo. */
+ BLI_assert_msg(win != nullptr, "The window should always be set for tool interactions!");
+ const Scene *scene = win ? win->scene : nullptr;
- ScrArea *area = handler->dynamic.user_data;
- handler->keymap_tool = NULL;
- bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL;
+ ScrArea *area = static_cast<ScrArea *>(handler->dynamic.user_data);
+ handler->keymap_tool = nullptr;
+ bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : nullptr;
if (tref_rt && tref_rt->keymap[0]) {
keymap_id_list[keymap_id_list_len++] = tref_rt->keymap;
@@ -4302,18 +4312,18 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
}
if (with_gizmos && (tref_rt->gizmo_group[0] != '\0')) {
- wmGizmoMap *gzmap = NULL;
- wmGizmoGroup *gzgroup = NULL;
+ wmGizmoMap *gzmap = nullptr;
+ wmGizmoGroup *gzgroup = nullptr;
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- if (region->gizmo_map != NULL) {
+ if (region->gizmo_map != nullptr) {
gzmap = region->gizmo_map;
gzgroup = WM_gizmomap_group_find(gzmap, tref_rt->gizmo_group);
- if (gzgroup != NULL) {
+ if (gzgroup != nullptr) {
break;
}
}
}
- if (gzgroup != NULL) {
+ if (gzgroup != nullptr) {
if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
/* If all are hidden, don't override. */
is_gizmo_visible = true;
@@ -4344,7 +4354,7 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
&wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW);
/* We shouldn't use key-maps from unrelated spaces. */
- if (km == NULL) {
+ if (km == nullptr) {
printf("Key-map: '%s' not found for tool '%s'\n", keymap_id, area->runtime.tool->idname);
continue;
}
@@ -4369,12 +4379,12 @@ void WM_event_get_keymap_from_toolsystem(wmWindowManager *wm,
wm_event_get_keymap_from_toolsystem_ex(wm, win, handler, km_result, false);
}
-struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
+wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
ListBase *handlers, wmEventHandler_KeymapDynamicFn *keymap_fn, void *user_data)
{
if (!keymap_fn) {
- CLOG_WARN(WM_LOG_HANDLERS, "called with NULL keymap_fn");
- return NULL;
+ CLOG_WARN(WM_LOG_HANDLERS, "called with nullptr keymap_fn");
+ return nullptr;
}
/* Only allow same key-map once. */
@@ -4389,7 +4399,7 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
}
}
- wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>(__func__);
handler->head.type = WM_HANDLER_TYPE_KEYMAP;
BLI_addtail(handlers, handler);
handler->dynamic.keymap_fn = keymap_fn;
@@ -4404,7 +4414,7 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers,
{
WM_event_remove_keymap_handler(handlers, keymap);
- wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), "event key-map handler");
+ wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>("event key-map handler");
handler->head.type = WM_HANDLER_TYPE_KEYMAP;
BLI_addhead(handlers, handler);
@@ -4436,8 +4446,8 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler_poll(ListBase *handlers,
EventHandlerPoll poll)
{
wmEventHandler_Keymap *handler = WM_event_add_keymap_handler(handlers, keymap);
- if (handler == NULL) {
- return NULL;
+ if (handler == nullptr) {
+ return nullptr;
}
handler->head.poll = poll;
@@ -4480,7 +4490,7 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C,
void *user_data,
const char flag)
{
- wmEventHandler_UI *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_UI *handler = MEM_cnew<wmEventHandler_UI>(__func__);
handler->head.type = WM_HANDLER_TYPE_UI;
handler->handle_fn = handle_fn;
handler->remove_fn = remove_fn;
@@ -4491,9 +4501,9 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C,
handler->context.menu = CTX_wm_menu(C);
}
else {
- handler->context.area = NULL;
- handler->context.region = NULL;
- handler->context.menu = NULL;
+ handler->context.area = nullptr;
+ handler->context.region = nullptr;
+ handler->context.menu = nullptr;
}
BLI_assert((flag & WM_HANDLER_DO_FREE) == 0);
@@ -4558,7 +4568,7 @@ wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers, ListBas
}
}
- wmEventHandler_Dropbox *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Dropbox *handler = MEM_cnew<wmEventHandler_Dropbox>(__func__);
handler->head.type = WM_HANDLER_TYPE_DROPBOX;
/* Dropbox stored static, no free or copy. */
@@ -4583,6 +4593,20 @@ void WM_event_remove_area_handler(ListBase *handlers, void *area)
}
}
+wmOperator *WM_operator_find_modal_by_type(wmWindow *win, const wmOperatorType *ot)
+{
+ LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
+ if (handler_base->type != WM_HANDLER_TYPE_OP) {
+ continue;
+ }
+ wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
+ if (handler->op && handler->op->type == ot) {
+ return handler->op;
+ }
+ }
+ return nullptr;
+}
+
#if 0
static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
{
@@ -4853,22 +4877,25 @@ static void wm_eventemulation(wmEvent *event, bool test_only)
}
}
-static const wmTabletData wm_event_tablet_data_default = {
- .active = EVT_TABLET_NONE,
- .pressure = 1.0f,
- .x_tilt = 0.0f,
- .y_tilt = 0.0f,
- .is_motion_absolute = false,
-};
+constexpr wmTabletData wm_event_tablet_data_default()
+{
+ wmTabletData tablet_data{};
+ tablet_data.active = EVT_TABLET_NONE;
+ tablet_data.pressure = 1.0f;
+ tablet_data.x_tilt = 0.0f;
+ tablet_data.y_tilt = 0.0f;
+ tablet_data.is_motion_absolute = false;
+ return tablet_data;
+}
void WM_event_tablet_data_default_set(wmTabletData *tablet_data)
{
- *tablet_data = wm_event_tablet_data_default;
+ *tablet_data = wm_event_tablet_data_default();
}
void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab)
{
- if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) {
+ if ((tablet_data != nullptr) && tablet_data->Active != GHOST_kTabletModeNone) {
wmtab->active = (int)tablet_data->Active;
wmtab->pressure = wm_pressure_curve(tablet_data->Pressure);
wmtab->x_tilt = tablet_data->Xtilt;
@@ -4878,7 +4905,7 @@ void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData
// printf("%s: using tablet %.5f\n", __func__, wmtab->pressure);
}
else {
- *wmtab = wm_event_tablet_data_default;
+ *wmtab = wm_event_tablet_data_default();
// printf("%s: not using tablet\n", __func__);
}
}
@@ -4887,7 +4914,7 @@ void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData
/* Adds custom-data to event. */
static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *ghost)
{
- wmNDOFMotionData *data = MEM_mallocN(sizeof(wmNDOFMotionData), "Custom-data NDOF");
+ wmNDOFMotionData *data = MEM_cnew<wmNDOFMotionData>("Custom-data NDOF");
const float ts = U.ndof_sensitivity;
const float rs = U.ndof_orbit_sensitivity;
@@ -4915,33 +4942,38 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g
/* Imperfect but probably usable... draw/enable drags to other windows. */
static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event)
{
- int mval[2] = {event->xy[0], event->xy[1]};
+ /* If GHOST doesn't support window positioning, don't use this feature at all. */
+ const static int8_t supports_window_position = GHOST_SupportsWindowPosition();
+ if (!supports_window_position) {
+ return nullptr;
+ }
if (wm->windows.first == wm->windows.last) {
- return NULL;
+ return nullptr;
}
/* In order to use window size and mouse position (pixels), we have to use a WM function. */
/* Check if outside, include top window bar. */
- if (mval[0] < 0 || mval[1] < 0 || mval[0] > WM_window_pixels_x(win) ||
- mval[1] > WM_window_pixels_y(win) + 30) {
+ int event_xy[2] = {UNPACK2(event->xy)};
+ if (event_xy[0] < 0 || event_xy[1] < 0 || event_xy[0] > WM_window_pixels_x(win) ||
+ event_xy[1] > WM_window_pixels_y(win) + 30) {
/* Let's skip windows having modal handlers now. */
/* Potential XXX ugly... I wouldn't have added a `modalhandlers` list
* (introduced in rev 23331, ton). */
LISTBASE_FOREACH (wmEventHandler *, handler, &win->modalhandlers) {
if (ELEM(handler->type, WM_HANDLER_TYPE_UI, WM_HANDLER_TYPE_OP)) {
- return NULL;
+ return nullptr;
}
}
- wmWindow *win_other = WM_window_find_under_cursor(win, mval, mval);
+ wmWindow *win_other = WM_window_find_under_cursor(win, event_xy, event_xy);
if (win_other && win_other != win) {
- copy_v2_v2_int(event->xy, mval);
+ copy_v2_v2_int(event->xy, event_xy);
return win_other;
}
}
- return NULL;
+ return nullptr;
}
static bool wm_event_is_double_click(const wmEvent *event)
@@ -4982,18 +5014,18 @@ static void wm_event_prev_click_set(wmEvent *event_state)
static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
{
- wmEvent *event_last = win->event_queue.last;
+ wmEvent *event_last = static_cast<wmEvent *>(win->event_queue.last);
/* Some painting operators want accurate mouse events, they can
* handle in between mouse move moves, others can happily ignore
* them for better performance. */
if (event_last && event_last->type == MOUSEMOVE) {
event_last->type = INBETWEEN_MOUSEMOVE;
- event_last->flag = 0;
+ event_last->flag = (eWM_EventFlag)0;
}
wmEvent *event_new = wm_event_add(win, event);
- if (event_last == NULL) {
+ if (event_last == nullptr) {
event_last = win->eventstate;
}
@@ -5012,7 +5044,7 @@ static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win)
if (event_last) {
tevent = *event_last;
- tevent.flag = 0;
+ tevent.flag = (eWM_EventFlag)0;
tevent.ascii = '\0';
tevent.utf8_buf[0] = '\0';
@@ -5038,7 +5070,7 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d
{
/* Ignore in between track-pad events for performance, we only need high accuracy
* for painting with mouse moves, for navigation using the accumulated value is ok. */
- wmEvent *event_last = win->event_queue.last;
+ wmEvent *event_last = static_cast<wmEvent *>(win->event_queue.last);
if (event_last && event_last->type == event->type) {
deltax += event_last->xy[0] - event_last->prev_xy[0];
deltay += event_last->xy[1] - event_last->prev_xy[1];
@@ -5127,7 +5159,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
/* Initialize and copy state (only mouse x y and modifiers). */
event = *event_state;
- event.flag = 0;
+ event.flag = (eWM_EventFlag)0;
/**
* Always support accessing the last key press/release. This is set from `win->eventstate`,
@@ -5164,7 +5196,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
switch (type) {
/* Mouse move, also to inactive window (X11 does this). */
case GHOST_kEventCursorMove: {
- GHOST_TEventCursorData *cd = customdata;
+ GHOST_TEventCursorData *cd = static_cast<GHOST_TEventCursorData *>(customdata);
copy_v2_v2_int(event.xy, &cd->x);
wm_stereo3d_mouse_offset_apply(win, event.xy);
@@ -5201,7 +5233,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
break;
}
case GHOST_kEventTrackpad: {
- GHOST_TEventTrackpadData *pd = customdata;
+ GHOST_TEventTrackpadData *pd = static_cast<GHOST_TEventTrackpadData *>(customdata);
switch (pd->subtype) {
case GHOST_kTrackpadEventMagnify:
event.type = MOUSEZOOM;
@@ -5235,7 +5267,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
/* Mouse button. */
case GHOST_kEventButtonDown:
case GHOST_kEventButtonUp: {
- GHOST_TEventButtonData *bd = customdata;
+ GHOST_TEventButtonData *bd = static_cast<GHOST_TEventButtonData *>(customdata);
/* Get value and type from Ghost. */
event.val = (type == GHOST_kEventButtonDown) ? KM_PRESS : KM_RELEASE;
@@ -5266,7 +5298,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
wm_tablet_data_from_ghost(&bd->tablet, &event.tablet);
wm_eventemulation(&event, false);
- wm_event_state_update_and_click_set(&event, event_state, type);
+ wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type);
/* Add to other window if event is there (not to both!). */
wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event);
@@ -5294,14 +5326,14 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
/* Keyboard. */
case GHOST_kEventKeyDown:
case GHOST_kEventKeyUp: {
- GHOST_TEventKeyData *kd = customdata;
+ GHOST_TEventKeyData *kd = static_cast<GHOST_TEventKeyData *>(customdata);
event.type = convert_key(kd->key);
if (UNLIKELY(event.type == EVENT_NONE)) {
break;
}
event.ascii = kd->ascii;
- /* Might be not NULL terminated. */
+ /* Might be not nullptr terminated. */
memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf));
if (kd->is_repeat) {
event.flag |= WM_EVENT_IS_REPEAT;
@@ -5390,7 +5422,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
/* It's important `event.modifier` has been initialized first. */
- wm_event_state_update_and_click_set(&event, event_state, type);
+ wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type);
/* If test_break set, it catches this. Do not set with modifier presses.
* Exclude modifiers because MS-Windows uses these to bring up the task manager.
@@ -5409,7 +5441,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
case GHOST_kEventWheel: {
- GHOST_TEventWheelData *wheelData = customdata;
+ GHOST_TEventWheelData *wheelData = static_cast<GHOST_TEventWheelData *>(customdata);
if (wheelData->z > 0) {
event.type = WHEELUPMOUSE;
@@ -5438,7 +5470,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
case GHOST_kEventNDOFMotion: {
event.type = NDOF_MOTION;
event.val = KM_NOTHING;
- attach_ndof_data(&event, customdata);
+ attach_ndof_data(&event, static_cast<const GHOST_TEventNDOFMotionData *>(customdata));
wm_event_add(win, &event);
CLOG_INFO(WM_LOG_HANDLERS, 1, "sending NDOF_MOTION, prev = %d %d", event.xy[0], event.xy[1]);
@@ -5446,7 +5478,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
case GHOST_kEventNDOFButton: {
- GHOST_TEventNDOFButtonData *e = customdata;
+ GHOST_TEventNDOFButtonData *e = static_cast<GHOST_TEventNDOFButtonData *>(customdata);
event.type = NDOF_BUTTON_NONE + e->button;
@@ -5462,9 +5494,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
event.custom = 0;
- event.customdata = NULL;
+ event.customdata = nullptr;
- wm_event_state_update_and_click_set(&event, event_state, type);
+ wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type);
wm_event_add(win, &event);
@@ -5486,7 +5518,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
#ifdef WITH_INPUT_IME
case GHOST_kEventImeCompositionStart: {
event.val = KM_PRESS;
- win->ime_data = customdata;
+ win->ime_data = static_cast<wmIMEData *>(customdata);
win->ime_data->is_ime_composing = true;
event.type = WM_IME_COMPOSITE_START;
wm_event_add(win, &event);
@@ -5520,14 +5552,13 @@ void wm_event_add_xrevent(wmWindow *win, wmXrActionData *actiondata, short val)
{
BLI_assert(ELEM(val, KM_PRESS, KM_RELEASE));
- wmEvent event = {
- .type = EVT_XR_ACTION,
- .val = val,
- .flag = 0,
- .custom = EVT_DATA_XR,
- .customdata = actiondata,
- .customdata_free = true,
- };
+ wmEvent event{};
+ event.type = EVT_XR_ACTION;
+ event.val = val;
+ event.flag = (eWM_EventFlag)0;
+ event.custom = EVT_DATA_XR;
+ event.customdata = actiondata;
+ event.customdata_free = true;
wm_event_add(win, &event);
}
@@ -5588,15 +5619,15 @@ void WM_event_get_keymaps_from_handler(wmWindowManager *wm,
wmEventHandler_Keymap *handler,
wmEventHandler_KeymapResult *km_result)
{
- if (handler->dynamic.keymap_fn != NULL) {
+ if (handler->dynamic.keymap_fn != nullptr) {
handler->dynamic.keymap_fn(wm, win, handler, km_result);
- BLI_assert(handler->keymap == NULL);
+ BLI_assert(handler->keymap == nullptr);
}
else {
memset(km_result, 0x0, sizeof(*km_result));
wmKeyMap *keymap = WM_keymap_active(wm, handler->keymap);
- BLI_assert(keymap != NULL);
- if (keymap != NULL) {
+ BLI_assert(keymap != nullptr);
+ if (keymap != nullptr) {
km_result->keymaps[km_result->keymaps_len++] = keymap;
}
}
@@ -5606,13 +5637,13 @@ wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wm
{
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if (wm_eventmatch(event, kmi)) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) {
return kmi;
}
}
}
- return NULL;
+ return nullptr;
}
wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
@@ -5623,7 +5654,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
if (handler_base->flag & WM_HANDLER_DO_FREE) {
/* Pass. */
}
- else if (handler_base->poll == NULL || handler_base->poll(CTX_wm_region(C), event)) {
+ else if (handler_base->poll == nullptr || handler_base->poll(CTX_wm_region(C), event)) {
if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
wmEventHandler_KeymapResult km_result;
@@ -5632,7 +5663,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
wmKeyMap *keymap = km_result.keymaps[km_index];
if (WM_keymap_poll(C, keymap)) {
wmKeyMapItem *kmi = WM_event_match_keymap_item(C, keymap, event);
- if (kmi != NULL) {
+ if (kmi != nullptr) {
return kmi;
}
}
@@ -5640,7 +5671,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
}
}
}
- return NULL;
+ return nullptr;
}
/** \} */
@@ -5670,10 +5701,10 @@ struct CursorKeymapInfo {
*/
char text[3][2][128];
wmEvent state_event;
- struct CursorKeymapInfo_State state;
+ CursorKeymapInfo_State state;
};
-static void wm_event_cursor_store(struct CursorKeymapInfo_State *state,
+static void wm_event_cursor_store(CursorKeymapInfo_State *state,
const wmEvent *event,
short space_type,
short region_type,
@@ -5682,29 +5713,29 @@ static void wm_event_cursor_store(struct CursorKeymapInfo_State *state,
state->modifier = event->modifier;
state->space_type = space_type;
state->region_type = region_type;
- state->tref = tref ? *tref : (bToolRef){0};
+ state->tref = tref ? *tref : bToolRef{};
}
const char *WM_window_cursor_keymap_status_get(const wmWindow *win,
int button_index,
int type_index)
{
- if (win->cursor_keymap_status != NULL) {
- struct CursorKeymapInfo *cd = win->cursor_keymap_status;
+ if (win->cursor_keymap_status != nullptr) {
+ CursorKeymapInfo *cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status);
const char *msg = cd->text[button_index][type_index];
if (*msg) {
return msg;
}
}
- return NULL;
+ return nullptr;
}
ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen)
{
if (screen->state == SCREENFULL) {
- return NULL;
+ return nullptr;
}
- ScrArea *area_statusbar = NULL;
+ ScrArea *area_statusbar = nullptr;
LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
if (area->spacetype == SPACE_STATUSBAR) {
area_statusbar = area;
@@ -5718,7 +5749,7 @@ void WM_window_status_area_tag_redraw(wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
ScrArea *area = WM_window_status_area_find(win, screen);
- if (area != NULL) {
+ if (area != nullptr) {
ED_area_tag_redraw(area);
}
}
@@ -5727,16 +5758,16 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
ScrArea *area_statusbar = WM_window_status_area_find(win, screen);
- if (area_statusbar == NULL) {
+ if (area_statusbar == nullptr) {
MEM_SAFE_FREE(win->cursor_keymap_status);
return;
}
- struct CursorKeymapInfo *cd;
- if (UNLIKELY(win->cursor_keymap_status == NULL)) {
- win->cursor_keymap_status = MEM_callocN(sizeof(struct CursorKeymapInfo), __func__);
+ CursorKeymapInfo *cd;
+ if (UNLIKELY(win->cursor_keymap_status == nullptr)) {
+ win->cursor_keymap_status = MEM_callocN(sizeof(CursorKeymapInfo), __func__);
}
- cd = win->cursor_keymap_status;
+ cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status);
/* Detect unchanged state (early exit). */
if (memcmp(&cd->state_event, win->eventstate, sizeof(wmEvent)) == 0) {
@@ -5745,23 +5776,23 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
/* Now perform more comprehensive check,
* still keep this fast since it happens on mouse-move. */
- struct CursorKeymapInfo cd_prev = *((struct CursorKeymapInfo *)win->cursor_keymap_status);
+ CursorKeymapInfo cd_prev = *((CursorKeymapInfo *)win->cursor_keymap_status);
cd->state_event = *win->eventstate;
/* Find active region and associated area. */
ARegion *region = screen->active_region;
- if (region == NULL) {
+ if (region == nullptr) {
return;
}
- ScrArea *area = NULL;
+ ScrArea *area = nullptr;
ED_screen_areas_iter (win, screen, area_iter) {
if (BLI_findindex(&area_iter->regionbase, region) != -1) {
area = area_iter;
break;
}
}
- if (area == NULL) {
+ if (area == nullptr) {
return;
}
@@ -5784,15 +5815,14 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
/* Detect changes to the state. */
{
- bToolRef *tref = NULL;
+ bToolRef *tref = nullptr;
if ((region->regiontype == RGN_TYPE_WINDOW) &&
((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK)) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
WorkSpace *workspace = WM_window_get_active_workspace(win);
- const bToolKey tkey = {
- .space_type = area->spacetype,
- .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
- };
+ bToolKey tkey{};
+ tkey.space_type = area->spacetype;
+ tkey.mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype);
tref = WM_toolsystem_ref_find(workspace, &tkey);
}
wm_event_cursor_store(&cd->state, win->eventstate, area->spacetype, region->regiontype, tref);
@@ -5846,9 +5876,9 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
wmEvent test_event = *win->eventstate;
test_event.type = event_data[data_index].event_type;
test_event.val = event_data[data_index].event_value;
- test_event.flag = 0;
+ test_event.flag = (eWM_EventFlag)0;
wm_eventemulation(&test_event, true);
- wmKeyMapItem *kmi = NULL;
+ wmKeyMapItem *kmi = nullptr;
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
kmi = WM_event_match_keymap_item_from_handlers(
C, wm, win, handlers[handler_index], &test_event);
@@ -5857,7 +5887,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
}
}
if (kmi) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
const char *name = (ot) ? WM_operatortype_name(ot, kmi->ptr) : kmi->idname;
STRNCPY(cd->text[button_index][type_index], name);
}
@@ -5867,7 +5897,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
ED_area_tag_redraw(area_statusbar);
}
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
/** \} */
@@ -5879,12 +5909,12 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *layout)
{
wmWindowManager *wm = CTX_wm_manager(C);
- wmKeyMap *keymap = NULL;
- wmOperator *op = NULL;
+ wmKeyMap *keymap = nullptr;
+ wmOperator *op = nullptr;
LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
if (handler_base->type == WM_HANDLER_TYPE_OP) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
- if (handler->op != NULL) {
+ if (handler->op != nullptr) {
/* 'handler->keymap' could be checked too, seems not to be used. */
wmKeyMap *keymap_test = WM_keymap_active(wm, handler->op->type->modalkeymap);
if (keymap_test && keymap_test->modal_items) {
@@ -5895,17 +5925,17 @@ bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *la
}
}
}
- if (keymap == NULL || keymap->modal_items == NULL) {
+ if (keymap == nullptr || keymap->modal_items == nullptr) {
return false;
}
- const EnumPropertyItem *items = keymap->modal_items;
+ const EnumPropertyItem *items = static_cast<const EnumPropertyItem *>(keymap->modal_items);
uiLayout *row = uiLayoutRow(layout, true);
for (int i = 0; items[i].identifier; i++) {
if (!items[i].identifier[0]) {
continue;
}
- if ((keymap->poll_modal_item != NULL) &&
+ if ((keymap->poll_modal_item != nullptr) &&
(keymap->poll_modal_item(op, items[i].value) == false)) {
continue;
}
@@ -5914,13 +5944,13 @@ bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *la
{
/* WARNING: O(n^2). */
- wmKeyMapItem *kmi = NULL;
- for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ wmKeyMapItem *kmi = nullptr;
+ for (kmi = static_cast<wmKeyMapItem *>(keymap->items.first); kmi; kmi = kmi->next) {
if (kmi->propvalue == items[i].value) {
break;
}
}
- if (kmi != NULL) {
+ if (kmi != nullptr) {
if (kmi->val == KM_RELEASE) {
/* Assume release events just disable something which was toggled on. */
continue;
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 9578f82d3d4..a170fa9902b 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -1096,7 +1096,7 @@ void wm_homefile_read_ex(bContext *C,
const bool reset_app_template = ((!app_template && U.app_template[0]) ||
(app_template && !STREQ(app_template, U.app_template)));
- /* options exclude eachother */
+ /* Options exclude each other. */
BLI_assert((use_factory_settings && filepath_startup_override) == 0);
if ((G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) == 0) {
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index b41ffb4cfc2..f2c41dada48 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -438,7 +438,7 @@ void WM_OT_link(wmOperatorType *ot)
ot->exec = wm_link_append_exec;
ot->poll = wm_link_append_poll;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB,
@@ -462,7 +462,7 @@ void WM_OT_append(wmOperatorType *ot)
ot->exec = wm_link_append_exec;
ot->poll = wm_link_append_poll;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB,
@@ -803,7 +803,7 @@ void WM_OT_lib_relocate(wmOperatorType *ot)
ot->invoke = wm_lib_relocate_invoke;
ot->exec = wm_lib_relocate_exec;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to relocate");
RNA_def_property_flag(prop, PROP_HIDDEN);
@@ -833,7 +833,7 @@ void WM_OT_lib_reload(wmOperatorType *ot)
ot->exec = wm_lib_reload_exec;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to reload");
RNA_def_property_flag(prop, PROP_HIDDEN);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index dbce360cb61..f77aad24719 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -338,10 +338,10 @@ void WM_init(bContext *C, int argc, const char **argv)
if (!G.background) {
if (wm_start_with_console) {
- setConsoleWindowState(GHOST_kConsoleWindowStateShow);
+ GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateShow);
}
else {
- setConsoleWindowState(GHOST_kConsoleWindowStateHideForNonConsoleLaunch);
+ GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateHideForNonConsoleLaunch);
}
}
@@ -380,7 +380,7 @@ static void free_openrecent(void)
}
#ifdef WIN32
-/* Read console events until there is a key event. Also returns on any error. */
+/* Read console events until there is a key event. Also returns on any error. */
static void wait_for_console_key(void)
{
HANDLE hConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index b44cf9e48b8..d5c4d07e9ed 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -87,6 +87,16 @@ struct wmJob {
* Executed in main thread.
*/
void (*endjob)(void *);
+ /**
+ * Called when job is stopped normally, i.e. by simply completing the startjob function.
+ * Executed in main thread.
+ */
+ void (*completed)(void *);
+ /**
+ * Called when job is stopped abnormally, i.e. when stop=true but ready=false.
+ * Executed in main thread.
+ */
+ void (*canceled)(void *);
/** Running jobs each have own timer */
double timestep;
@@ -344,10 +354,23 @@ void WM_jobs_callbacks(wmJob *wm_job,
void (*update)(void *),
void (*endjob)(void *))
{
+ WM_jobs_callbacks_ex(wm_job, startjob, initjob, update, endjob, NULL, NULL);
+}
+
+void WM_jobs_callbacks_ex(wmJob *wm_job,
+ wm_jobs_start_callback startjob,
+ void (*initjob)(void *),
+ void (*update)(void *),
+ void (*endjob)(void *),
+ void (*completed)(void *),
+ void (*canceled)(void *))
+{
wm_job->startjob = startjob;
wm_job->initjob = initjob;
wm_job->update = update;
wm_job->endjob = endjob;
+ wm_job->completed = completed;
+ wm_job->canceled = canceled;
}
static void *do_job_thread(void *job_v)
@@ -465,6 +488,24 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
}
}
+static void wm_job_end(wmJob *wm_job)
+{
+ BLI_assert_msg(BLI_thread_is_main(), "wm_job_end should only be called from the main thread");
+ if (wm_job->endjob) {
+ wm_job->endjob(wm_job->run_customdata);
+ }
+
+ /* Do the final callback based on whether the job was run to completion or not.
+ * Not all jobs have the same way of signaling cancellation (i.e. rendering stops when
+ * `G.is_break == true`, but doesn't set any wm_job properties to cancel the WM job). */
+ const bool was_canceled = wm_job->stop || G.is_break;
+ void (*final_callback)(void *) = (wm_job->ready && !was_canceled) ? wm_job->completed :
+ wm_job->canceled;
+ if (final_callback) {
+ final_callback(wm_job->run_customdata);
+ }
+}
+
static void wm_job_free(wmWindowManager *wm, wmJob *wm_job)
{
BLI_remlink(&wm->jobs, wm_job);
@@ -485,10 +526,7 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
WM_job_main_thread_lock_release(wm_job);
BLI_threadpool_end(&wm_job->threads);
WM_job_main_thread_lock_acquire(wm_job);
-
- if (wm_job->endjob) {
- wm_job->endjob(wm_job->run_customdata);
- }
+ wm_job_end(wm_job);
}
if (wm_job->wt) {
@@ -600,9 +638,7 @@ void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
}
if (wm_job->ready) {
- if (wm_job->endjob) {
- wm_job->endjob(wm_job->run_customdata);
- }
+ wm_job_end(wm_job);
/* free own data */
wm_job->run_free(wm_job->run_customdata);
@@ -670,3 +706,13 @@ bool WM_jobs_has_running(const wmWindowManager *wm)
return false;
}
+
+bool WM_jobs_has_running_type(const struct wmWindowManager *wm, int job_type)
+{
+ LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
+ if (wm_job->running && wm_job->job_type == job_type) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index 5a35570296a..0817b10f86e 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -270,6 +270,12 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
break;
}
}
+ else if (STRPREFIX(opname, "CURVES_OT")) {
+ km = WM_keymap_find_all(wm, "Curves", 0, 0);
+ }
+ else if (STRPREFIX(opname, "SCULPT_CURVES_OT")) {
+ km = WM_keymap_find_all(wm, "Sculpt Curves", 0, 0);
+ }
else if (STRPREFIX(opname, "MBALL_OT")) {
km = WM_keymap_find_all(wm, "Metaball", 0, 0);
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 307d3282659..33c69a23558 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1308,6 +1308,10 @@ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short i
return id;
}
+ if (!WM_operator_properties_id_lookup_is_set(op->ptr)) {
+ return NULL;
+ }
+
/* Lookup an already existing ID. */
id = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, idcode);
@@ -2068,7 +2072,7 @@ static void WM_OT_quit_blender(wmOperatorType *ot)
static int wm_console_toggle_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
{
- setConsoleWindowState(GHOST_kConsoleWindowStateToggle);
+ GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateToggle);
return OPERATOR_FINISHED;
}
@@ -3898,7 +3902,7 @@ static void gesture_box_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_box");
- /* XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel */
+ /* XXX TODO: zoom border should perhaps map right-mouse to zoom out instead of in+cancel. */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border");
WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border");
WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 95879829d42..9c97b05f79b 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -33,6 +33,7 @@
#include "BLI_path_util.h"
#include "BLI_rect.h"
#include "BLI_string.h"
+#include "BLI_system.h"
#include "BLI_utildefines.h"
#include "IMB_colormanagement.h"
@@ -211,7 +212,7 @@ static void playanim_gl_matrix(void)
/* implementation */
static void playanim_event_qual_update(void)
{
- int val;
+ bool val;
/* Shift */
GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyLeftShift, &val);
@@ -673,7 +674,7 @@ static void build_pict_list_ex(
*
* If set, all reads and writes on the resulting file descriptor will
* be performed directly to or from the user program buffer, provided
- * appropriate size and alignment restrictions are met. Refer to the
+ * appropriate size and alignment restrictions are met. Refer to the
* F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
* information about how to determine the alignment constraints.
* O_DIRECT is a Silicon Graphics extension and is only supported on
@@ -870,7 +871,7 @@ static void change_frame(PlayState *ps)
ps->need_frame_update = false;
}
-static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
+static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
{
PlayState *ps = (PlayState *)ps_void;
const GHOST_TEventType type = GHOST_GetEventType(evt);
@@ -901,7 +902,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
default:
break;
}
- return 1;
+ return true;
}
if (ps->wait2 && ps->stopped == false) {
@@ -1334,7 +1335,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
break;
}
- return 1;
+ return true;
}
static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey)
@@ -1536,6 +1537,8 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);
+ GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace);
+
g_WS.ghost_system = GHOST_CreateSystem();
GHOST_AddEventConsumer(g_WS.ghost_system, consumer);
@@ -1552,6 +1555,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
/* initialize the font */
BLF_init();
+ BLF_load_font_stack();
ps.fontid = BLF_load_mono_default(false);
BLF_size(ps.fontid, 11.0f, 72);
diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c
index 88eacf9013b..6dd64b89eb6 100644
--- a/source/blender/windowmanager/intern/wm_uilist_type.c
+++ b/source/blender/windowmanager/intern/wm_uilist_type.c
@@ -20,7 +20,6 @@
#include "UI_interface.h"
#include "BLI_ghash.h"
-#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index c0427f9be9a..91ec45da6d4 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -23,6 +23,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_system.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -982,7 +983,7 @@ static int query_qual(modifierKeyType qual)
break;
}
- int val = 0;
+ bool val = false;
GHOST_GetModifierKeyState(g_system, left, &val);
if (!val) {
GHOST_GetModifierKeyState(g_system, right, &val);
@@ -1052,7 +1053,7 @@ void wm_window_reset_drawable(void)
*
* Mouse coordinate conversion happens here.
*/
-static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
+static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
{
bContext *C = C_void_ptr;
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1090,17 +1091,17 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
* but it should return if WM didn't initialize yet.
* Can happen on file read (especially full size window). */
if ((wm->initialized & WM_WINDOW_IS_INIT) == 0) {
- return 1;
+ return true;
}
if (!ghostwin) {
/* XXX: should be checked, why are we getting an event here, and what is it? */
puts("<!> event has no window");
- return 1;
+ return true;
}
if (!GHOST_ValidWindow(g_system, ghostwin)) {
/* XXX: should be checked, why are we getting an event here, and what is it? */
puts("<!> event has invalid window");
- return 1;
+ return true;
}
wmWindow *win = GHOST_GetWindowUserData(ghostwin);
@@ -1443,7 +1444,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
}
}
- return 1;
+ return true;
}
/**
@@ -1543,6 +1544,8 @@ void wm_ghost_init(bContext *C)
consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
}
+ GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace);
+
g_system = GHOST_CreateSystem();
GHOST_Debug debug = {0};
@@ -1869,11 +1872,10 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv
return NULL;
}
- wmWindow *r_win = GHOST_GetWindowUserData(ghostwin);
- wm_cursor_position_from_ghost(r_win, &tmp[0], &tmp[1]);
+ wmWindow *win_other = GHOST_GetWindowUserData(ghostwin);
+ wm_cursor_position_from_ghost(win_other, &tmp[0], &tmp[1]);
copy_v2_v2_int(r_mval, tmp);
-
- return r_win;
+ return win_other;
}
void WM_window_pixel_sample_read(const wmWindowManager *wm,
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
index 3c090423c41..3f0c72a4a05 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
@@ -731,8 +731,9 @@ static void wm_xr_raycast(Scene *scene,
sctx,
depsgraph,
NULL,
- &(const struct SnapObjectParams){
- .snap_select = (selectable_only ? SNAP_SELECTABLE : SNAP_ALL)},
+ &(const struct SnapObjectParams){.snap_target_select = (selectable_only ?
+ SCE_SNAP_TARGET_ONLY_SELECTABLE :
+ SCE_SNAP_TARGET_ALL)},
origin,
direction,
ray_dist,
diff --git a/source/tools b/source/tools
-Subproject ccc8fceb6bd83ffbf6e5207247fb8f76fc47a5b
+Subproject 01b4c0e4a172819414229445c314be34527bf41
diff --git a/tests/python/alembic_export_tests.py b/tests/python/alembic_export_tests.py
index f6c05d955c9..95ae3ee9feb 100644
--- a/tests/python/alembic_export_tests.py
+++ b/tests/python/alembic_export_tests.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Alembic Export Tests
diff --git a/tests/python/batch_import.py b/tests/python/batch_import.py
index a6b44bc7478..811b070b0ca 100644
--- a/tests/python/batch_import.py
+++ b/tests/python/batch_import.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Example Usage:
diff --git a/tests/python/bl_alembic_io_test.py b/tests/python/bl_alembic_io_test.py
index f3480380911..4cfda239bd1 100644
--- a/tests/python/bl_alembic_io_test.py
+++ b/tests/python/bl_alembic_io_test.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
./blender.bin --background -noaudio --factory-startup --python tests/python/bl_alembic_io_test.py -- --testdir /path/to/lib/tests/alembic
"""
diff --git a/tests/python/bl_animation_fcurves.py b/tests/python/bl_animation_fcurves.py
index 449f17ebfec..931db3f2d22 100644
--- a/tests/python/bl_animation_fcurves.py
+++ b/tests/python/bl_animation_fcurves.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
blender -b -noaudio --factory-startup --python tests/python/bl_animation_fcurves.py -- --testdir /path/to/lib/tests/animation
"""
diff --git a/tests/python/bl_bundled_modules.py b/tests/python/bl_bundled_modules.py
index 4a055960f83..7728a2deb47 100644
--- a/tests/python/bl_bundled_modules.py
+++ b/tests/python/bl_bundled_modules.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Test that modules we ship with our Python installation are available
import bz2
diff --git a/tests/python/bl_keymap_completeness.py b/tests/python/bl_keymap_completeness.py
index ee24a531f53..97335a94c01 100644
--- a/tests/python/bl_keymap_completeness.py
+++ b/tests/python/bl_keymap_completeness.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# simple script to test 'bl_keymap_utils.keymap_hierarchy' contains correct values.
# Needed for 'bl_keymap_utils.keymap_hierarchy' which inspects tools.
diff --git a/tests/python/bl_keymap_validate.py b/tests/python/bl_keymap_validate.py
index b87eed0c0df..83d41c8a9f6 100644
--- a/tests/python/bl_keymap_validate.py
+++ b/tests/python/bl_keymap_validate.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# ./blender.bin --background -noaudio --factory-startup --python tests/python/bl_keymap_validate.py
#
diff --git a/tests/python/bl_load_addons.py b/tests/python/bl_load_addons.py
index 8fee31f7a2b..b94c56541af 100644
--- a/tests/python/bl_load_addons.py
+++ b/tests/python/bl_load_addons.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# simple script to enable all addons, and disable
"""
diff --git a/tests/python/bl_load_py_modules.py b/tests/python/bl_load_py_modules.py
index 4d4196d1f64..7ad5895ce86 100644
--- a/tests/python/bl_load_py_modules.py
+++ b/tests/python/bl_load_py_modules.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# simple script to enable all addons, and disable
"""
diff --git a/tests/python/bl_mesh_modifiers.py b/tests/python/bl_mesh_modifiers.py
index 3b653402083..640cf1c30f2 100644
--- a/tests/python/bl_mesh_modifiers.py
+++ b/tests/python/bl_mesh_modifiers.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Currently this script only generates images from different modifier
# combinations and does not validate they work correctly,
# this is because we don't get 1:1 match with bmesh.
diff --git a/tests/python/bl_mesh_validate.py b/tests/python/bl_mesh_validate.py
index 9a9384ce777..9e093608406 100644
--- a/tests/python/bl_mesh_validate.py
+++ b/tests/python/bl_mesh_validate.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Simple script to check mash validate code.
# XXX Should be extended with many more "wrong cases"!
diff --git a/tests/python/bl_rigging_symmetrize.py b/tests/python/bl_rigging_symmetrize.py
index 6531b4df85f..963be6d41d3 100644
--- a/tests/python/bl_rigging_symmetrize.py
+++ b/tests/python/bl_rigging_symmetrize.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
blender -b -noaudio --factory-startup --python tests/python/bl_rigging_symmetrize.py -- --testdir /path/to/lib/tests/animation
"""
diff --git a/tests/python/bl_rna_manual_reference.py b/tests/python/bl_rna_manual_reference.py
index 70f218f0bb2..257c8b7601a 100644
--- a/tests/python/bl_rna_manual_reference.py
+++ b/tests/python/bl_rna_manual_reference.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Use for validating our manual interlinking.
# ./blender.bin --background -noaudio --python tests/python/bl_rna_manual_reference.py
#
diff --git a/tests/python/bl_rst_completeness.py b/tests/python/bl_rst_completeness.py
index 59e532c433b..4846e65b78f 100644
--- a/tests/python/bl_rst_completeness.py
+++ b/tests/python/bl_rst_completeness.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# run this script in the game engine.
# or on the command line with...
# ./blender.bin --background -noaudio --python tests/python/bl_rst_completeness.py
diff --git a/tests/python/bl_run_operators.py b/tests/python/bl_run_operators.py
index 7e73ec163a4..a2478bd7547 100644
--- a/tests/python/bl_run_operators.py
+++ b/tests/python/bl_run_operators.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# semi-useful script, runs all operators in a number of different
# contexts, cheap way to find misc small bugs but is in no way a complete test.
#
diff --git a/tests/python/bl_run_operators_event_simulate.py b/tests/python/bl_run_operators_event_simulate.py
index 56f96847d0b..d218e6b1bc0 100644
--- a/tests/python/bl_run_operators_event_simulate.py
+++ b/tests/python/bl_run_operators_event_simulate.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
r"""
Overview
========
diff --git a/tests/python/bl_test.py b/tests/python/bl_test.py
index 7e79639a226..b71ebd2a7a7 100644
--- a/tests/python/bl_test.py
+++ b/tests/python/bl_test.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import sys
import os
diff --git a/tests/python/bl_usd_import_test.py b/tests/python/bl_usd_import_test.py
index 1ba9b4f1edf..95b2328b2aa 100644
--- a/tests/python/bl_usd_import_test.py
+++ b/tests/python/bl_usd_import_test.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import pathlib
import sys
import unittest
diff --git a/tests/python/boolean_operator.py b/tests/python/boolean_operator.py
index fed0b2bddfd..8b93226ab93 100644
--- a/tests/python/boolean_operator.py
+++ b/tests/python/boolean_operator.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# To run all tests, use
# BLENDER_VERBOSE=1 blender path/to/bool_regression.blend --python path/to/boolean_operator.py -- --run-all-tests
# To run one test, use
diff --git a/tests/python/deform_modifiers.py b/tests/python/deform_modifiers.py
index 40cd9d4839c..e5be133a3ef 100644
--- a/tests/python/deform_modifiers.py
+++ b/tests/python/deform_modifiers.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# To run the test type: blender -b /path/to/the/blend/file --python path/to/this/py/file -- --run-all-tests -- --verbose
# Type the above line in cmd/terminal, for example, look below
# blender -b c:\blender-lib\deform_modifiers.blend --python c:\deform_modifiers.py -- --run-all-tests -- --verbose
diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py
index abbe38193b5..b40b8030f7e 100644
--- a/tests/python/ffmpeg_tests.py
+++ b/tests/python/ffmpeg_tests.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import argparse
import pathlib
import sys
diff --git a/tests/python/geo_node_test.py b/tests/python/geo_node_test.py
index 9d7c634db76..0842dd001da 100644
--- a/tests/python/geo_node_test.py
+++ b/tests/python/geo_node_test.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/modifiers.py b/tests/python/modifiers.py
index 8f8b5c6498c..11d696c3bed 100644
--- a/tests/python/modifiers.py
+++ b/tests/python/modifiers.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import math
import os
import sys
@@ -215,7 +213,6 @@ def main():
SpecMeshTest("MergedNoneWeld", "testMergedNoneWeld", "expectedMergedNoneWeld",
[ModifierSpec("weld", 'WELD', {"merge_threshold": 0.019})]),
-
#############################################
# One 'Deform' modifier on primitive meshes
#############################################
@@ -327,6 +324,22 @@ def main():
]
+ boolean_basename = "CubeBooleanDiffBMeshObject"
+ tests.append(SpecMeshTest("BooleandDiffBMeshObject", "test" + boolean_basename, "expected" + boolean_basename,
+ [ModifierSpec("boolean", 'BOOLEAN',
+ {"solver": 'FAST', "operation": 'DIFFERENCE', "operand_type": 'OBJECT',
+ "object": bpy.data.objects["test" + boolean_basename + "Operand"]})]))
+ boolean_basename = "CubeBooleanDiffBMeshCollection"
+ tests.append(SpecMeshTest("BooleandDiffBMeshCollection",
+ "test" + boolean_basename,
+ "expected" + boolean_basename,
+ [ModifierSpec("boolean",
+ 'BOOLEAN',
+ {"solver": 'FAST',
+ "operation": 'DIFFERENCE',
+ "operand_type": 'COLLECTION',
+ "collection": bpy.data.collections["test" + boolean_basename + "Operands"]})]))
+
modifiers_test = RunTest(tests)
command = list(sys.argv)
diff --git a/tests/python/modules/mesh_test.py b/tests/python/modules/mesh_test.py
index 873ab779d65..5b01bfeee94 100644
--- a/tests/python/modules/mesh_test.py
+++ b/tests/python/modules/mesh_test.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# A framework to run regression tests on mesh modifiers and operators based on howardt's mesh_ops_test.py
#
# General idea:
diff --git a/tests/python/modules/render_report.py b/tests/python/modules/render_report.py
index cae81af3144..15441918800 100755
--- a/tests/python/modules/render_report.py
+++ b/tests/python/modules/render_report.py
@@ -253,8 +253,11 @@ class Report:
failed = len(failed_tests) > 0
if failed:
message = """<div class="alert alert-danger" role="alert">"""
- message += """Run this command to update reference images for failed tests, or create images for new tests:<br>"""
- message += """<tt>BLENDER_TEST_UPDATE=1 ctest -R %s</tt>""" % self.title.lower()
+ message += """<p>Run this command to regenerate reference (ground truth) images:</p>"""
+ message += """<p><tt>BLENDER_TEST_UPDATE=1 ctest -R %s</tt></p>""" % self.title.lower()
+ message += """<p>This then happens for new and failing tests; reference images of """ \
+ """passing test cases will not be updated. Be sure to commit the new reference """ \
+ """images to the SVN repository afterwards.</p>"""
message += """</div>"""
else:
message = ""
@@ -294,6 +297,7 @@ class Report:
background-position:0 0, 25px 0, 25px -25px, 0px 25px;
}}
table td:first-child {{ width: 256px; }}
+ p {{ margin-bottom: 0.5rem; }}
</style>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
diff --git a/tests/python/modules/test_utils.py b/tests/python/modules/test_utils.py
index d5cd743cde9..6aba3a75263 100755
--- a/tests/python/modules/test_utils.py
+++ b/tests/python/modules/test_utils.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import functools
import shutil
import pathlib
diff --git a/tests/python/operators.py b/tests/python/operators.py
index 6ccc96dba5d..548a2b50b05 100644
--- a/tests/python/operators.py
+++ b/tests/python/operators.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
import os
import sys
diff --git a/tests/python/pep8.py b/tests/python/pep8.py
index 9a2871c9ed5..2583bec8256 100644
--- a/tests/python/pep8.py
+++ b/tests/python/pep8.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import os
import subprocess
import shutil
@@ -22,7 +20,6 @@ import shutil
# how many lines to read into the file, pep8 comment
# should be directly after the license header, ~20 in most cases
-PEP8_SEEK_COMMENT = 40
SKIP_PREFIX = "./tools", "./config", "./extern"
SKIP_ADDONS = True
FORCE_PEP8_ALL = False
@@ -39,22 +36,8 @@ def is_pep8(path):
print(path)
if open(path, 'rb').read(3) == b'\xef\xbb\xbf':
print("\nfile contains BOM, remove first 3 bytes: %r\n" % path)
-
- # templates don't have a header but should be pep8
- for d in ("presets", "templates_py", "examples"):
- if ("%s%s%s" % (os.sep, d, os.sep)) in path:
- return 1
-
- f = open(path, 'r', encoding="utf8")
- for _ in range(PEP8_SEEK_COMMENT):
- line = f.readline()
- if line.startswith("# <pep8"):
- if line.startswith("# <pep8 compliant>"):
- return 1
- elif line.startswith("# <pep8-80 compliant>"):
- return 2
- f.close()
- return 0
+ # Currently all scripts assumed to be pep8.
+ return 1
def check_files_flake8(files):
diff --git a/tests/python/physics_cloth.py b/tests/python/physics_cloth.py
index e453b4dd68b..fbd33392371 100644
--- a/tests/python/physics_cloth.py
+++ b/tests/python/physics_cloth.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/physics_dynamic_paint.py b/tests/python/physics_dynamic_paint.py
index 57b96ccffba..132c7b8c46d 100644
--- a/tests/python/physics_dynamic_paint.py
+++ b/tests/python/physics_dynamic_paint.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/physics_ocean.py b/tests/python/physics_ocean.py
index 20d563f782b..54cf8d65a9d 100644
--- a/tests/python/physics_ocean.py
+++ b/tests/python/physics_ocean.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/physics_particle_instance.py b/tests/python/physics_particle_instance.py
index 353c0d868c8..3cd52fd9fa0 100644
--- a/tests/python/physics_particle_instance.py
+++ b/tests/python/physics_particle_instance.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/physics_particle_system.py b/tests/python/physics_particle_system.py
index 37e3df781b0..51afae68a7b 100644
--- a/tests/python/physics_particle_system.py
+++ b/tests/python/physics_particle_system.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
import bpy
diff --git a/tests/python/physics_softbody.py b/tests/python/physics_softbody.py
index 00d2a637cf7..ebb9fbb724f 100644
--- a/tests/python/physics_softbody.py
+++ b/tests/python/physics_softbody.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/rna_info_dump.py b/tests/python/rna_info_dump.py
index afedf670f2f..af00ef54de9 100644
--- a/tests/python/rna_info_dump.py
+++ b/tests/python/rna_info_dump.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Used for generating API diffs between releases
# ./blender.bin --background -noaudio --python tests/python/rna_info_dump.py
diff --git a/tests/python/rst_to_doctree_mini.py b/tests/python/rst_to_doctree_mini.py
index 3466c915aa0..43116922fe5 100644
--- a/tests/python/rst_to_doctree_mini.py
+++ b/tests/python/rst_to_doctree_mini.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Module with function to extract a doctree from an reStructuredText file.
# Named 'Mini' because we only parse the minimum data needed to check
# Python classes, methods and attributes match up to those in existing modules.