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:
authorPeter Kim <pk15950@gmail.com>2022-06-17 11:27:30 +0300
committerPeter Kim <pk15950@gmail.com>2022-06-17 11:27:30 +0300
commita39532670f6b668da7be5810fb1f844b82feeba3 (patch)
tree4d6a40f6c362ca1d9b7c7031527e6e54a62589e6
parent7948150ca3683dc326c37609ded322d54b832d0d (diff)
parent10981bc8c092dda48ed5228cc19108513035abf0 (diff)
Merge branch 'master' into xr-dev
-rw-r--r--build_files/build_environment/windows/build_deps.cmd11
-rw-r--r--intern/cycles/device/metal/queue.h69
-rw-r--r--intern/cycles/device/metal/queue.mm552
-rw-r--r--intern/ghost/CMakeLists.txt14
-rw-r--r--intern/ghost/GHOST_C-api.h40
-rw-r--r--intern/ghost/GHOST_ISystem.h11
-rw-r--r--intern/ghost/GHOST_Rect.h36
-rw-r--r--intern/ghost/GHOST_Types.h2
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp68
-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.cpp21
-rw-r--r--intern/ghost/intern/GHOST_System.h1
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp1573
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h36
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp144
-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_XrAction.cpp37
-rw-r--r--intern/ghost/test/gears/GHOST_C-Test.c12
-rw-r--r--intern/ghost/test/multitest/MultiTest.c6
-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/icons/ops.curves.sculpt_density.dat (renamed from release/datafiles/icons/ops.curves.density.dat)bin3032 -> 3032 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_slide.dat (renamed from release/datafiles/icons/ops.curves.slide.dat)bin1394 -> 1394 bytes
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c9
-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/bl_console_utils/__init__.py2
-rwxr-xr-xrelease/scripts/modules/blend_render_info.py14
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py15
-rw-r--r--release/scripts/startup/bl_operators/node.py2
-rw-r--r--release/scripts/startup/bl_operators/object.py9
-rw-r--r--release/scripts/startup/bl_operators/wm.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curves.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py8
-rw-r--r--release/scripts/startup/bl_ui/properties_data_pointcloud.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py4
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py3
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py2
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py7
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py11
-rw-r--r--source/blender/blenkernel/BKE_attribute.h4
-rw-r--r--source/blender/blenkernel/BKE_collection.h2
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h18
-rw-r--r--source/blender/blenkernel/BKE_mesh_boolean_convert.hh5
-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.cc33
-rw-r--r--source/blender/blenkernel/intern/attribute.cc55
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c4
-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/image.cc6
-rw-r--r--source/blender/blenkernel/intern/lib_override.cc38
-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_wrapper.cc23
-rw-r--r--source/blender/blenkernel/intern/nla.c45
-rw-r--r--source/blender/blenkernel/intern/pbvh.c50
-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/tracking.c10
-rw-r--r--source/blender/blenkernel/intern/unit.c16
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.cc1
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c20
-rw-r--r--source/blender/blenlib/tests/BLI_math_color_test.cc68
-rw-r--r--source/blender/blenloader/intern/versioning_280.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.c3
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc6
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c2
-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/shaders/eevee_attributes_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl2
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc32
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h16
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc8
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.cc53
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc51
-rw-r--r--source/blender/draw/intern/draw_subdivision.h3
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc16
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc147
-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/keyframes_keylist.cc4
-rw-r--r--source/blender/editors/curve/editcurve_paint.c8
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt18
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc13
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c28
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c11
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c2
-rw-r--r--source/blender/editors/include/ED_datafiles.h38
-rw-r--r--source/blender/editors/include/ED_gpencil.h6
-rw-r--r--source/blender/editors/include/ED_sculpt.h2
-rw-r--r--source/blender/editors/include/UI_grid_view.hh264
-rw-r--r--source/blender/editors/include/UI_icons.h14
-rw-r--r--source/blender/editors/include/UI_interface.h88
-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_drag.cc144
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c128
-rw-r--r--source/blender/editors/interface/interface_icons.c17
-rw-r--r--source/blender/editors/interface/interface_intern.h22
-rw-r--r--source/blender/editors/interface/interface_ops.c20
-rw-r--r--source/blender/editors/interface/interface_query.cc19
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c2
-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/io_obj.c3
-rw-r--r--source/blender/editors/io/io_usd.c29
-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/object/object_relations.c137
-rw-r--r--source/blender/editors/screen/area.c10
-rw-r--r--source/blender/editors/screen/screen_ops.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.cc2
-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.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c61
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.cc22
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c37
-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_mask_expand.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c21
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c9
-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/filesel.c3
-rw-r--r--source/blender/editors/space_file/space_file.c1
-rw-r--r--source/blender/editors/space_info/info_stats.cc18
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc24
-rw-r--r--source/blender/editors/space_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_edit.c20
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c2
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c5
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c287
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c1
-rw-r--r--source/blender/editors/transform/transform_snap.c2
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c101
-rw-r--r--source/blender/geometry/GEO_uv_parametrizer.h5
-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.h282
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c247
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c1600
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h11
-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/intern/gpu_codegen.cc4
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c26
-rw-r--r--source/blender/gpu/intern/gpu_material.c2
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc2
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc4
-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/transform.cc23
-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/collada/BCMath.cpp6
-rw-r--r--source/blender/io/common/IO_abstract_hierarchy_iterator.h5
-rw-r--r--source/blender/io/common/intern/abstract_hierarchy_iterator.cc5
-rw-r--r--source/blender/io/stl/importer/stl_import_mesh.cc56
-rw-r--r--source/blender/io/stl/importer/stl_import_mesh.hh14
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc86
-rw-r--r--source/blender/io/usd/intern/usd_reader_prim.h10
-rw-r--r--source/blender/io/usd/intern/usd_writer_material.cc3
-rw-r--r--source/blender/io/usd/usd.h8
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h1
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc37
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh6
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_io.hh4
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc4
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh5
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc4
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.cc2
-rw-r--r--source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc4
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc58
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.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.cc14
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh1
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_importer_tests.cc121
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h3
-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.h19
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h7
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h1
-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/intern/rna_ID.c18
-rw-r--r--source/blender/makesrna/intern/rna_access.c48
-rw-r--r--source/blender/makesrna/intern/rna_brush.c14
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c4
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c11
-rw-r--r--source/blender/makesrna/intern/rna_rna.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c18
-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/modifiers/intern/MOD_boolean.cc3
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc2
-rw-r--r--source/blender/python/intern/bpy_traceback.c2
-rw-r--r--source/blender/render/intern/render_result.c2
-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.c299
-rw-r--r--source/blender/sequencer/intern/utils.c2
-rw-r--r--source/blender/windowmanager/WM_api.h1
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c14
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.cc49
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c4
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c5
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c6
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c11
-rw-r--r--source/blender/windowmanager/intern/wm_uilist_type.c1
-rw-r--r--source/blender/windowmanager/intern/wm_window.c22
-rwxr-xr-xtests/python/modules/render_report.py8
295 files changed, 7106 insertions, 3684 deletions
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/intern/cycles/device/metal/queue.h b/intern/cycles/device/metal/queue.h
index de20514de0b..b0bd487c86d 100644
--- a/intern/cycles/device/metal/queue.h
+++ b/intern/cycles/device/metal/queue.h
@@ -38,45 +38,50 @@ 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 verbose_tracing_ = false;
+ bool label_command_encoders_ = false;
/* Per-kernel profiling (see CYCLES_METAL_PROFILING). */
@@ -85,28 +90,30 @@ class MetalDeviceQueue : public DeviceQueue {
int work_size;
uint64_t timing_id;
};
- std::vector<TimingData> command_encoder_labels;
- id<MTLSharedEvent> timing_shared_event = nil;
- uint64_t timing_shared_event_id;
- uint64_t command_buffer_start_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;
+ 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 = 0;
- int capture_dispatch_counter = 0;
- bool is_capturing = false;
- bool is_capturing_to_disk = false;
- bool has_captured_to_disk = false;
+ 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 9d8625e1455..0e260886abb 100644
--- a/intern/cycles/device/metal/queue.mm
+++ b/intern/cycles/device/metal/queue.mm
@@ -17,79 +17,180 @@ 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];
+ timing_shared_event_ = [mtlDevice_ newSharedEvent];
+ label_command_encoders_ = true;
}
if (getenv("CYCLES_METAL_DEBUG")) {
/* Enable very verbose tracing (shows every dispatch). */
- verbose_tracing = true;
+ verbose_tracing_ = true;
+ label_command_encoders_ = true;
}
- timing_shared_event_id = 1;
+ timing_shared_event_id_ = 1;
}
- capture_kernel = DeviceKernel(-1);
+ setup_capture();
+}
+
+void MetalDeviceQueue::setup_capture()
+{
+ capture_kernel_ = DeviceKernel(-1);
+
if (auto capture_kernel_str = getenv("CYCLES_DEBUG_METAL_CAPTURE_KERNEL")) {
- /* 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];
+ /* 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 = -1;
+ capture_dispatch_counter_ = 0;
if (auto capture_dispatch_str = getenv("CYCLES_DEBUG_METAL_CAPTURE_DISPATCH")) {
- capture_dispatch = atoi(capture_dispatch_str);
- capture_dispatch_counter = 0;
+ 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);
}
- capture_kernel = DeviceKernel(atoi(capture_kernel_str));
- printf("Capture kernel: %d = %s\n", capture_kernel, device_kernel_as_string(capture_kernel));
+ printf("Capturing sample block %d (dispatch limit: %d)\n",
+ capture_reset_counter_,
+ capture_dispatch_counter_);
+ }
+ else {
+ /* No capturing requested. */
+ return;
+ }
- if (auto capture_url = getenv("CYCLES_DEBUG_METAL_CAPTURE_URL")) {
- if (@available(macos 10.15, *)) {
- if ([captureManager supportsDestination:MTLCaptureDestinationGPUTraceDocument]) {
+ /* 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_];
- MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
- captureDescriptor.captureObject = mtlCaptureScope;
- captureDescriptor.destination = MTLCaptureDestinationGPUTraceDocument;
- captureDescriptor.outputURL = [NSURL fileURLWithPath:@(capture_url)];
+ label_command_encoders_ = true;
- 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;
- }
+ 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 to file is not supported\n");
+ 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");
}
}
}
@@ -98,31 +199,31 @@ 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];
+ [command_buffer_desc_ release];
}
- if (mtlCommandQueue) {
- [mtlCommandQueue release];
- mtlCommandQueue = nil;
+ if (mtlCommandQueue_) {
+ [mtlCommandQueue_ release];
+ mtlCommandQueue_ = nil;
}
- if (mtlCaptureScope) {
- [mtlCaptureScope release];
+ 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) {
+ for (auto &stat : timing_stats_) {
total_time += stat.total_time;
num_dispatches += stat.num_dispatches;
}
@@ -140,7 +241,7 @@ MetalDeviceQueue::~MetalDeviceQueue()
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];
+ 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)),
@@ -169,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;
@@ -183,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;
@@ -195,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();
}
@@ -204,20 +305,9 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
const int work_size,
DeviceKernelArguments const &args)
{
- if (kernel == capture_kernel) {
- if (capture_dispatch < 0 || capture_dispatch == capture_dispatch_counter) {
- /* Start gputrace capture. */
- if (mtlCommandBuffer) {
- synchronize();
- }
- [mtlCaptureScope beginScope];
- printf("[mtlCaptureScope beginScope]\n");
- is_capturing = true;
- }
- capture_dispatch_counter += 1;
- }
+ update_capture(kernel);
- if (metal_device->have_error()) {
+ if (metal_device_->have_error()) {
return false;
}
@@ -226,8 +316,10 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
id<MTLComputeCommandEncoder> mtlComputeCommandEncoder = get_compute_encoder(kernel);
- if (timing_shared_event) {
- command_encoder_labels.push_back({kernel, work_size, timing_shared_event_id});
+ 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. */
@@ -246,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);
@@ -270,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;
@@ -290,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];
}
}
}
@@ -307,9 +403,10 @@ 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 (verbose_tracing || timing_shared_event || is_capturing) {
+ 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",
@@ -321,43 +418,43 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
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);
+ 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];
+ [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++) {
@@ -365,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) {
@@ -388,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:
@@ -433,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;
@@ -447,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+ */
@@ -472,12 +569,12 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
}
}];
- if (verbose_tracing || is_capturing) {
+ 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 (verbose_tracing_) {
if (kernel == DEVICE_KERNEL_INTEGRATOR_RESET) {
printf(
"_____________________________________.____________________.______________.___________"
@@ -487,9 +584,9 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
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) {
+ 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. */
@@ -513,89 +610,76 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
}
}
- return !(metal_device->have_error());
+ return !(metal_device_->have_error());
}
bool MetalDeviceQueue::synchronize()
{
- if (has_captured_to_disk || 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) {
+ if (mtlCommandBuffer_) {
scoped_timer timer;
- 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;
- }
- }
- }];
+
+ if (@available(macos 10.14, *)) {
+ 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++;
+ uint64_t shared_event_id_ = this->shared_event_id_++;
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);
- }
-
- if (is_capturing) {
- [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");
- }
- }
+ __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;
- command_encoder_labels.clear();
+ mtlCommandBuffer_ = nil;
+ command_encoder_labels_.clear();
}
- return !(metal_device->have_error());
+ return !(metal_device_->have_error());
}
void MetalDeviceQueue::zero_to_device(device_memory &mem)
@@ -608,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);
}
}
@@ -633,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;
}
@@ -649,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
@@ -663,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);
}
}
@@ -678,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();
@@ -689,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);
@@ -702,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;
@@ -721,97 +805,99 @@ 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)
{
bool concurrent = (kernel < DEVICE_KERNEL_INTEGRATOR_NUM);
- 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 (@available(macos 10.14, *)) {
+ 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 (@available(macos 10.14, *)) {
- if (mtlComputeEncoder) {
- if (mtlComputeEncoder.dispatchType == concurrent ? MTLDispatchTypeConcurrent :
- MTLDispatchTypeSerial) {
+ 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];
- command_buffer_start_timing_id = timing_shared_event_id;
+ 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 (timing_shared_event) {
- [mtlCommandBuffer encodeSignalEvent:timing_shared_event value:timing_shared_event_id++];
+ 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/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 ad19efadba5..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)
@@ -436,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).
@@ -447,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
/***************************************************************************************
@@ -468,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.
@@ -534,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.
@@ -894,22 +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 int GHOST_SupportsCursorWarp(void);
+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 8a4412403f7..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.
@@ -310,6 +313,11 @@ class GHOST_ISystem {
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;
@@ -482,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_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 a7dc619f573..01a0a7652aa 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;
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 8dd31a88ad3..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)
@@ -392,28 +392,28 @@ void GHOST_GetCursorGrabState(GHOST_WindowHandle windowhandle,
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;
}
@@ -426,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)
@@ -489,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)
@@ -817,25 +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();
}
-int GHOST_SupportsCursorWarp(void)
+bool GHOST_SupportsCursorWarp(void)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
return system->supportsCursorWarp();
}
-void GHOST_UseWindowFocus(int use_focus)
+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 2aad4f2ea29..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. */
@@ -395,6 +395,11 @@ 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 9f2fba1a2c6..b60ce09f743 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -152,6 +152,7 @@ class GHOST_System : public GHOST_ISystem {
bool m_nativePixel;
bool supportsCursorWarp(void);
+ bool supportsWindowPosition(void);
/**
* Focus window after opening, or put them in the background.
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index a5789a2526f..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,9 @@
#include <unistd.h>
#include <cstring>
+#include <mutex>
+
+static GHOST_WindowWayland *window_from_surface(struct wl_surface *surface);
/* -------------------------------------------------------------------- */
/** \name Private Types & Defines
@@ -57,105 +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. */
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_confined_pointer_v1 *confined_pointer;
+ struct zwp_relative_pointer_v1 *relative_pointer = nullptr;
+ struct zwp_locked_pointer_v1 *locked_pointer = nullptr;
+ struct zwp_confined_pointer_v1 *confined_pointer = nullptr;
- struct xkb_context *xkb_context;
- struct xkb_state *xkb_state;
+ struct xkb_context *xkb_context = nullptr;
+ struct xkb_state *xkb_state = nullptr;
struct {
/** Key repetition in character per second. */
- int32_t rate;
+ int32_t rate = 0;
/** Time (milliseconds) after which to start repeating keys. */
- int32_t delay;
+ int32_t delay = 0;
/** Timer for key repeats. */
GHOST_ITimerTask *timer = nullptr;
} key_repeat;
+ 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;
/** Drag & Drop. */
- struct data_offer_t *data_offer_dnd;
+ struct data_offer_t *data_offer_dnd = nullptr;
+ std::mutex data_offer_dnd_mutex;
+
/** Copy & Paste. */
- struct data_offer_t *data_offer_copy_paste;
+ struct data_offer_t *data_offer_copy_paste = nullptr;
+ std::mutex data_offer_copy_paste_mutex;
- struct data_source_t *data_source;
+ struct data_source_t *data_source = nullptr;
+ std::mutex data_source_mutex;
+
+ /** Last device that was active. */
+ uint32_t data_source_serial = 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;
@@ -171,54 +227,97 @@ struct display_t {
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);
@@ -226,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;
}
@@ -374,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 = {
@@ -451,7 +571,7 @@ static const std::vector<std::string> mime_send = {
* an event is received from the compositor.
* \{ */
-static void relative_pointer_relative_motion(
+static void relative_pointer_handle_relative_motion(
void *data,
struct zwp_relative_pointer_v1 * /*zwp_relative_pointer_v1*/,
uint32_t /*utime_hi*/,
@@ -462,23 +582,24 @@ 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,
};
/** \} */
@@ -489,21 +610,28 @@ static const zwp_relative_pointer_v1_listener relative_pointer_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) {
@@ -512,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];
@@ -519,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;
}
@@ -530,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);
}
@@ -561,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 */
}
@@ -574,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 */
}
@@ -586,20 +724,20 @@ static void data_source_dnd_finished(void * /*data*/, struct wl_data_source * /*
* after matching the source/destination side actions. Only one
* action (or none) will be offered here.
*/
-static void data_source_action(void * /*data*/,
- struct wl_data_source * /*wl_data_source*/,
- uint32_t /*dnd_action*/)
+static void data_source_handle_action(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/,
+ uint32_t /*dnd_action*/)
{
/* pass */
}
static const struct wl_data_source_listener data_source_listener = {
- data_source_target,
- data_source_send,
- data_source_cancelled,
- data_source_dnd_drop_performed,
- data_source_dnd_finished,
- data_source_action,
+ data_source_handle_target,
+ data_source_handle_send,
+ data_source_handle_cancelled,
+ data_source_handle_dnd_drop_performed,
+ data_source_handle_dnd_finished,
+ data_source_handle_action,
};
/** \} */
@@ -608,31 +746,31 @@ static const struct wl_data_source_listener data_source_listener = {
/** \name Listener (Data Offer), #wl_data_offer_listener
* \{ */
-static void data_offer_offer(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- const char *mime_type)
+static void data_offer_handle_offer(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ const char *mime_type)
{
static_cast<data_offer_t *>(data)->types.insert(mime_type);
}
-static void data_offer_source_actions(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- uint32_t source_actions)
+static void data_offer_handle_source_actions(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ uint32_t source_actions)
{
static_cast<data_offer_t *>(data)->source_actions = source_actions;
}
-static void data_offer_action(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- uint32_t dnd_action)
+static void data_offer_handle_action(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ uint32_t dnd_action)
{
static_cast<data_offer_t *>(data)->dnd_action = dnd_action;
}
static const struct wl_data_offer_listener data_offer_listener = {
- data_offer_offer,
- data_offer_source_actions,
- data_offer_action,
+ data_offer_handle_offer,
+ data_offer_handle_source_actions,
+ data_offer_handle_action,
};
/** \} */
@@ -641,30 +779,32 @@ static const struct wl_data_offer_listener data_offer_listener = {
/** \name Listener (Data Device), #wl_data_device_listener
* \{ */
-static void data_device_data_offer(void * /*data*/,
- struct wl_data_device * /*wl_data_device*/,
- struct wl_data_offer *id)
+static void data_device_handle_data_offer(void * /*data*/,
+ struct wl_data_device * /*wl_data_device*/,
+ struct wl_data_offer *id)
{
data_offer_t *data_offer = new data_offer_t;
data_offer->id = id;
wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
}
-static void data_device_enter(void *data,
- struct wl_data_device * /*wl_data_device*/,
- uint32_t serial,
- struct wl_surface * /*surface*/,
- wl_fixed_t x,
- wl_fixed_t y,
- struct wl_data_offer *id)
+static void data_device_handle_enter(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ uint32_t serial,
+ struct wl_surface *surface,
+ wl_fixed_t x,
+ wl_fixed_t y,
+ struct wl_data_offer *id)
{
input_t *input = static_cast<input_t *>(data);
+ std::lock_guard lock{input->data_offer_dnd_mutex};
+
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 |
@@ -675,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);
@@ -691,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(),
@@ -713,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);
@@ -733,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;
@@ -756,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) {
@@ -773,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. */
@@ -799,65 +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,
};
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Listener (Surface), #wl_surface_listener
+/** \name Listener (Buffer), #wl_buffer_listener
* \{ */
-static void cursor_buffer_release(void *data, struct wl_buffer *wl_buffer)
+static void cursor_buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
{
cursor_t *cursor = static_cast<cursor_t *>(data);
wl_buffer_destroy(wl_buffer);
- if (wl_buffer == cursor->buffer) {
+ if (wl_buffer == cursor->wl_buffer) {
/* the mapped buffer was from a custom cursor */
- cursor->buffer = nullptr;
+ cursor->wl_buffer = nullptr;
}
}
const struct wl_buffer_listener cursor_buffer_listener = {
- cursor_buffer_release,
+ cursor_buffer_handle_release,
};
-static GHOST_IWindow *get_window(struct wl_surface *surface)
-{
- if (!surface) {
- return nullptr;
- }
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Surface), #wl_surface_listener
+ * \{ */
- for (GHOST_IWindow *win : window_manager->getWindows()) {
- if (surface == static_cast<const GHOST_WindowWayland *>(win)->surface()) {
- return win;
+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;
@@ -874,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);
}
}
@@ -909,8 +1076,8 @@ static void cursor_surface_leave(void *data,
}
struct wl_surface_listener cursor_surface_listener = {
- cursor_surface_enter,
- cursor_surface_leave,
+ cursor_surface_handle_enter,
+ cursor_surface_handle_leave,
};
/** \} */
@@ -919,15 +1086,14 @@ struct wl_surface_listener cursor_surface_listener = {
/** \name Listener (Pointer), #wl_pointer_listener
* \{ */
-static void pointer_enter(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t serial,
- struct wl_surface *surface,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
+static void pointer_handle_enter(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t serial,
+ struct wl_surface *surface,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
{
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(surface));
-
+ GHOST_WindowWayland *win = window_from_surface(surface);
if (!win) {
return;
}
@@ -936,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;
}
@@ -965,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;
}
@@ -1040,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;
}
@@ -1069,11 +1231,349 @@ 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,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \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,
};
/** \} */
@@ -1082,7 +1582,7 @@ static const struct wl_pointer_listener pointer_listener = {
/** \name Listener (Keyboard), #wl_keyboard_listener
* \{ */
-static void keyboard_keymap(
+static void keyboard_handle_keymap(
void *data, struct wl_keyboard * /*wl_keyboard*/, uint32_t format, int32_t fd, uint32_t size)
{
input_t *input = static_cast<input_t *>(data);
@@ -1107,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);
}
@@ -1118,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;
@@ -1135,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;
@@ -1171,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);
@@ -1195,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) &&
@@ -1205,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(
@@ -1215,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 &&
@@ -1230,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,
@@ -1267,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);
@@ -1279,12 +1784,12 @@ static void keyboard_repeat_info(void *data,
}
static const struct wl_keyboard_listener keyboard_listener = {
- keyboard_keymap,
- keyboard_enter,
- keyboard_leave,
- keyboard_key,
- keyboard_modifiers,
- keyboard_repeat_info,
+ keyboard_handle_keymap,
+ keyboard_handle_enter,
+ keyboard_handle_leave,
+ keyboard_handle_key,
+ keyboard_handle_modifiers,
+ keyboard_repeat_handle_info,
};
/** \} */
@@ -1293,40 +1798,111 @@ static const struct wl_keyboard_listener keyboard_listener = {
/** \name Listener (Seat), #wl_seat_listener
* \{ */
-static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
+static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
{
input_t *input = static_cast<input_t *>(data);
- input->pointer = nullptr;
- input->keyboard = nullptr;
+ input->wl_pointer = nullptr;
+ input->wl_keyboard = nullptr;
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
- input->pointer = wl_seat_get_pointer(wl_seat);
- input->cursor.surface = wl_compositor_create_surface(input->system->compositor());
+ input->wl_pointer = wl_seat_get_pointer(wl_seat);
+ input->cursor.wl_surface = wl_compositor_create_surface(input->system->compositor());
input->cursor.visible = true;
- input->cursor.buffer = nullptr;
+ input->cursor.wl_buffer = nullptr;
input->cursor.file_buffer = new buffer_t;
if (!get_cursor_settings(input->cursor.theme_name, input->cursor.size)) {
input->cursor.theme_name = std::string();
input->cursor.size = default_cursor_size;
}
- wl_pointer_add_listener(input->pointer, &pointer_listener, data);
- wl_surface_add_listener(input->cursor.surface, &cursor_surface_listener, data);
+ wl_pointer_add_listener(input->wl_pointer, &pointer_listener, data);
+ wl_surface_add_listener(input->cursor.wl_surface, &cursor_surface_listener, data);
}
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
- input->keyboard = wl_seat_get_keyboard(wl_seat);
- wl_keyboard_add_listener(input->keyboard, &keyboard_listener, data);
+ input->wl_keyboard = wl_seat_get_keyboard(wl_seat);
+ wl_keyboard_add_listener(input->wl_keyboard, &keyboard_listener, data);
}
}
-static void seat_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
+static void seat_handle_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
{
static_cast<input_t *>(data)->name = std::string(name);
}
static const struct wl_seat_listener seat_listener = {
- seat_capabilities,
- seat_name,
+ seat_handle_capabilities,
+ seat_handle_name,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Output), #zxdg_output_v1_listener
+ * \{ */
+
+static void xdg_output_handle_logical_position(void *data,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ int32_t x,
+ int32_t y)
+{
+ output_t *output = static_cast<output_t *>(data);
+ output->position_logical[0] = x;
+ output->position_logical[1] = y;
+ output->has_position_logical = true;
+}
+
+static void xdg_output_handle_logical_size(void *data,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ int32_t width,
+ int32_t height)
+{
+ output_t *output = static_cast<output_t *>(data);
+
+ if (output->size_logical[0] != 0 && output->size_logical[1] != 0) {
+ /* Original comment from SDL. */
+ /* FIXME(@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,
};
/** \} */
@@ -1335,35 +1911,45 @@ static const struct wl_seat_listener seat_listener = {
/** \name Listener (Output), #wl_output_listener
* \{ */
-static void output_geometry(void *data,
- struct wl_output * /*wl_output*/,
- int32_t /*x*/,
- int32_t /*y*/,
- int32_t physical_width,
- int32_t physical_height,
- int32_t /*subpixel*/,
- const char *make,
- const char *model,
- int32_t transform)
+static void output_handle_geometry(void *data,
+ struct wl_output * /*wl_output*/,
+ int32_t /*x*/,
+ int32_t /*y*/,
+ int32_t physical_width,
+ int32_t physical_height,
+ int32_t /*subpixel*/,
+ const char *make,
+ const char *model,
+ int32_t transform)
{
output_t *output = static_cast<output_t *>(data);
output->transform = transform;
output->make = std::string(make);
output->model = std::string(model);
- output->width_mm = physical_width;
- output->height_mm = physical_height;
+ output->size_mm[0] = physical_width;
+ output->size_mm[1] = physical_height;
}
-static void output_mode(void *data,
- struct wl_output * /*wl_output*/,
- uint32_t /*flags*/,
- int32_t width,
- int32_t height,
- int32_t /*refresh*/)
+static void output_handle_mode(void *data,
+ struct wl_output * /*wl_output*/,
+ uint32_t flags,
+ int32_t width,
+ int32_t height,
+ int32_t /*refresh*/)
{
output_t *output = static_cast<output_t *>(data);
- output->width_pxl = width;
- output->height_pxl = height;
+
+ if (flags & WL_OUTPUT_MODE_CURRENT) {
+ output->size_native[0] = width;
+ output->size_native[1] = height;
+
+ /* Don't rotate this yet, `wl-output` coordinates are transformed in
+ * handle_done and `xdg-output` coordinates are pre-transformed. */
+ if (!output->has_size_logical) {
+ output->size_logical[0] = width;
+ output->size_logical[1] = height;
+ }
+ }
}
/**
@@ -1374,20 +1960,43 @@ static void output_mode(void *data,
* changes done after that. This allows changes to the output
* properties to be seen as atomic, even if they happen via multiple events.
*/
-static void output_done(void * /*data*/, struct wl_output * /*wl_output*/)
+static void output_handle_done(void *data, struct wl_output * /*wl_output*/)
{
+ output_t *output = static_cast<output_t *>(data);
+ int32_t size_native[2];
+ if (output->transform & WL_OUTPUT_TRANSFORM_90) {
+ size_native[0] = output->size_native[1];
+ size_native[1] = output->size_native[1];
+ }
+ else {
+ size_native[0] = output->size_native[0];
+ size_native[1] = output->size_native[1];
+ }
+
+ /* If `xdg-output` is present, calculate the true scale of the desktop */
+ if (output->has_size_logical) {
+
+ /* NOTE: it's not necessary to divide these values by their greatest-common-denominator
+ * as even a 64k screen resolution doesn't approach overflowing an `int32_t`. */
+
+ GHOST_ASSERT(size_native[0] && output->size_logical[0],
+ "Screen size values were not set when they were expected to be.");
+
+ output->scale_fractional = wl_fixed_from_int(size_native[0]) / output->size_logical[0];
+ output->has_scale_fractional = true;
+ }
}
-static void output_scale(void *data, struct wl_output * /*wl_output*/, int32_t factor)
+static void output_handle_scale(void *data, struct wl_output * /*wl_output*/, int32_t factor)
{
static_cast<output_t *>(data)->scale = factor;
}
static const struct wl_output_listener output_listener = {
- output_geometry,
- output_mode,
- output_done,
- output_scale,
+ output_handle_geometry,
+ output_handle_mode,
+ output_handle_done,
+ output_handle_scale,
};
/** \} */
@@ -1396,13 +2005,13 @@ static const struct wl_output_listener output_listener = {
/** \name Listener (XDG WM Base), #xdg_wm_base_listener
* \{ */
-static void shell_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
+static void shell_handle_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
{
xdg_wm_base_pong(xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener shell_listener = {
- shell_ping,
+ shell_handle_ping,
};
/** \} */
@@ -1411,11 +2020,11 @@ static const struct xdg_wm_base_listener shell_listener = {
/** \name Listener (Registry), #wl_registry_listener
* \{ */
-static void global_add(void *data,
- struct wl_registry *wl_registry,
- uint32_t name,
- const char *interface,
- uint32_t /*version*/)
+static void global_handle_add(void *data,
+ struct wl_registry *wl_registry,
+ uint32_t name,
+ const char *interface,
+ uint32_t /*version*/)
{
struct display_t *display = static_cast<struct display_t *>(data);
if (!strcmp(interface, wl_compositor_interface.name)) {
@@ -1431,31 +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->confined_pointer = nullptr;
- input->seat = static_cast<wl_seat *>(
+ input->wl_seat = static_cast<wl_seat *>(
wl_registry_bind(wl_registry, name, &wl_seat_interface, 4));
display->inputs.push_back(input);
- wl_seat_add_listener(input->seat, &seat_listener, input);
+ wl_seat_add_listener(input->wl_seat, &seat_listener, input);
}
else if (!strcmp(interface, wl_shm_interface.name)) {
display->shm = static_cast<wl_shm *>(
@@ -1463,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 *>(
@@ -1484,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,
};
/** \} */
@@ -1503,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);
@@ -1529,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()
@@ -1561,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
@@ -1612,7 +2248,11 @@ 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);
@@ -1622,16 +2262,15 @@ void GHOST_SystemWayland::putClipboard(const char *buffer, bool /*selection*/) c
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);
}
}
@@ -1642,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;
}
@@ -1660,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;
}
}
@@ -1782,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;
}
@@ -1813,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;
- wl_surface_damage(c->surface, 0, 0, int32_t(c->image.width), int32_t(c->image.height));
- wl_pointer_set_cursor(input->pointer,
+ 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_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)
@@ -1836,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);
@@ -1854,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);
@@ -1961,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);
@@ -1983,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 {
@@ -1997,12 +2684,19 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
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 */
@@ -2052,6 +2746,49 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
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;
}
@@ -2072,13 +2809,13 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
* An alternative could be to draw the cursor in software (and hide the real cursor),
* or just accept a locked cursor on WAYLAND. */
input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
- d->relative_pointer_manager, input->pointer);
+ d->relative_pointer_manager, input->wl_pointer);
zwp_relative_pointer_v1_add_listener(
input->relative_pointer, &relative_pointer_listener, input);
input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
d->pointer_constraints,
surface,
- input->pointer,
+ input->wl_pointer,
nullptr,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
@@ -2088,7 +2825,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
input->confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
d->pointer_constraints,
surface,
- input->pointer,
+ input->wl_pointer,
nullptr,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index 5b3e4f8ed75..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;
@@ -104,6 +125,7 @@ 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,
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_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_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/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/icons/ops.curves.density.dat b/release/datafiles/icons/ops.curves.sculpt_density.dat
index f336de79082..f336de79082 100644
--- a/release/datafiles/icons/ops.curves.density.dat
+++ b/release/datafiles/icons/ops.curves.sculpt_density.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.slide.dat b/release/datafiles/icons/ops.curves.sculpt_slide.dat
index 7f143ad92cc..7f143ad92cc 100644
--- a/release/datafiles/icons/ops.curves.slide.dat
+++ b/release/datafiles/icons/ops.curves.sculpt_slide.dat
Binary files differ
diff --git a/release/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/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/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/blend_render_info.py b/release/scripts/modules/blend_render_info.py
index 4ba818a19e5..37c5f6dd3ba 100755
--- a/release/scripts/modules/blend_render_info.py
+++ b/release/scripts/modules/blend_render_info.py
@@ -85,7 +85,13 @@ def _read_blend_rend_chunk_from_file(blendfile, filepath):
sizeof_bhead = 24 if is_64_bit else 20
- while len(bhead_id := blendfile.read(4)) == 4:
+ # Should always be 4, but a malformed/corrupt file may be less.
+ while (bhead_id := blendfile.read(4)) != b'ENDB':
+
+ if len(bhead_id) != 4:
+ sys.stderr.write("Unable to read until ENDB block (corrupt file): %s\n" % filepath)
+ break
+
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
@@ -107,8 +113,12 @@ def _read_blend_rend_chunk_from_file(blendfile, filepath):
scenes.append((start_frame, end_frame, scene_name))
- if sizeof_data_left != 0:
+ 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
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 77890a9800d..7d0929ef28f 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -2223,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},
@@ -3013,7 +3014,7 @@ def km_sequencerpreview(params):
return keymap
-def km_sequencer_channels(params):
+def km_sequencer_channels(_params):
items = []
keymap = (
"Sequencer Channels",
@@ -5588,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 = []
@@ -8013,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/node.py b/release/scripts/startup/bl_operators/node.py
index a99a81e0c63..bad12ff4621 100644
--- a/release/scripts/startup/bl_operators/node.py
+++ b/release/scripts/startup/bl_operators/node.py
@@ -130,7 +130,7 @@ class NodeAddOperator:
return result
@classmethod
- def description(cls, context, properties):
+ def description(cls, _context, properties):
nodetype = properties["type"]
bl_rna = bpy.types.Node.bl_rna_get_subclass(nodetype)
if bl_rna is not None:
diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py
index 60f534b3ab6..6e08d557353 100644
--- a/release/scripts/startup/bl_operators/object.py
+++ b/release/scripts/startup/bl_operators/object.py
@@ -596,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
@@ -621,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'
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 0eaada7249b..50fc6bad720 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1352,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,
)
@@ -1363,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/properties_data_curves.py b/release/scripts/startup/bl_ui/properties_data_curves.py
index ed7f6e3697c..4a11c5edde6 100644
--- a/release/scripts/startup/bl_ui/properties_data_curves.py
+++ b/release/scripts/startup/bl_ui/properties_data_curves.py
@@ -77,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_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 6feddfe4d3b..0b043905713 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -70,7 +70,7 @@ class MESH_MT_color_attribute_context_menu(Menu):
def draw(self, _context):
layout = self.layout
- props = layout.operator(
+ layout.operator(
"geometry.color_attribute_duplicate",
icon='DUPLICATE',
)
@@ -507,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
@@ -596,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 = []
diff --git a/release/scripts/startup/bl_ui/properties_data_pointcloud.py b/release/scripts/startup/bl_ui/properties_data_pointcloud.py
index b492a87c741..8ef6ad63bba 100644
--- a/release/scripts/startup/bl_ui/properties_data_pointcloud.py
+++ b/release/scripts/startup/bl_ui/properties_data_pointcloud.py
@@ -65,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_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 5a9a8882bd9..f0034a3d710 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -1316,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/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index d8d387036ff..a806e9e0c33 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -199,7 +199,8 @@ class CLIP_HT_header(Header):
row = layout.row(align=True)
row.prop(dopesheet, "sort_method", text="")
row.prop(dopesheet, "use_invert_sort",
- text="Invert", toggle=True)
+ text="", toggle=True,
+ icon='SORT_DESC' if dopesheet.use_invert_sort else 'SORT_ASC')
def _draw_masking(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index d6f26880d20..5157a215f34 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -151,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_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 84725d9e781..2db30ac1450 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -2087,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_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 191066df89f..5070bd04142 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -1196,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 80ea33f8a75..5e5e7a79035 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -95,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")
@@ -106,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")
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index 5755ddb3018..13eefd27bec 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -64,7 +64,7 @@ bool BKE_id_attribute_remove(struct ID *id, const char *name, struct ReportList
* Creates a duplicate attribute layer.
*/
struct CustomDataLayer *BKE_id_attribute_duplicate(struct ID *id,
- struct CustomDataLayer *layer,
+ const char *name,
struct ReportList *reports);
struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
@@ -72,7 +72,7 @@ struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
int type,
eAttrDomain domain);
-struct CustomDataLayer *BKE_id_attribute_search(const struct ID *id,
+struct CustomDataLayer *BKE_id_attribute_search(struct ID *id,
const char *name,
eCustomDataMask type,
eAttrDomainMask domain_mask);
diff --git a/source/blender/blenkernel/BKE_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_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_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_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 8496692ceb3..b3a9d894944 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -52,6 +52,7 @@
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
+#include "BKE_subdiv_modifier.h"
#include "BLI_sys_types.h" /* for intptr_t support */
@@ -598,10 +599,10 @@ static bool mesh_has_modifier_final_normals(const Mesh *mesh_input,
/* Test if mesh has the required loop normals, in case an additional modifier
* evaluation from another instance or from an operator requests it but the
* initial normals were not loop normals. */
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
- return (!do_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
+ return (!calc_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
}
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
@@ -610,16 +611,19 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
Mesh *mesh_final)
{
/* Compute normals. */
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
- mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ if (subsurf_runtime_data) {
+ subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
+ }
- if (do_loop_normals) {
+ if (calc_loop_normals) {
/* Compute loop normals (NOTE: will compute poly and vert normals as well, if needed!). In case
* of deferred CPU subdivision, this will be computed when the wrapper is generated. */
- if (mesh_final->runtime.subsurf_resolution == 0) {
+ if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}
@@ -1266,15 +1270,18 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
return;
}
- const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
- mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ if (subsurf_runtime_data) {
+ subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
+ }
- if (do_loop_normals) {
+ if (calc_loop_normals) {
/* Compute loop normals. In case of deferred CPU subdivision, this will be computed when the
* wrapper is generated. */
- if (mesh_final->runtime.subsurf_resolution == 0) {
+ if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}
diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc
index b2ea8b833b3..7c09b4a4ce3 100644
--- a/source/blender/blenkernel/intern/attribute.cc
+++ b/source/blender/blenkernel/intern/attribute.cc
@@ -208,53 +208,36 @@ CustomDataLayer *BKE_id_attribute_new(
return (index == -1) ? nullptr : &(customdata->layers[index]);
}
-CustomDataLayer *BKE_id_attribute_duplicate(ID *id, CustomDataLayer *layer, ReportList *reports)
+CustomDataLayer *BKE_id_attribute_duplicate(ID *id, const char *name, ReportList *reports)
{
- DomainInfo info[ATTR_DOMAIN_NUM];
- get_domains(id, info);
-
- eCustomDataType type = (eCustomDataType)layer->type;
- eAttrDomain domain = BKE_id_attribute_domain(id, layer);
-
- CustomData *customdata = info[domain].customdata;
- if (customdata == nullptr) {
- BKE_report(reports, RPT_ERROR, "Attribute domain not supported by this geometry type");
+ const CustomDataLayer *src_layer = BKE_id_attribute_search(
+ id, name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
+ if (src_layer == nullptr) {
+ BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
return nullptr;
}
- char name[MAX_CUSTOMDATA_LAYER_NAME];
- char uniquename[MAX_CUSTOMDATA_LAYER_NAME];
+ const eCustomDataType type = (eCustomDataType)src_layer->type;
+ const eAttrDomain domain = BKE_id_attribute_domain(id, src_layer);
/* Make a copy of name in case CustomData API reallocates the layers. */
- BLI_strncpy(name, layer->name, MAX_CUSTOMDATA_LAYER_NAME);
- BKE_id_attribute_calc_unique_name(id, layer->name, uniquename);
+ const std::string name_copy = name;
- switch (GS(id->name)) {
- case ID_ME: {
- Mesh *me = (Mesh *)id;
- BMEditMesh *em = me->edit_mesh;
- if (em != nullptr) {
- BM_data_layer_add_named(em->bm, customdata, type, uniquename);
- }
- else {
- CustomData_add_layer_named(
- customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
- }
- break;
- }
- default: {
- CustomData_add_layer_named(
- customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
- break;
- }
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(id, info);
+ CustomData *customdata = info[domain].customdata;
+
+ CustomDataLayer *new_layer = BKE_id_attribute_new(id, name_copy.c_str(), type, domain, reports);
+ if (new_layer == nullptr) {
+ return nullptr;
}
- int from_index = CustomData_get_named_layer_index(customdata, type, name);
- int to_index = CustomData_get_named_layer_index(customdata, type, uniquename);
+ const int from_index = CustomData_get_named_layer_index(customdata, type, name_copy.c_str());
+ const int to_index = CustomData_get_named_layer_index(customdata, type, new_layer->name);
CustomData_copy_data_layer(
customdata, customdata, from_index, to_index, 0, 0, info[domain].length);
- return (to_index == -1) ? nullptr : &(customdata->layers[to_index]);
+ return new_layer;
}
bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports)
@@ -317,7 +300,7 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
return nullptr;
}
-CustomDataLayer *BKE_id_attribute_search(const ID *id,
+CustomDataLayer *BKE_id_attribute_search(ID *id,
const char *name,
const eCustomDataMask type_mask,
const eAttrDomainMask domain_mask)
diff --git a/source/blender/blenkernel/intern/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/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/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/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc
index aa43ca94c99..22012662180 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;
@@ -2677,11 +2706,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/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_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc
index c505a74724b..fdebf1d6a26 100644
--- a/source/blender/blenkernel/intern/mesh_wrapper.cc
+++ b/source/blender/blenkernel/intern/mesh_wrapper.cc
@@ -314,28 +314,23 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
return me;
}
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (runtime_data == nullptr || runtime_data->settings.level == 0) {
+ return me;
+ }
+
/* Initialize the settings before ensuring the descriptor as this is checked to decide whether
* subdivision is needed at all, and checking the descriptor status might involve checking if the
* data is out-of-date, which is a very expensive operation. */
SubdivToMeshSettings mesh_settings;
- mesh_settings.resolution = me->runtime.subsurf_resolution;
- mesh_settings.use_optimal_display = me->runtime.subsurf_use_optimal_display;
+ mesh_settings.resolution = runtime_data->resolution;
+ mesh_settings.use_optimal_display = runtime_data->use_optimal_display;
if (mesh_settings.resolution < 3) {
return me;
}
- const bool apply_render = me->runtime.subsurf_apply_render;
-
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(&subdiv_settings, smd, apply_render);
- if (subdiv_settings.level == 0) {
- return me;
- }
-
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
-
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, me, false);
if (subdiv == nullptr) {
/* Happens on bad topology, but also on empty input mesh. */
return me;
@@ -358,7 +353,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
CustomData_set_layer_flag(&me->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
CustomData_set_layer_flag(&subdiv_mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
- else if (me->runtime.subsurf_do_loop_normals) {
+ else if (runtime_data->calc_loop_normals) {
BKE_mesh_calc_normals_split(subdiv_mesh);
}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index a5f6c453ed4..8f54d71108a 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -244,24 +244,42 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, const ListBase *src, const
}
}
-static void update_active_strip_from_listbase(AnimData *adt_dest,
- NlaTrack *track_dest,
- const NlaStrip *active_strip,
- const ListBase /* NlaStrip */ *strips_source)
+/**
+ * Find `active_strip` in `strips_source`, then return the strip with the same
+ * index from `strips_dest`.
+ */
+static NlaStrip *find_active_strip_from_listbase(const NlaStrip *active_strip,
+ const ListBase /* NlaStrip */ *strips_source,
+ const ListBase /* NlaStrip */ *strips_dest)
{
- NlaStrip *strip_dest = track_dest->strips.first;
+ NlaStrip *strip_dest = strips_dest->first;
LISTBASE_FOREACH (const NlaStrip *, strip_source, strips_source) {
- if (strip_source == active_strip) {
- adt_dest->actstrip = strip_dest;
- return;
+ if (strip_dest == NULL) {
+ /* The tracks are assumed to have an equal number of strips, but this is not the case when
+ * dragging multiple strips. The transform system merges the selected strips into one
+ * meta-strip, reducing the number of strips in `track_dest`. */
+ break;
}
-
- if (strip_source->type == NLASTRIP_TYPE_META) {
- update_active_strip_from_listbase(adt_dest, track_dest, active_strip, &strip_source->strips);
+ if (strip_source == active_strip) {
+ return strip_dest;
+ }
+
+ const bool src_is_meta = strip_source->type == NLASTRIP_TYPE_META;
+ const bool dst_is_meta = strip_dest->type == NLASTRIP_TYPE_META;
+ BLI_assert_msg(src_is_meta == dst_is_meta,
+ "Expecting topology of source and destination strips to be equal");
+ if (src_is_meta && dst_is_meta) {
+ NlaStrip *found_in_meta = find_active_strip_from_listbase(
+ active_strip, &strip_source->strips, &strip_dest->strips);
+ if (found_in_meta != NULL) {
+ return found_in_meta;
+ }
}
strip_dest = strip_dest->next;
}
+
+ return NULL;
}
/* Set adt_dest->actstrip to the strip with the same index as adt_source->actstrip. */
@@ -272,8 +290,9 @@ static void update_active_strip(AnimData *adt_dest,
{
BLI_assert(BLI_listbase_count(&track_source->strips) == BLI_listbase_count(&track_dest->strips));
- update_active_strip_from_listbase(
- adt_dest, track_dest, adt_source->actstrip, &track_source->strips);
+ NlaStrip *active_strip = find_active_strip_from_listbase(
+ adt_source->actstrip, &track_source->strips, &track_dest->strips);
+ adt_dest->actstrip = active_strip;
}
/* Set adt_dest->act_track to the track with the same index as adt_source->act_track. */
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 8c9db339753..3b20bdc826c 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -1391,8 +1391,7 @@ void pbvh_free_draw_buffers(PBVH *pbvh, PBVHNode *node)
}
}
-static void pbvh_update_draw_buffers(
- PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag, bool full_render)
+static void pbvh_check_draw_layout(PBVH *pbvh)
{
const CustomData *vdata;
const CustomData *ldata;
@@ -1420,10 +1419,14 @@ static void pbvh_update_draw_buffers(
break;
}
- const bool active_attrs_only = !full_render;
-
- /* rebuild all draw buffers if attribute layout changed */
- if (GPU_pbvh_attribute_names_update(pbvh->type, pbvh->vbo_id, vdata, ldata, active_attrs_only)) {
+ /* 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;
@@ -1433,6 +1436,33 @@ static void pbvh_update_draw_buffers(
}
}
}
+}
+
+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. */
@@ -2837,10 +2867,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
void *user_data,
- bool full_render)
+ bool UNUSED(full_render))
{
- pbvh->draw_cache_invalid = false;
-
PBVHNode **nodes;
int totnode;
int update_flag = 0;
@@ -2862,9 +2890,11 @@ 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, full_render);
+ pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag);
}
MEM_SAFE_FREE(nodes);
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/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/unit.c b/source/blender/blenkernel/intern/unit.c
index 557fb2568fe..b31632f0234 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -462,11 +462,6 @@ static size_t unit_as_string(char *str,
double value_conv = (value / unit->scalar) - unit->bias;
bool strip_skip = false;
- /* 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);
-
/* Negative precision is used to disable stripping of zeroes.
* This reduces text jumping when changing values. */
if (prec < 0) {
@@ -474,6 +469,11 @@ static size_t unit_as_string(char *str,
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. */
@@ -491,10 +491,10 @@ static size_t unit_as_string(char *str,
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/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/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/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/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index eafb27f9758..e542bc46a28 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -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_300.c b/source/blender/blenloader/intern/versioning_300.c
index 57240b93ab1..97b414d4b4a 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -1001,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")) {
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/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/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_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/shaders/eevee_attributes_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
index fafea1e576e..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
@@ -287,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/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
index 280b31ea463..c0d4393f2da 100644
--- a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
@@ -5,6 +5,6 @@ void main()
vec3 world_pos = point_object_to_world(vec3(au, 0.0));
gl_Position = point_world_to_ndc(world_pos);
- finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorVertexSelect : vec4(colorWire.rgb, 1.0);
+ finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorFaceDot : vec4(colorWire.rgb, 1.0);
gl_PointSize = pointSize;
}
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc
index 82be73f6de8..baea0c7b646 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc
@@ -117,7 +117,7 @@ static void mesh_render_data_lverts_bm(const MeshRenderData *mr, MeshBufferCache
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;
}
}
@@ -135,7 +135,7 @@ static void mesh_render_data_ledges_bm(const MeshRenderData *mr, MeshBufferCache
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;
}
}
@@ -337,7 +337,7 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
* The overall advantage is small (around 1%), so keep this as-is. */
mr->mlooptri = static_cast<MLoopTri *>(
MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI"));
- if (mr->poly_normals != NULL) {
+ if (mr->poly_normals != nullptr) {
BKE_mesh_recalc_looptri_with_normals(me->mloop,
me->mpoly,
me->mvert,
@@ -356,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));
}
}
}
@@ -391,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 {
@@ -403,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;
@@ -423,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);
}
@@ -455,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;
@@ -515,13 +515,13 @@ 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) {
@@ -575,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 2c07b651c7c..8399f5c9650 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -163,7 +163,7 @@ void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode)
cache->is_dirty = true;
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
}
@@ -530,8 +530,6 @@ static bool curves_ensure_attributes(const Curves &curves,
}
switch (type) {
- default:
- break;
case CD_PROP_BOOL:
case CD_PROP_INT8:
case CD_PROP_INT32:
@@ -548,6 +546,8 @@ static bool curves_ensure_attributes(const Curves &curves,
}
break;
}
+ default:
+ break;
}
}
@@ -638,7 +638,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.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc
index 1b45f3f88dd..7c02ee2c033 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc
@@ -238,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;
}
}
@@ -351,7 +351,8 @@ static void mesh_cd_calc_active_mloopcol_layer(const Object *object,
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);
const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id);
int layer_i = BKE_id_attribute_to_index(
@@ -367,7 +368,7 @@ static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
const CustomData *cd_ldata,
const char name[])
{
- const CustomDataLayer *layer = NULL;
+ const CustomDataLayer *layer = nullptr;
eAttrDomain domain;
if (name[0]) {
@@ -426,7 +427,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
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;
@@ -739,7 +740,7 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me)
{
MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
- if (cache == NULL) {
+ if (cache == nullptr) {
return false;
}
@@ -755,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;
}
@@ -782,7 +783,7 @@ static void mesh_batch_cache_init(Object *object, Mesh *me)
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);
@@ -928,7 +929,7 @@ static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache)
void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
{
MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
- if (cache == NULL) {
+ if (cache == nullptr) {
return;
}
DRWBatchFlag batch_map;
@@ -1009,7 +1010,7 @@ 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;
}
}
@@ -1088,7 +1089,8 @@ static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Me
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
Mesh me_query = blender::dna::shallow_zero_initialize();
- 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);
const CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id);
const CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id);
@@ -1134,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);
@@ -1253,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;
}
@@ -1375,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);
@@ -1450,7 +1452,7 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
{
MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
- if (cache == NULL) {
+ if (cache == nullptr) {
return;
}
@@ -1521,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;
}
@@ -1556,12 +1558,12 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
#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. */
@@ -1572,7 +1574,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
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);
@@ -1589,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;
}
@@ -1749,7 +1751,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
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);
}
@@ -2066,8 +2068,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
if (do_subdivision) {
- DRW_create_subdivision(scene,
- ob,
+ DRW_create_subdivision(ob,
me,
cache,
&cache->final,
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index e7726ff55ca..b37a420b555 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -1052,14 +1052,10 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache)
static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
Subdiv *subdiv,
Mesh *mesh_eval,
- const Scene *scene,
- const SubsurfModifierData *smd,
- const bool is_final_render)
+ const SubsurfRuntimeData *runtime_data)
{
- const int requested_levels = (is_final_render) ? smd->renderLevels : smd->levels;
- const int level = get_render_subsurf_level(&scene->r, requested_levels, is_final_render);
SubdivToMeshSettings to_mesh_settings;
- to_mesh_settings.resolution = (1 << level) + 1;
+ to_mesh_settings.resolution = runtime_data->resolution;
to_mesh_settings.use_optimal_display = false;
if (cache->resolution != to_mesh_settings.resolution) {
@@ -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);
@@ -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_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
index 8920a2dcd51..2d9f4713feb 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -185,8 +185,7 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache);
/** \} */
-void DRW_create_subdivision(const struct Scene *scene,
- struct Object *ob,
+void DRW_create_subdivision(struct Object *ob,
struct Mesh *mesh,
struct MeshBatchCache *batch_cache,
struct MeshBufferCache *mbc,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc
index 7e02fbbf7d0..ec7d3a933b4 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc
@@ -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_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
index 7d584824045..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
@@ -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);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
index 5f07f8dfb72..fb6b5e1904b 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -27,21 +27,16 @@ namespace blender::draw {
static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, eAttrDomain domain)
{
switch (domain) {
- default: {
- return nullptr;
- }
- case ATTR_DOMAIN_POINT: {
+ case ATTR_DOMAIN_POINT:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
- }
- case ATTR_DOMAIN_CORNER: {
+ case ATTR_DOMAIN_CORNER:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
- }
- case ATTR_DOMAIN_FACE: {
+ case ATTR_DOMAIN_FACE:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
- }
- case ATTR_DOMAIN_EDGE: {
+ case ATTR_DOMAIN_EDGE:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->edata : &mr->me->edata;
- }
+ default:
+ return nullptr;
}
}
@@ -50,7 +45,7 @@ static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, eAttrDom
* etc.) directly map to available GPU types. Booleans are still converted as attributes are vec4
* in the shader.
*/
-template<typename AttributeType, typename VBOType> struct attribute_type_converter {
+template<typename AttributeType, typename VBOType> struct AttributeTypeConverter {
static VBOType convert_value(AttributeType value)
{
if constexpr (std::is_same_v<AttributeType, VBOType>) {
@@ -67,7 +62,7 @@ struct gpuMeshCol {
ushort r, g, b, a;
};
-template<> struct attribute_type_converter<MPropCol, gpuMeshCol> {
+template<> struct AttributeTypeConverter<MPropCol, gpuMeshCol> {
static gpuMeshCol convert_value(MPropCol value)
{
gpuMeshCol result;
@@ -86,53 +81,42 @@ static uint gpu_component_size_for_attribute_type(eCustomDataType type)
case CD_PROP_BOOL:
case CD_PROP_INT8:
case CD_PROP_INT32:
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
/* TODO(@kevindietrich): should be 1 when scalar attributes conversion is handled by us. See
* comment #extract_attr_init. */
return 3;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
return 2;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
return 3;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return 4;
- }
- default: {
+ default:
return 0;
- }
}
}
static GPUVertFetchMode get_fetch_mode_for_type(eCustomDataType type)
{
switch (type) {
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
return GPU_FETCH_INT_TO_FLOAT;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return GPU_FETCH_INT_TO_FLOAT_UNIT;
- }
- default: {
+ default:
return GPU_FETCH_FLOAT;
- }
}
}
static GPUVertCompType get_comp_type_for_type(eCustomDataType type)
{
switch (type) {
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
return GPU_COMP_I32;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return GPU_COMP_U16;
- }
- default: {
+ default:
return GPU_COMP_F32;
- }
}
}
@@ -184,41 +168,36 @@ static void fill_vertbuf_with_attribute(const MeshRenderData *mr,
const AttributeType *attr_data = static_cast<const AttributeType *>(
CustomData_get_layer_n(custom_data, request.cd_type, layer_index));
- using converter = attribute_type_converter<AttributeType, VBOType>;
+ using Converter = AttributeTypeConverter<AttributeType, VBOType>;
switch (request.domain) {
- default: {
- BLI_assert(false);
- break;
- }
- case ATTR_DOMAIN_POINT: {
+ case ATTR_DOMAIN_POINT:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
- *vbo_data = converter::convert_value(attr_data[mloop->v]);
+ *vbo_data = Converter::convert_value(attr_data[mloop->v]);
}
break;
- }
- case ATTR_DOMAIN_CORNER: {
+ case ATTR_DOMAIN_CORNER:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++) {
- *vbo_data = converter::convert_value(attr_data[ml_index]);
+ *vbo_data = Converter::convert_value(attr_data[ml_index]);
}
break;
- }
- case ATTR_DOMAIN_EDGE: {
+ case ATTR_DOMAIN_EDGE:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
- *vbo_data = converter::convert_value(attr_data[mloop->e]);
+ *vbo_data = Converter::convert_value(attr_data[mloop->e]);
}
break;
- }
- case ATTR_DOMAIN_FACE: {
+ case ATTR_DOMAIN_FACE:
for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) {
const MPoly &poly = mpoly[mp_index];
- const VBOType value = converter::convert_value(attr_data[mp_index]);
+ const VBOType value = Converter::convert_value(attr_data[mp_index]);
for (int l = 0; l < poly.totloop; l++) {
*vbo_data++ = value;
}
}
break;
- }
+ default:
+ BLI_assert_unreachable();
+ break;
}
}
@@ -231,9 +210,9 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
BLI_assert(custom_data);
const int layer_index = request.layer_index;
- int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
+ const int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
- using converter = attribute_type_converter<AttributeType, VBOType>;
+ using Converter = AttributeTypeConverter<AttributeType, VBOType>;
BMIter f_iter;
BMFace *efa;
@@ -255,10 +234,10 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->e, cd_ofs));
}
else {
- BLI_assert(false);
+ BLI_assert_unreachable();
continue;
}
- *vbo_data = converter::convert_value(*attr_data);
+ *vbo_data = Converter::convert_value(*attr_data);
vbo_data++;
} while ((l_iter = l_iter->next) != l_first);
}
@@ -297,37 +276,29 @@ static void extract_attr_init(const MeshRenderData *mr,
* Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a similar
* texture as for volume attribute, so we can control the conversion ourselves. */
switch (request.cd_type) {
- case CD_PROP_BOOL: {
+ case CD_PROP_BOOL:
extract_attr_generic<bool, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_INT8: {
+ case CD_PROP_INT8:
extract_attr_generic<int8_t, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
extract_attr_generic<int32_t, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
extract_attr_generic<float, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
extract_attr_generic<float2>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
extract_attr_generic<float3>(mr, vbo, request);
break;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request);
break;
- }
- default: {
- BLI_assert(false);
- }
+ default:
+ BLI_assert_unreachable();
}
}
@@ -353,37 +324,29 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop));
switch (request.cd_type) {
- case CD_PROP_BOOL: {
+ case CD_PROP_BOOL:
extract_attr_generic<bool, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_INT8: {
+ case CD_PROP_INT8:
extract_attr_generic<int8_t, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
extract_attr_generic<int32_t, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
extract_attr_generic<float, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
extract_attr_generic<float2>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
extract_attr_generic<float3>(mr, src_data, request);
break;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request);
break;
- }
- default: {
- BLI_assert(false);
- }
+ default:
+ BLI_assert_unreachable();
}
GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
@@ -430,7 +393,7 @@ EXTRACT_INIT_WRAPPER(12)
EXTRACT_INIT_WRAPPER(13)
EXTRACT_INIT_WRAPPER(14)
-template<int index>
+template<int Index>
constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn)
{
MeshExtract extractor = {nullptr};
@@ -439,7 +402,7 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
- extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[index]);
+ extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[Index]);
return extractor;
}
diff --git a/source/blender/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/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/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/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 34ae7697d2d..9da2c4819a3 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -772,17 +772,17 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.curve.pen
ops.curve.radius
ops.curve.vertex_random
- ops.curves.density
ops.curves.sculpt_add
ops.curves.sculpt_comb
ops.curves.sculpt_cut
ops.curves.sculpt_delete
+ ops.curves.sculpt_density
ops.curves.sculpt_grow_shrink
ops.curves.sculpt_pinch
ops.curves.sculpt_puff
+ ops.curves.sculpt_slide
ops.curves.sculpt_smooth
ops.curves.sculpt_snake_hook
- ops.curves.slide
ops.generic.cursor
ops.generic.select
ops.generic.select_box
@@ -933,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)
@@ -970,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 37ec7a61bcb..c7e782b7b89 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -518,15 +518,18 @@ static int geometry_color_attribute_duplicate_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
ID *id = static_cast<ID *>(ob->data);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
if (layer == nullptr) {
return OPERATOR_CANCELLED;
}
- CustomDataLayer *newLayer = BKE_id_attribute_duplicate(id, layer, op->reports);
+ CustomDataLayer *new_layer = BKE_id_attribute_duplicate(id, layer->name, op->reports);
+ if (new_layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
- BKE_id_attributes_active_color_set(id, newLayer);
+ BKE_id_attributes_active_color_set(id, new_layer);
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
@@ -539,6 +542,10 @@ static bool geometry_color_attributes_duplicate_poll(bContext *C)
if (!geometry_attributes_poll(C)) {
return false;
}
+ if (CTX_data_edit_object(C) != nullptr) {
+ CTX_wm_operator_poll_msg_set(C, "Operation is not allowed in edit mode");
+ return false;
+ }
Object *ob = ED_object_context(C);
ID *data = ob ? static_cast<ID *>(ob->data) : nullptr;
diff --git a/source/blender/editors/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/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 4733da85291..fc5b3838900 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -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_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_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_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/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 d650f4215b9..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)
@@ -928,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 07232a478dc..984d3409554 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
@@ -3181,7 +3201,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
@@ -3219,6 +3244,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 56df79aac77..a140ee27d3c 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_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_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 241776fd761..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 {
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 11d4a440a68..341d5e78872 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -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);
@@ -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)
+{
+ uiButGridTile *grid_tile_but = (uiButGridTile *)but;
+ BLI_assert(grid_tile_but->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;
+ // 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);
@@ -8019,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;
@@ -9476,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,
@@ -9686,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;
}
@@ -9718,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;
@@ -11318,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_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 60a68e270bf..aafb56119ae 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1942,6 +1942,24 @@ static void UI_OT_drop_color(wmOperatorType *ot)
/** \name Drop Name Operator
* \{ */
+static bool drop_name_poll(bContext *C)
+{
+ if (!ED_operator_regionactive(C)) {
+ return false;
+ }
+
+ const uiBut *but = UI_but_active_drop_name_button(C);
+ if (!but) {
+ return false;
+ }
+
+ if (but->flag & UI_BUT_DISABLED) {
+ return false;
+ }
+
+ return true;
+}
+
static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
uiBut *but = UI_but_active_drop_name_button(C);
@@ -1961,7 +1979,7 @@ static void UI_OT_drop_name(wmOperatorType *ot)
ot->idname = "UI_OT_drop_name";
ot->description = "Drop name to button";
- ot->poll = ED_operator_regionactive;
+ ot->poll = drop_name_poll;
ot->invoke = drop_name_invoke;
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
diff --git a/source/blender/editors/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_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_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 f625bf371e2..4b3937dabce 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/io_obj.c b/source/blender/editors/io/io_obj.c
index a8eed136df3..4819ae09785 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -100,6 +100,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects");
export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv");
export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals");
+ export_params.export_colors = RNA_boolean_get(op->ptr, "export_colors");
export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
export_params.path_mode = RNA_enum_get(op->ptr, "path_mode");
export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
@@ -160,6 +161,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
uiItemR(sub, imfptr, "export_uv", 0, IFACE_("UV Coordinates"), ICON_NONE);
uiItemR(sub, imfptr, "export_normals", 0, IFACE_("Normals"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_colors", 0, IFACE_("Colors"), ICON_NONE);
uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Materials"), ICON_NONE);
uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE);
uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE);
@@ -315,6 +317,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"Export Normals",
"Export per-face normals if the face is flat-shaded, per-face-per-loop "
"normals if smooth-shaded");
+ RNA_def_boolean(ot->srna, "export_colors", false, "Export Colors", "Export per-vertex colors");
RNA_def_boolean(ot->srna,
"export_materials",
true,
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index 45d658d5b25..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 };
@@ -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_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/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/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_ops.c b/source/blender/editors/screen/screen_ops.c
index 80b0862bbab..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;
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index fe48485c7d5..c5ebcf870a3 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -1359,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,
};
@@ -1369,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);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc
index e326d385593..56cd4751881 100644
--- a/source/blender/editors/sculpt_paint/paint_image.cc
+++ b/source/blender/editors/sculpt_paint/paint_image.cc
@@ -272,7 +272,7 @@ static bool image_paint_poll_ex(bContext *C, bool check_tool)
SpaceImage *sima = CTX_wm_space_image(C);
if (sima) {
- if (sima->image != NULL &&
+ if (sima->image != nullptr &&
(ID_IS_LINKED(sima->image) || ID_IS_OVERRIDE_LIBRARY(sima->image))) {
return false;
}
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 48397922ca8..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;
- const 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;
- const 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 c3c69bf4e0a..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);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc
index 8b548a89502..67b60acc667 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -1608,7 +1608,7 @@ 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;
const Scene *scene = CTX_data_scene(C);
@@ -1629,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);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 17a0463abd0..9ce80e4a433 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -4174,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;
@@ -4204,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);
@@ -4343,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 &&
@@ -4373,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],
};
@@ -4392,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;
@@ -4413,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)) {
@@ -4783,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],
@@ -4797,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);
@@ -4821,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);
@@ -4850,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 = {
@@ -4948,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;
@@ -4970,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);
@@ -5275,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)
@@ -5303,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;
@@ -5328,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. */
@@ -5523,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;
}
@@ -5783,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;
@@ -5847,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.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
index 94417defe48..bb101717c9b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
@@ -44,8 +44,8 @@
#include "bmesh.h"
-#include <math.h>
-#include <stdlib.h>
+#include <cmath>
+#include <cstdlib>
using blender::IndexRange;
@@ -57,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,
@@ -170,13 +170,13 @@ 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)
@@ -197,7 +197,7 @@ 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);
@@ -212,7 +212,7 @@ 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 = {0};
+ AutomaskFloodFillData fdata = {nullptr};
fdata.automask_factor = automask_factor;
fdata.radius = radius;
@@ -232,12 +232,12 @@ 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);
@@ -262,7 +262,7 @@ 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);
@@ -327,7 +327,7 @@ 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 = (AutomaskingCache *)MEM_callocN(sizeof(AutomaskingCache),
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 5275c6aac8a..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);
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_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 477c7d5ae00..f16763be735 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -1061,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 cb0a3b75094..48033f3407e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -422,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/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/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/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_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index b817ff887ce..29a7eb150a1 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -46,6 +46,7 @@
#include "BKE_pbvh.h"
#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_modifier.h"
#include "DEG_depsgraph_query.h"
@@ -92,15 +93,18 @@ static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *st
}
int totvert, totedge, totface, totloop;
- if (me_eval->runtime.subdiv_ccg != nullptr) {
- const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
+
+ const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
+ const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime.subsurf_runtime_data;
+
+ if (subdiv_ccg != nullptr) {
BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop);
}
- else if (me_eval->runtime.subsurf_resolution != 0) {
- totvert = me_eval->runtime.subsurf_totvert;
- totedge = me_eval->runtime.subsurf_totedge;
- totface = me_eval->runtime.subsurf_totpoly;
- totloop = me_eval->runtime.subsurf_totloop;
+ else if (subsurf_runtime_data && subsurf_runtime_data->resolution != 0) {
+ totvert = subsurf_runtime_data->stats_totvert;
+ totedge = subsurf_runtime_data->stats_totedge;
+ totface = subsurf_runtime_data->stats_totpoly;
+ totloop = subsurf_runtime_data->stats_totloop;
}
else {
totvert = me_eval->totvert;
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index 475d02020d0..ec19e8d5e5b 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -222,13 +222,33 @@ static void unlink_action_fn(bContext *C,
}
static void unlink_material_fn(bContext *UNUSED(C),
- ReportList *UNUSED(reports),
+ ReportList *reports,
Scene *UNUSED(scene),
TreeElement *te,
TreeStoreElem *tsep,
- TreeStoreElem *UNUSED(tselem),
+ TreeStoreElem *tselem,
void *UNUSED(user_data))
{
+ const bool te_is_material = TSE_IS_REAL_ID(tselem) && (GS(tselem->id->name) == ID_MA);
+
+ if (!te_is_material) {
+ /* Just fail silently. Another element may be selected that is a material, we don't want to
+ * confuse users with an error in that case. */
+ return;
+ }
+
+ if (!tsep || !TSE_IS_REAL_ID(tsep)) {
+ /* Valid case, no parent element of the material or it is not an ID (could be a #TSE_ID_BASE
+ * for example) so there's no data to unlink from. */
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Cannot unlink material '%s'. It's not clear which object or object-data it "
+ "should be unlinked from, there's no object or object-data as parent in the "
+ "Outliner tree",
+ tselem->id->name + 2);
+ return;
+ }
+
Material **matar = nullptr;
int a, totcol = 0;
diff --git a/source/blender/editors/space_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_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_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 422dc4ad29f..01f94bcab55 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_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_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 f0dd0a42ddb..741b1e35838 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -223,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];
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 62afc6ea1b5..649217092aa 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -79,7 +79,7 @@ static void TargetSnapActive(TransInfo *t);
/** \name Implementations
* \{ */
-static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_select);
+static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select);
static NodeBorder snapNodeBorder(eSnapMode snap_node_mode);
#if 0
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_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/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/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 16b9fcbbdd7..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,52 +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;
- LineartElementLinkNode *isect_scheduled_up_to;
- int isect_scheduled_up_to_index;
+ uint32_t tile_count;
- /** This one's memory is not from main pool and is free()ed after culling stage. */
- ListBase triangle_adjacent_pointers;
+ } qtree;
- ListBase intersecting_vertex_buffer;
- /** Use the one comes with Line Art. */
- LineartStaticMemPool render_data_pool;
- ListBase wasted_cuts;
- SpinLock lock_cuts;
+ struct _geom {
- /* This is just a pointer to LineartCache::chain_data_pool, which acts as a cache for line
- * chains. */
- LineartStaticMemPool *chain_data_pool;
+ 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;
@@ -263,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
@@ -361,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;
@@ -393,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;
/**
@@ -465,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))
@@ -632,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);
@@ -675,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;
@@ -695,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 621531d29e3..c08bf3e0fe9 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -46,10 +46,6 @@
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
-#include "bmesh.h"
-#include "bmesh_class.h"
-#include "bmesh_tools.h"
-
#include "lineart_intern.h"
typedef struct LineartIsecSingle {
@@ -73,19 +69,18 @@ typedef struct LineartIsecThread {
int count_test;
/* For individual thread reference.*/
- LineartRenderBuffer *rb;
+ LineartData *ld;
} LineartIsecThread;
typedef struct LineartIsecData {
- LineartRenderBuffer *rb;
+ LineartData *ld;
LineartIsecThread *threads;
int thread_count;
} LineartIsecData;
-static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer *rb,
- LineartEdge *e);
+static LineartBoundingArea *lineart_edge_first_bounding_area(LineartData *ld, LineartEdge *e);
-static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb,
+static void lineart_bounding_area_link_edge(LineartData *ld,
LineartBoundingArea *root_ba,
LineartEdge *e);
@@ -99,12 +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 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,
@@ -121,7 +112,7 @@ 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(LineartRenderBuffer *rb,
+static void lineart_bounding_area_link_triangle(LineartData *ld,
LineartBoundingArea *root_ba,
LineartTriangle *tri,
double *LRUB,
@@ -132,54 +123,54 @@ static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive);
-static void lineart_free_bounding_area_memories(LineartRenderBuffer *rb);
+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
@@ -206,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;
}
@@ -374,10 +369,10 @@ static void lineart_bounding_area_line_add(LineartBoundingArea *ba, LineartEdge
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;
@@ -406,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;
@@ -431,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;
}
@@ -458,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);
}
}
}
@@ -474,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;
@@ -485,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);
@@ -575,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.
@@ -585,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]);
@@ -593,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;
}
/**
@@ -662,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;
@@ -681,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;
@@ -698,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;
@@ -751,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,
@@ -768,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;
@@ -777,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;
@@ -785,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. */
@@ -799,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); \
@@ -817,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) {
@@ -878,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);
@@ -903,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
@@ -931,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;
@@ -952,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];
@@ -972,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;
@@ -993,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];
@@ -1043,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);
@@ -1068,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];
@@ -1099,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;
@@ -1120,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];
@@ -1148,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;
@@ -1169,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];
@@ -1213,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. */
@@ -1244,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; \
}
@@ -1297,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;
@@ -1319,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,
@@ -1348,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];
@@ -1385,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;
@@ -1399,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))) {
@@ -1436,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,
+};
+
+#define LRT_MESH_EDGE_TYPES_COUNT 5
-static int lineart_edge_type_duplication_count(char eflag)
+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++;
}
}
@@ -1454,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;
@@ -1510,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;
@@ -1527,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;
}
@@ -1537,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;
}
}
@@ -1561,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;
}
}
@@ -1612,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;
@@ -1627,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;
}
}
@@ -1643,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]];
@@ -1663,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;
}
@@ -1789,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;
}
}
@@ -1885,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;
@@ -1931,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;
@@ -1965,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;
@@ -1993,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
@@ -2002,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;
@@ -2019,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;
@@ -2051,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);
@@ -2072,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);
@@ -2098,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;
@@ -2114,16 +2128,17 @@ 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;
@@ -2148,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;
}
@@ -2157,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);
}
@@ -2185,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;
}
}
@@ -2219,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);
}
}
@@ -2300,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;
@@ -2356,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,
@@ -2366,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;
@@ -2377,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;
@@ -2400,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;
}
@@ -2423,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;
@@ -2442,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) {
@@ -2450,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);
+
+ double t_start;
+ if (G.debug_value == 4000) {
+ t_start = PIL_check_seconds_timer();
+ }
- int thread_count = rb->thread_count;
+ int thread_count = ld->thread_count;
- /* This memory is in render buffer memory pool. so we don't need to free those after loading.
- */
+ /* 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;
@@ -2502,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;
@@ -2513,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);
}
@@ -2533,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) {
@@ -2551,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);
}
}
@@ -2645,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.
@@ -2658,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.
*
@@ -2680,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;
@@ -2714,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);
-
- sub_v3_v3v3_db(Lv, e->v1->gloc, tri->v[0]->gloc);
- sub_v3_v3v3_db(Rv, e->v2->gloc, tri->v[0]->gloc);
+ INTERSECT_SORT_MIN_TO_MAX_3(cross_ratios[0], cross_ratios[1], cross_ratios[2], cross_order);
- copy_v3_v3_db(Cv, camera_dir);
+ 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(dir_cam, camera_dir);
+ copy_v3_v3_db(view_vector, override_camera_loc);
if (override_cam_is_persp) {
- copy_v3_v3_db(vd4, override_camera_loc);
- }
- else {
- copy_v4_v4_db(vd4, 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
@@ -2749,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. */
@@ -2803,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; \
}
@@ -2811,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);
}
}
}
@@ -2908,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;
}
@@ -2943,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,
@@ -3025,37 +3038,37 @@ static LineartVert *lineart_triangle_share_point(const LineartTriangle *l,
}
static bool lineart_triangle_2v_intersection_math(
- LineartVert *v1, LineartVert *v2, LineartTriangle *t2, double *last, double *rv)
+ LineartVert *v1, LineartVert *v2, LineartTriangle *tri, double *last, double *rv)
{
- double Lv[3];
- double Rv[3];
- double dot_l, dot_r;
+ /* 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;
- sub_v3_v3v3_db(Lv, l->gloc, t2->v[0]->gloc);
- sub_v3_v3v3_db(Rv, r->gloc, t2->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, t2->gn);
- dot_r = dot_v3v3_db(Rv, t2->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)) {
+ 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.
- */
+ /* 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, t2->v[0]->gloc, t2->v[1]->gloc, t2->v[2]->gloc))) {
+ if (!(lineart_point_inside_triangle3d(
+ gloc, tri->v[0]->gloc, tri->v[1]->gloc, tri->v[2]->gloc))) {
return false;
}
@@ -3152,11 +3165,11 @@ static void lineart_add_isec_thread(LineartIsecThread *th,
MEM_freeN(th->array);
th->array = new_array;
}
- LineartIsecSingle *is = &th->array[th->current];
- copy_v3fl_v3db(is->v1, v1);
- copy_v3fl_v3db(is->v2, v2);
- is->tri1 = tri1;
- is->tri2 = tri2;
+ 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++;
}
@@ -3164,38 +3177,38 @@ static void lineart_add_isec_thread(LineartIsecThread *th,
static bool lineart_schedule_new_triangle_task(LineartIsecThread *th)
{
- LineartRenderBuffer *rb = th->rb;
+ LineartData *ld = th->ld;
int remaining = LRT_ISECT_TRIANGLE_PER_THREAD;
- BLI_spin_lock(&rb->lock_task);
- LineartElementLinkNode *eln = rb->isect_scheduled_up_to;
+ BLI_spin_lock(&ld->lock_task);
+ LineartElementLinkNode *eln = ld->isect_scheduled_up_to;
if (!eln) {
- BLI_spin_unlock(&rb->lock_task);
+ BLI_spin_unlock(&ld->lock_task);
return false;
}
th->pending_from = eln;
- th->index_from = rb->isect_scheduled_up_to_index;
+ th->index_from = ld->isect_scheduled_up_to_index;
while (remaining > 0 && eln) {
- int remaining_this_eln = eln->element_count - rb->isect_scheduled_up_to_index;
+ 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;
- rb->isect_scheduled_up_to = eln;
- rb->isect_scheduled_up_to_index = 0;
+ ld->isect_scheduled_up_to = eln;
+ ld->isect_scheduled_up_to_index = 0;
}
else {
- rb->isect_scheduled_up_to_index += added_count;
+ ld->isect_scheduled_up_to_index += added_count;
}
}
- th->pending_to = eln ? eln : rb->triangle_buffer_pointers.last;
- th->index_to = rb->isect_scheduled_up_to_index;
+ th->pending_to = eln ? eln : ld->geom.triangle_buffer_pointers.last;
+ th->index_to = ld->isect_scheduled_up_to_index;
- BLI_spin_unlock(&rb->lock_task);
+ BLI_spin_unlock(&ld->lock_task);
return true;
}
@@ -3205,14 +3218,14 @@ static bool lineart_schedule_new_triangle_task(LineartIsecThread *th)
* 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, LineartRenderBuffer *rb, int thread_count)
+static void lineart_init_isec_thread(LineartIsecData *d, LineartData *ld, int thread_count)
{
d->threads = MEM_callocN(sizeof(LineartIsecThread) * thread_count, "LineartIsecThread arr");
- d->rb = rb;
+ d->ld = ld;
d->thread_count = thread_count;
- rb->isect_scheduled_up_to = rb->triangle_buffer_pointers.first;
- rb->isect_scheduled_up_to_index = 0;
+ ld->isect_scheduled_up_to = ld->geom.triangle_buffer_pointers.first;
+ ld->isect_scheduled_up_to_index = 0;
for (int i = 0; i < thread_count; i++) {
LineartIsecThread *it = &d->threads[i];
@@ -3220,7 +3233,7 @@ static void lineart_init_isec_thread(LineartIsecData *d, LineartRenderBuffer *rb
it->max = 100;
it->current = 0;
it->thread_id = i;
- it->rb = rb;
+ it->ld = ld;
}
}
@@ -3290,14 +3303,14 @@ static void lineart_triangle_intersect_in_bounding_area(LineartTriangle *tri,
/**
* 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]);
@@ -3305,45 +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_free_bounding_area_memories(rb);
+ lineart_free_bounding_area_memories(ld);
- lineart_mem_destroy(&rb->render_data_pool);
+ 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) {
@@ -3367,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) {
@@ -3390,97 +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);
- rb->thread_count = BKE_render_num_threads(&scene->r);
+ ld->thread_count = BKE_render_num_threads(&scene->r);
- return rb;
+ return ld;
}
-static int lineart_triangle_size_get(LineartRenderBuffer *rb)
+static int lineart_triangle_size_get(LineartData *ld)
{
- 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
@@ -3491,11 +3505,11 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
LineartBoundingArea *ba;
/* Always make sure the shortest side has at least LRT_BA_ROWS tiles. */
- if (rb->w > rb->h) {
- sp_w = sp_h * rb->w / rb->h;
+ if (ld->w > ld->h) {
+ sp_w = sp_h * ld->w / ld->h;
}
else {
- sp_h = sp_w * rb->h / rb->w;
+ sp_h = sp_w * ld->h / ld->w;
}
/* Because NDC (Normalized Device Coordinates) range is (-1,1),
@@ -3503,19 +3517,19 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
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 * rb->tile_count_x + col];
+ ba = &ld->qtree.initials[row * ld->qtree.count_x + col];
/* Set the four direction limits. */
ba->l = span_w * col - 1.0;
@@ -3542,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]);
@@ -3682,54 +3696,45 @@ static void lineart_bounding_areas_connect_new(LineartRenderBuffer *rb, LineartB
BLI_listbase_clear(&root->bp);
}
-static void lineart_bounding_areas_connect_recursive(LineartRenderBuffer *rb,
- LineartBoundingArea *root)
+static void lineart_bounding_areas_connect_recursive(LineartData *ld, LineartBoundingArea *root)
{
if (root->child) {
- lineart_bounding_areas_connect_new(rb, root);
+ lineart_bounding_areas_connect_new(ld, root);
for (int i = 0; i < 4; i++) {
- lineart_bounding_areas_connect_recursive(rb, &root->child[i]);
+ lineart_bounding_areas_connect_recursive(ld, &root->child[i]);
}
}
}
-static void lineart_main_bounding_areas_connect_post(LineartRenderBuffer *rb)
+static void lineart_main_bounding_areas_connect_post(LineartData *ld)
{
- int total_tile_initial = rb->tile_count_x * rb->tile_count_y;
- int tiles_per_row = rb->tile_count_x;
+ 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 < rb->tile_count_y; row++) {
- for (int col = 0; col < rb->tile_count_x; col++) {
- LineartBoundingArea *ba = &rb->initial_bounding_areas[row * tiles_per_row + col];
+ 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,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[(row - 1) * tiles_per_row + col]);
+ &ba->up, &ld->render_data_pool, &ld->qtree.initials[(row - 1) * tiles_per_row + col]);
}
if (col) {
lineart_list_append_pointer_pool(
- &ba->lp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[row * tiles_per_row + col - 1]);
+ &ba->lp, &ld->render_data_pool, &ld->qtree.initials[row * tiles_per_row + col - 1]);
}
- if (row != rb->tile_count_y - 1) {
+ if (row != ld->qtree.count_y - 1) {
lineart_list_append_pointer_pool(
- &ba->bp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[(row + 1) * tiles_per_row + col]);
+ &ba->bp, &ld->render_data_pool, &ld->qtree.initials[(row + 1) * tiles_per_row + col]);
}
- if (col != rb->tile_count_x - 1) {
+ if (col != ld->qtree.count_x - 1) {
lineart_list_append_pointer_pool(
- &ba->rp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[row * tiles_per_row + col + 1]);
+ &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(rb, &rb->initial_bounding_areas[i]);
+ lineart_bounding_areas_connect_recursive(ld, &ld->qtree.initials[i]);
}
}
@@ -3737,12 +3742,12 @@ static void lineart_main_bounding_areas_connect_post(LineartRenderBuffer *rb)
* 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_thread(&rb->render_data_pool,
+ LineartBoundingArea *ba = lineart_mem_acquire_thread(&ld->render_data_pool,
sizeof(LineartBoundingArea) * 4);
ba[0].l = root->cx;
ba[0].r = root->r;
@@ -3795,16 +3800,16 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb,
/* 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(rb, &ba[0], tri, b, 0, recursive_level + 1, false, NULL);
+ lineart_bounding_area_link_triangle(ld, &ba[0], tri, b, 0, recursive_level + 1, false, NULL);
}
if (LRT_BOUND_AREA_CROSSES(b, &ba[1].l)) {
- lineart_bounding_area_link_triangle(rb, &ba[1], tri, b, 0, recursive_level + 1, false, NULL);
+ lineart_bounding_area_link_triangle(ld, &ba[1], tri, b, 0, recursive_level + 1, false, NULL);
}
if (LRT_BOUND_AREA_CROSSES(b, &ba[2].l)) {
- lineart_bounding_area_link_triangle(rb, &ba[2], tri, b, 0, recursive_level + 1, false, NULL);
+ lineart_bounding_area_link_triangle(ld, &ba[2], tri, b, 0, recursive_level + 1, false, NULL);
}
if (LRT_BOUND_AREA_CROSSES(b, &ba[3].l)) {
- lineart_bounding_area_link_triangle(rb, &ba[3], tri, b, 0, recursive_level + 1, false, NULL);
+ lineart_bounding_area_link_triangle(ld, &ba[3], tri, b, 0, recursive_level + 1, false, NULL);
}
}
@@ -3812,15 +3817,15 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb,
* inserted, so assign root->child for #lineart_bounding_area_link_triangle to use. */
root->child = ba;
- rb->bounding_area_count += 3;
+ 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;
@@ -3831,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;
}
@@ -3858,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)
{
@@ -3895,7 +3900,7 @@ static bool lineart_bounding_area_triangle_intersect(LineartRenderBuffer *fb,
/**
* This function does two things:
*
- * 1) Builds a quad-tree under rb->InitialBoundingAreas to achieve good geometry separation for
+ * 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.
*
@@ -3905,7 +3910,7 @@ static bool lineart_bounding_area_triangle_intersect(LineartRenderBuffer *fb,
* 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,
@@ -3914,7 +3919,7 @@ static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
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;
}
@@ -3935,7 +3940,7 @@ static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
for (int iba = 0; iba < 4; iba++) {
if (LRT_BOUND_AREA_CROSSES(B1, &old_ba->child[iba].l)) {
lineart_bounding_area_link_triangle(
- rb, &old_ba->child[iba], tri, B1, recursive, recursive_level + 1, do_intersection, th);
+ ld, &old_ba->child[iba], tri, B1, recursive, recursive_level + 1, do_intersection, th);
}
}
return;
@@ -3954,7 +3959,7 @@ static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
old_ba->linked_triangles[old_ba->triangle_count++] = tri;
/* Do intersections in place. */
- if (do_intersection && rb->use_intersections) {
+ if (do_intersection && ld->conf.use_intersections) {
lineart_triangle_intersect_in_bounding_area(tri, old_ba, th, old_tri_count);
}
@@ -3964,10 +3969,10 @@ static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
}
else { /* We need to wait for either splitting or array extension to be done. */
- if (recursive_level < rb->tile_recursive_level) {
+ 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(rb, old_ba, recursive_level);
+ lineart_bounding_area_split(ld, old_ba, recursive_level);
} /* Otherwise other thread has completed the splitting process. */
}
else {
@@ -3984,7 +3989,7 @@ static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
/* Of course we still have our own triangle needs to be added. */
lineart_bounding_area_link_triangle(
- rb, root_ba, tri, LRUB, recursive, recursive_level, do_intersection, th);
+ ld, root_ba, tri, LRUB, recursive, recursive_level, do_intersection, th);
}
}
@@ -4003,17 +4008,16 @@ static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recu
}
}
}
-static void lineart_free_bounding_area_memories(LineartRenderBuffer *rb)
+static void lineart_free_bounding_area_memories(LineartData *ld)
{
- for (int i = 0; i < rb->tile_count_y; i++) {
- for (int j = 0; j < rb->tile_count_x; j++) {
- lineart_free_bounding_area_memory(&rb->initial_bounding_areas[i * rb->tile_count_x + j],
- true);
+ 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)
{
@@ -4022,20 +4026,20 @@ static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb,
}
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);
}
}
}
@@ -4043,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 * rb->tile_count_x + col], e);
+ ld, &ld->qtree.initials[row * ld->qtree.count_x + col], e);
}
}
}
@@ -4060,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]) {
@@ -4085,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;
@@ -4104,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) {
@@ -4133,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) {
@@ -4165,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;
@@ -4180,29 +4174,29 @@ LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *r
row = 0;
}
- return &rb->initial_bounding_areas[row * rb->tile_count_x + 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 * rb->tile_count_x + c];
+ iba = &ld->qtree.initials[r * ld->qtree.count_x + c];
while (iba->child) {
if (x > iba->cx) {
if (y > iba->cy) {
@@ -4224,49 +4218,48 @@ 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)
{
- LineartRenderBuffer *rb = th->rb;
+ 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) + rb->triangle_size * index_start);
+ 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) + rb->triangle_size);
+ tri = (void *)(((uchar *)tri) + ld->sizeof_triangle);
continue;
}
- if (lineart_get_triangle_bounding_areas(rb, tri, &y1, &y2, &x1, &x2)) {
+ 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(
- rb,
- &rb->initial_bounding_areas[r * rb->tile_count_x + co],
- tri,
- 0,
- 1,
- 0,
- (!(tri->flags & LRT_TRIANGLE_NO_INTERSECTION)),
- th);
+ 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) + rb->triangle_size);
+ tri = (void *)(((uchar *)tri) + ld->sizeof_triangle);
}
}
}
@@ -4274,9 +4267,9 @@ static void lineart_add_triangles_worker(TaskPool *__restrict UNUSED(pool), Line
static void lineart_create_edges_from_isec_data(LineartIsecData *d)
{
- LineartRenderBuffer *rb = d->rb;
- double ZMax = rb->far_clip;
- double ZMin = rb->near_clip;
+ 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];
@@ -4289,9 +4282,9 @@ static void lineart_create_edges_from_isec_data(LineartIsecData *d)
/* 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(
- &rb->render_data_pool, sizeof(LineartVertIntersection) * th->current * 2);
- LineartEdge *e = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdge) * th->current);
- LineartEdgeSegment *es = lineart_mem_acquire(&rb->render_data_pool,
+ &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;
@@ -4307,15 +4300,15 @@ static void lineart_create_edges_from_isec_data(LineartIsecData *d)
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, rb->view_projection, v1->gloc);
- mul_v4_m4v3_db(v2->fbcoord, rb->view_projection, v2->gloc);
+ 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] -= 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;
+ 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
@@ -4331,7 +4324,7 @@ static void lineart_create_edges_from_isec_data(LineartIsecData *d)
e->intersection_mask = (is->tri1->intersection_mask | is->tri2->intersection_mask);
BLI_addtail(&e->segments, es);
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
v += 2;
e++;
@@ -4344,7 +4337,7 @@ static void lineart_create_edges_from_isec_data(LineartIsecData *d)
* 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)
{
double t_start;
if (G.debug_value == 4000) {
@@ -4354,10 +4347,10 @@ static void lineart_main_add_triangles(LineartRenderBuffer *rb)
/* Initialize per-thread data for thread task scheduling information and storing intersection
* results. */
LineartIsecData d = {0};
- lineart_init_isec_thread(&d, rb, rb->thread_count);
+ lineart_init_isec_thread(&d, ld, ld->thread_count);
TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
- for (int i = 0; i < rb->thread_count; i++) {
+ 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);
@@ -4378,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};
@@ -4387,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) &&
@@ -4408,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]);
}
/**
@@ -4639,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;
@@ -4650,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 !=
@@ -4660,6 +4650,9 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
}
}
else {
+
+ BKE_scene_camera_switch_update(scene);
+
if (!scene->camera) {
return false;
}
@@ -4669,58 +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(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(rb);
+ 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
@@ -4729,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);
@@ -4785,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;
}
@@ -4812,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,
@@ -4971,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,
@@ -4993,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 2114ca1dc91..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. */
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/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 808a8ccd955..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
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/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/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/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/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/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/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/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
index 82bb1c57833..1fbddc45964 100644
--- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
@@ -267,6 +267,11 @@ void AbstractHierarchyIterator::export_graph_construct()
{
Scene *scene = DEG_get_evaluated_scene(depsgraph_);
+ /* Add a "null" root node with no children immediately for the case where the top-most node in
+ * the scene is not being exported and a root node otherwise wouldn't get added. */
+ ExportGraph::key_type root_node_id = ObjectIdentifier::for_real_object(nullptr);
+ export_graph_[root_node_id] = ExportChildren();
+
DEG_OBJECT_ITER_BEGIN (depsgraph_,
object,
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc
index 5f5c2624414..7de8239b233 100644
--- a/source/blender/io/stl/importer/stl_import_mesh.cc
+++ b/source/blender/io/stl/importer/stl_import_mesh.cc
@@ -21,30 +21,30 @@
namespace blender::io::stl {
-STLMeshHelper::STLMeshHelper(int num_tris, bool use_custom_normals)
- : m_use_custom_normals(use_custom_normals)
+STLMeshHelper::STLMeshHelper(int tris_num, bool use_custom_normals)
+ : use_custom_normals_(use_custom_normals)
{
- m_num_degenerate_tris = 0;
- m_num_duplicate_tris = 0;
- m_tris.reserve(num_tris);
+ degenerate_tris_num_ = 0;
+ duplicate_tris_num_ = 0;
+ tris_.reserve(tris_num);
/* Upper bound (all vertices are unique). */
- m_verts.reserve(num_tris * 3);
+ verts_.reserve(tris_num * 3);
if (use_custom_normals) {
- m_loop_normals.reserve(num_tris * 3);
+ loop_normals_.reserve(tris_num * 3);
}
}
bool STLMeshHelper::add_triangle(const float3 &a, const float3 &b, const float3 &c)
{
- int v1_id = m_verts.index_of_or_add(a);
- int v2_id = m_verts.index_of_or_add(b);
- int v3_id = m_verts.index_of_or_add(c);
+ int v1_id = verts_.index_of_or_add(a);
+ int v2_id = verts_.index_of_or_add(b);
+ int v3_id = verts_.index_of_or_add(c);
if ((v1_id == v2_id) || (v1_id == v3_id) || (v2_id == v3_id)) {
- m_num_degenerate_tris++;
+ degenerate_tris_num_++;
return false;
}
- if (!m_tris.add({v1_id, v2_id, v3_id})) {
- m_num_duplicate_tris++;
+ if (!tris_.add({v1_id, v2_id, v3_id})) {
+ duplicate_tris_num_++;
return false;
}
return true;
@@ -56,18 +56,18 @@ void STLMeshHelper::add_triangle(const float3 &a,
const float3 &custom_normal)
{
if (add_triangle(a, b, c)) {
- m_loop_normals.append_n_times(custom_normal, 3);
+ loop_normals_.append_n_times(custom_normal, 3);
}
}
Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name)
{
- if (m_num_degenerate_tris > 0) {
- std::cout << "STL Importer: " << m_num_degenerate_tris << "degenerate triangles were removed"
+ if (degenerate_tris_num_ > 0) {
+ std::cout << "STL Importer: " << degenerate_tris_num_ << "degenerate triangles were removed"
<< std::endl;
}
- if (m_num_duplicate_tris > 0) {
- std::cout << "STL Importer: " << m_num_duplicate_tris << "duplicate triangles were removed"
+ if (duplicate_tris_num_ > 0) {
+ std::cout << "STL Importer: " << duplicate_tris_num_ << "duplicate triangles were removed"
<< std::endl;
}
@@ -75,36 +75,36 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name)
/* User count is already 1 here, but will be set later in #BKE_mesh_assign_object. */
id_us_min(&mesh->id);
- mesh->totvert = m_verts.size();
+ mesh->totvert = verts_.size();
mesh->mvert = static_cast<MVert *>(
CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert));
for (int i = 0; i < mesh->totvert; i++) {
- copy_v3_v3(mesh->mvert[i].co, m_verts[i]);
+ copy_v3_v3(mesh->mvert[i].co, verts_[i]);
}
- mesh->totpoly = m_tris.size();
- mesh->totloop = m_tris.size() * 3;
+ mesh->totpoly = tris_.size();
+ mesh->totloop = tris_.size() * 3;
mesh->mpoly = static_cast<MPoly *>(
CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly));
mesh->mloop = static_cast<MLoop *>(
CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop));
- threading::parallel_for(m_tris.index_range(), 2048, [&](IndexRange tris_range) {
+ threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) {
for (const int i : tris_range) {
mesh->mpoly[i].loopstart = 3 * i;
mesh->mpoly[i].totloop = 3;
- mesh->mloop[3 * i].v = m_tris[i].v1;
- mesh->mloop[3 * i + 1].v = m_tris[i].v2;
- mesh->mloop[3 * i + 2].v = m_tris[i].v3;
+ mesh->mloop[3 * i].v = tris_[i].v1;
+ mesh->mloop[3 * i + 1].v = tris_[i].v2;
+ mesh->mloop[3 * i + 2].v = tris_[i].v3;
}
});
/* NOTE: edges must be calculated first before setting custom normals. */
BKE_mesh_calc_edges(mesh, false, false);
- if (m_use_custom_normals && m_loop_normals.size() == mesh->totloop) {
- BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(m_loop_normals.data()));
+ if (use_custom_normals_ && loop_normals_.size() == mesh->totloop) {
+ BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(loop_normals_.data()));
mesh->flag |= ME_AUTOSMOOTH;
}
diff --git a/source/blender/io/stl/importer/stl_import_mesh.hh b/source/blender/io/stl/importer/stl_import_mesh.hh
index a01e5be09a4..f1c0d2126a9 100644
--- a/source/blender/io/stl/importer/stl_import_mesh.hh
+++ b/source/blender/io/stl/importer/stl_import_mesh.hh
@@ -47,15 +47,15 @@ class Triangle {
class STLMeshHelper {
private:
- VectorSet<float3> m_verts;
- VectorSet<Triangle> m_tris;
- Vector<float3> m_loop_normals;
- int m_num_degenerate_tris;
- int m_num_duplicate_tris;
- const bool m_use_custom_normals;
+ VectorSet<float3> verts_;
+ VectorSet<Triangle> tris_;
+ Vector<float3> loop_normals_;
+ int degenerate_tris_num_;
+ int duplicate_tris_num_;
+ const bool use_custom_normals_;
public:
- STLMeshHelper(int num_tris, bool use_custom_normals);
+ STLMeshHelper(int tris_num, bool use_custom_normals);
/* Creates a new triangle from specified vertex locations,
* duplicate vertices and triangles are merged.
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 2c86bfff4da..368d0e1bab9 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -62,11 +62,56 @@ 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, std::string> &usd_path_to_mat_name)
{
if (!(stage && bmain && ob)) {
return;
@@ -94,13 +139,10 @@ static void assign_materials(Main *bmain,
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_map, usd_path_to_mat_name);
+ if (!assigned_mat) {
/* Blender material doesn't exist, so create it now. */
/* Look up the USD material. */
@@ -122,11 +164,14 @@ static void assign_materials(Main *bmain,
continue;
}
+ const std::string mat_name = pxr::TfMakeValidIdentifier(assigned_mat->id.name + 2);
mat_map[mat_name] = assigned_mat;
- }
- else {
- /* We found an existing Blender material. */
- assigned_mat = mat_iter->second;
+
+ 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 +179,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 +755,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 +785,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 +805,12 @@ 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());
+ utils::assign_materials(bmain,
+ object_,
+ mat_map,
+ this->import_params_,
+ this->prim_.GetStage(),
+ 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..f2df00accf6 100644
--- a/source/blender/io/usd/intern/usd_reader_prim.h
+++ b/source/blender/io/usd/intern/usd_reader_prim.h
@@ -7,6 +7,9 @@
#include <pxr/usd/usd/prim.h>
+#include <map>
+#include <string>
+
struct Main;
struct Object;
@@ -33,6 +36,13 @@ 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;
+
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/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 0a78cdc714d..a719dff2126 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -45,6 +45,7 @@ struct OBJExportParams {
eEvaluationMode export_eval_mode;
bool export_uv;
bool export_normals;
+ bool export_colors;
bool export_materials;
bool export_triangulated_mesh;
bool export_curves_as_nurbs;
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
index 11d1bafdafe..cb95c561547 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
@@ -8,7 +8,9 @@
#include <cstdio>
#include "BKE_blender_version.h"
+#include "BKE_geometry_set.hh"
+#include "BLI_color.hh"
#include "BLI_enumerable_thread_specific.hh"
#include "BLI_path_util.h"
#include "BLI_task.hh"
@@ -241,13 +243,38 @@ void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh,
}
void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
- const OBJMesh &obj_mesh_data) const
+ const OBJMesh &obj_mesh_data,
+ bool write_colors) const
{
const int tot_count = obj_mesh_data.tot_vertices();
- obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
- float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
- buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
- });
+
+ Mesh *mesh = obj_mesh_data.get_mesh();
+ CustomDataLayer *colors_layer = nullptr;
+ if (write_colors) {
+ colors_layer = BKE_id_attributes_active_color_get(&mesh->id);
+ }
+ if (write_colors && (colors_layer != nullptr)) {
+ MeshComponent component;
+ component.replace(mesh, GeometryOwnershipType::ReadOnly);
+ VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>(
+ colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f});
+
+ BLI_assert(tot_count == attribute.size());
+ obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ ColorGeometry4f linear = attribute.get(i);
+ float srgb[3];
+ linearrgb_to_srgb_v3_v3(srgb, linear);
+ buf.write<eOBJSyntaxElement::vertex_coords_color>(
+ vertex[0], vertex[1], vertex[2], srgb[0], srgb[1], srgb[2]);
+ });
+ }
+ else {
+ obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
+ });
+ }
}
void OBJWriter::write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &r_obj_mesh_data) const
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
index 77da7b44276..97c23484426 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -72,9 +72,11 @@ class OBJWriter : NonMovable, NonCopyable {
*/
void write_mtllib_name(const StringRefNull mtl_filepath) const;
/**
- * Write vertex coordinates for all vertices as "v x y z".
+ * Write vertex coordinates for all vertices as "v x y z" or "v x y z r g b".
*/
- void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const;
+ void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
+ const OBJMesh &obj_mesh_data,
+ bool write_colors) const;
/**
* Write UV vertex coordinates for all vertices as `vt u v`.
* \note UV indices are stored here, but written with polygons later.
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
index f0263989bfc..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 8556d7c275c..e2ecda32717 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -122,9 +122,7 @@ 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(IO_AXIS_Y, IO_AXIS_Z, 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]);
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
index 91213ec8152..ee2e6227700 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -241,6 +241,11 @@ class OBJMesh : NonCopyable {
return i < 0 || i >= poly_order_.size() ? i : poly_order_[i];
}
+ Mesh *get_mesh() const
+ {
+ return export_mesh_eval_;
+ }
+
private:
/**
* Free the mesh if _the exporter_ created it.
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
index c0c29fcfdf8..172a59e5341 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
@@ -30,9 +30,7 @@ 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(IO_AXIS_Y, IO_AXIS_Z, 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_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 3c0ef646e13..f33753d720d 100644
--- a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
+++ b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
@@ -100,9 +100,7 @@ void transform_object(Object *object, const OBJImportParams &import_params)
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, IO_AXIS_Y, IO_AXIS_Z, axes_transform);
- /* mat3_from_axis_conversion returns a transposed matrix! */
- transpose_m3(axes_transform);
+ 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 a627e7261e3..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;
@@ -482,6 +531,9 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
else if (parse_keyword(p, end, "mtllib")) {
add_mtl_library(StringRef(p, end).trim());
}
+ else if (parse_keyword(p, end, "#MRGB")) {
+ geom_add_mrgb_colors(curr_geom, p, end, r_global_vertices);
+ }
/* Comments. */
else if (*p == '#') {
/* Nothing to do. */
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
index 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 b384d934c82..6aec848573f 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -436,6 +436,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;
@@ -494,6 +507,7 @@ TEST_F(obj_exporter_regression_test, all_objects)
_export.params.forward_axis = IO_AXIS_Y;
_export.params.up_axis = IO_AXIS_Z;
_export.params.export_smooth_groups = true;
+ _export.params.export_colors = true;
compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend",
"io_tests/obj/all_objects.obj",
"io_tests/obj/all_objects.mtl",
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
index 42f7620999d..7d3b41ed527 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
@@ -26,6 +26,7 @@ struct OBJExportParamsDefault {
params.export_selected_objects = false;
params.export_uv = true;
params.export_normals = true;
+ params.export_colors = false;
params.export_materials = true;
params.path_mode = PATH_REFERENCE_AUTO;
params.export_triangulated_mesh = false;
diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
index 6d09f522028..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 {
@@ -98,6 +99,15 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
float2 uv_first = mloopuv ? float2(mloopuv->uv) : float2(0, 0);
EXPECT_V2_NEAR(uv_first, exp.uv_first, 0.0001f);
+ if (exp.color_first.x >= 0) {
+ const float4 *colors = (const float4 *)(CustomData_get_layer(&mesh->vdata,
+ CD_PROP_COLOR));
+ EXPECT_TRUE(colors != nullptr);
+ EXPECT_V4_NEAR(colors[0], exp.color_first, 0.0001f);
+ }
+ else {
+ EXPECT_FALSE(CustomData_has_layer(&mesh->vdata, CD_PROP_COLOR));
+ }
}
if (object->type == OB_CURVES_LEGACY) {
Curve *curve = static_cast<Curve *>(DEG_get_evaluated_object(depsgraph, object)->data);
@@ -434,7 +444,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_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_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 a66badb4a68..2eca84959b8 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -32,6 +32,7 @@ struct MVert;
struct Material;
struct Mesh;
struct SubdivCCG;
+struct SubsurfRuntimeData;
#
#
@@ -123,26 +124,18 @@ typedef struct Mesh_Runtime {
/**
* Settings for lazily evaluating the subdivision on the CPU if needed. These are
- * set in the modifier when GPU subdivision can be performed.
+ * set in the modifier when GPU subdivision can be performed, and owned by the by
+ * the modifier in the object.
*/
- SessionUUID subsurf_session_uuid;
- char subsurf_resolution;
- char subsurf_do_loop_normals;
- char subsurf_apply_render;
- char subsurf_use_optimal_display;
-
- /* Cached from the draw code for stats display. */
- int subsurf_totvert;
- int subsurf_totedge;
- int subsurf_totpoly;
- int subsurf_totloop;
- char _pad2[2];
+ struct SubsurfRuntimeData *subsurf_runtime_data;
+ void *_pad1;
/**
* Caches for lazily computed vertex and polygon normals. These are stored here rather than in
* #CustomData because they can be calculated on a const mesh, and adding custom data layers on a
* const mesh is not thread-safe.
*/
+ char _pad2[6];
char vert_normals_dirty;
char poly_normals_dirty;
float (*vert_normals)[3];
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 6e3ce7e98a8..f148116eba8 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -178,13 +178,6 @@ typedef enum {
SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS = 1,
} eSubsurfBoundarySmooth;
-typedef struct SubsurfRuntimeData {
- /* Cached subdivision surface descriptor, with topology and settings. */
- struct Subdiv *subdiv;
- char set_by_draw_code;
- char _pad[7];
-} SubsurfRuntimeData;
-
typedef struct SubsurfModifierData {
ModifierData modifier;
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index e449605ed81..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;
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/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_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_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_api.c b/source/blender/makesrna/intern/rna_image_api.c
index d2b8b32eedc..be1e344d73f 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -160,15 +160,14 @@ static void rna_Image_update(Image *image, ReportList *reports)
BKE_image_release_ibuf(image, ibuf, NULL);
}
-static void rna_Image_scale(Image *image, bContext *C, ReportList *reports, int width, int height)
+static void rna_Image_scale(Image *image, ReportList *reports, int width, int height)
{
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;
}
- else {
- BKE_image_partial_update_mark_full_update(image);
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, image);
- }
+ BKE_image_partial_update_mark_full_update(image);
+ WM_main_add_notifier(NC_IMAGE | NA_EDITED, image);
}
static int rna_Image_gl_load(
@@ -285,7 +284,7 @@ void RNA_api_image(StructRNA *srna)
func = RNA_def_function(srna, "scale", "rna_Image_scale");
RNA_def_function_ui_description(func, "Scale the buffer of the image, in pixels");
- RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_int(func, "width", 1, 1, INT_MAX, "", "Width", 1, INT_MAX);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "height", 1, 1, INT_MAX, "", "Height", 1, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 895d6e8ba70..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", ""}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 3b739561f9a..9e2a1d81bd3 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -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 */
@@ -5922,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_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/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index 07504d91fea..5739de1c65c 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -447,7 +447,8 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
material_remaps,
use_self,
hole_tolerant,
- bmd->operation);
+ bmd->operation,
+ nullptr);
}
#endif
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 4201bab0326..23f447f2469 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -196,16 +196,21 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
/* Cache settings for lazy CPU evaluation. */
-static void subdiv_cache_cpu_evaluation_settings(const ModifierEvalContext *ctx,
- Mesh *me,
- SubsurfModifierData *smd)
+static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx,
+ Mesh *mesh,
+ SubsurfModifierData *smd,
+ SubsurfRuntimeData *runtime_data)
{
SubdivToMeshSettings mesh_settings;
subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
- me->runtime.subsurf_apply_render = (ctx->flag & MOD_APPLY_RENDER) != 0;
- me->runtime.subsurf_resolution = mesh_settings.resolution;
- me->runtime.subsurf_use_optimal_display = mesh_settings.use_optimal_display;
- me->runtime.subsurf_session_uuid = smd->modifier.session_uuid;
+
+ runtime_data->has_gpu_subdiv = true;
+ runtime_data->resolution = mesh_settings.resolution;
+ runtime_data->use_optimal_display = mesh_settings.use_optimal_display;
+ runtime_data->calc_loop_normals = false; /* Set at the end of modifier stack evaluation. */
+ runtime_data->use_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals);
+
+ mesh->runtime.subsurf_runtime_data = runtime_data;
}
/* Modifier itself. */
@@ -218,13 +223,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return result;
#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(
- &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
- if (subdiv_settings.level == 0) {
+ if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return result;
}
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
/* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier.
*/
@@ -237,13 +240,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
const bool is_editmode = (mesh->edit_mesh != NULL);
const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode);
if (BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ctx->object, mesh, smd, required_mode)) {
- subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd);
+ subdiv_cache_mesh_wrapper_settings(ctx, mesh, smd, runtime_data);
return result;
}
}
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
- smd, &subdiv_settings, mesh, false);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return result;
@@ -294,15 +296,11 @@ static void deformMatrices(ModifierData *md,
(void)deform_matrices;
SubsurfModifierData *smd = (SubsurfModifierData *)md;
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(
- &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
- if (subdiv_settings.level == 0) {
+ if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return;
}
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
- smd, &subdiv_settings, mesh, false);
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_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_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index 08b107e0152..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,6 +8,7 @@
#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"
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/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/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/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 e097de237f2..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_time_left_handle_frame_get(seq) > range_start) {
- range_start = SEQ_time_left_handle_frame_get(seq);
- }
-
- if (SEQ_time_right_handle_frame_get(seq) < range_end) {
- range_end = SEQ_time_right_handle_frame_get(seq);
- }
+ 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 ebf317eff05..19caf12ff2a 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -13,11 +13,13 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
#include "SEQ_animation.h"
#include "SEQ_channels.h"
+#include "SEQ_edit.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
@@ -307,6 +309,7 @@ static int shuffle_seq_time_offset_get(SeqCollection *strips_to_shuffle,
}
bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
+ SeqCollection *time_dependent_strips,
ListBase *seqbasep,
Scene *evil_scene,
ListBase *markers,
@@ -323,6 +326,12 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
seq->flag &= ~SEQ_OVERLAP;
}
+ if (time_dependent_strips != NULL) {
+ SEQ_ITERATOR_FOREACH (seq, time_dependent_strips) {
+ SEQ_offset_animdata(evil_scene, seq, offset);
+ }
+ }
+
if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) {
TimeMarker *marker;
/* affect selected markers - it's unlikely that we will want to affect all in this way? */
@@ -337,6 +346,296 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
return offset ? false : true;
}
+static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips)
+{
+ SeqCollection *collection = SEQ_collection_create(__func__);
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
+
+/* Query strips positioned after left edge of transformed strips bound-box. */
+static SeqCollection *query_right_side_strips(ListBase *seqbase,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips)
+{
+ int minframe = MAXFRAME;
+ {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ minframe = min_ii(minframe, SEQ_time_left_handle_frame_get(seq));
+ }
+ }
+
+ SeqCollection *collection = SEQ_collection_create(__func__);
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (SEQ_collection_has_strip(seq, time_dependent_strips)) {
+ continue;
+ }
+ if (SEQ_collection_has_strip(seq, transformed_strips)) {
+ continue;
+ }
+
+ if ((seq->flag & SELECT) == 0 && SEQ_time_left_handle_frame_get(seq) >= minframe) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
+
+/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal
+ * to overlap of transformed strips. */
+static void seq_transform_handle_expand_to_fit(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ ListBase *markers = &scene->markers;
+
+ SeqCollection *right_side_strips = query_right_side_strips(
+ seqbasep, transformed_strips, time_dependent_strips);
+
+ /* Temporarily move right side strips beyond timeline boundary. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine += MAXSEQ * 2;
+ }
+
+ /* Shuffle transformed standalone strips. This is because transformed strips can overlap with
+ * strips on left side. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
+
+ /* Move temporarily moved strips back to their original place and tag for shuffling. */
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine -= MAXSEQ * 2;
+ }
+ /* Shuffle again to displace strips on right side. Final effect shuffling is done in
+ * SEQ_transform_handle_overlap. */
+ SEQ_transform_seqbase_shuffle_time(
+ right_side_strips, NULL, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(right_side_strips);
+}
+
+static SeqCollection *query_overwrite_targets(ListBase *seqbasep,
+ SeqCollection *transformed_strips)
+{
+ SeqCollection *collection = SEQ_query_unselected_strips(seqbasep);
+
+ Sequence *seq, *seq_transformed;
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ bool does_overlap = false;
+
+ SEQ_ITERATOR_FOREACH (seq_transformed, transformed_strips) {
+ /* Effects of transformed strips can be unselected. These must not be included. */
+ if (seq == seq_transformed) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ if (SEQ_transform_test_overlap_seq_seq(seq, seq_transformed)) {
+ does_overlap = true;
+ }
+ }
+
+ if (!does_overlap) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ }
+
+ return collection;
+}
+
+typedef enum eOvelapDescrition {
+ /* No overlap. */
+ STRIP_OVERLAP_NONE,
+ /* Overlapping strip covers overlapped completely. */
+ STRIP_OVERLAP_IS_FULL,
+ /* Overlapping strip is inside overlapped. */
+ STRIP_OVERLAP_IS_INSIDE,
+ /* Partial overlap between 2 strips. */
+ STRIP_OVERLAP_LEFT_SIDE,
+ STRIP_OVERLAP_RIGHT_SIDE,
+} eOvelapDescrition;
+
+static eOvelapDescrition overlap_description_get(const Sequence *transformed,
+ const Sequence *target)
+{
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(transformed) >= SEQ_time_right_handle_frame_get(target)) {
+ return STRIP_OVERLAP_IS_FULL;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) > SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(transformed) < SEQ_time_right_handle_frame_get(target)) {
+ return STRIP_OVERLAP_IS_INSIDE;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_left_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
+ return STRIP_OVERLAP_LEFT_SIDE;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_right_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
+ return STRIP_OVERLAP_RIGHT_SIDE;
+ }
+ return STRIP_OVERLAP_NONE;
+}
+
+/* Split strip in 3 parts, remove middle part and fit transformed inside. */
+static void seq_transform_handle_overwrite_split(Scene *scene,
+ ListBase *seqbasep,
+ const Sequence *transformed,
+ Sequence *target)
+{
+ /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass
+ * NULL here. */
+ Main *bmain = NULL;
+
+ Sequence *split_strip = SEQ_edit_strip_split(bmain,
+ scene,
+ seqbasep,
+ target,
+ SEQ_time_left_handle_frame_get(transformed),
+ SEQ_SPLIT_SOFT,
+ NULL);
+ SEQ_edit_strip_split(bmain,
+ scene,
+ seqbasep,
+ split_strip,
+ SEQ_time_right_handle_frame_get(transformed),
+ SEQ_SPLIT_SOFT,
+ NULL);
+ SEQ_edit_flag_for_removal(scene, seqbasep, split_strip);
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+}
+
+/* Trim strips by adjusting handle position.
+ * This is bit more complicated in case overlap happens on effect. */
+static void seq_transform_handle_overwrite_trim(Scene *scene,
+ ListBase *seqbasep,
+ const Sequence *transformed,
+ Sequence *target,
+ const eOvelapDescrition overlap)
+{
+ SeqCollection *targets = SEQ_query_by_reference(target, seqbasep, SEQ_query_strip_effect_chain);
+
+ /* Expand collection by adding all target's children, effects and their children. */
+ if ((target->type & SEQ_TYPE_EFFECT) != 0) {
+ SEQ_collection_expand(seqbasep, targets, SEQ_query_strip_effect_chain);
+ }
+
+ /* Trim all non effects, that have influence on effect length which is overlapping. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, targets) {
+ if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) {
+ continue;
+ }
+ if (overlap == STRIP_OVERLAP_LEFT_SIDE) {
+ SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(transformed));
+ }
+ else {
+ BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE);
+ SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(transformed));
+ }
+ }
+ SEQ_collection_free(targets);
+}
+
+static void seq_transform_handle_overwrite(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips)
+{
+ SeqCollection *targets = query_overwrite_targets(seqbasep, transformed_strips);
+ SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
+
+ Sequence *target;
+ Sequence *transformed;
+ SEQ_ITERATOR_FOREACH (target, targets) {
+ SEQ_ITERATOR_FOREACH (transformed, transformed_strips) {
+ if (transformed->machine != target->machine) {
+ continue;
+ }
+
+ const eOvelapDescrition overlap = overlap_description_get(transformed, target);
+
+ if (overlap == STRIP_OVERLAP_IS_FULL) {
+ SEQ_collection_append_strip(target, strips_to_delete);
+ }
+ else if (overlap == STRIP_OVERLAP_IS_INSIDE) {
+ seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target);
+ }
+ else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) {
+ seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap);
+ }
+ }
+ }
+
+ SEQ_collection_free(targets);
+
+ /* Remove covered strips. This must be done in separate loop, because `SEQ_edit_strip_split()`
+ * also uses `SEQ_edit_remove_flagged_sequences()`. See T91096. */
+ if (SEQ_collection_len(strips_to_delete) > 0) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips_to_delete) {
+ SEQ_edit_flag_for_removal(scene, seqbasep, seq);
+ }
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+ }
+ SEQ_collection_free(strips_to_delete);
+}
+
+static void seq_transform_handle_overlap_shuffle(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ ListBase *markers = &scene->markers;
+
+ /* Shuffle non strips with no effects attached. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
+}
+
+void SEQ_transform_handle_overlap(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene);
+
+ switch (overlap_mode) {
+ case SEQ_OVERLAP_EXPAND:
+ seq_transform_handle_expand_to_fit(
+ scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
+ break;
+ case SEQ_OVERLAP_OVERWRITE:
+ seq_transform_handle_overwrite(scene, seqbasep, transformed_strips);
+ break;
+ case SEQ_OVERLAP_SHUFFLE:
+ seq_transform_handle_overlap_shuffle(
+ scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
+ break;
+ }
+
+ /* If any effects still overlap, we need to move them up.
+ * In some cases other strips can be overlapping still, see T90646. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if (SEQ_transform_test_overlap(seqbasep, seq)) {
+ SEQ_transform_seqbase_shuffle(seqbasep, seq, scene);
+ }
+ seq->flag &= ~SEQ_OVERLAP;
+ }
+}
+
void SEQ_transform_offset_after_frame(Scene *scene,
ListBase *seqbase,
const int delta,
diff --git a/source/blender/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/WM_api.h b/source/blender/windowmanager/WM_api.h
index 9942d62be52..e60d812e5b6 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -738,6 +738,7 @@ void WM_operator_last_properties_ensure(struct wmOperatorType *ot, struct Pointe
wmOperator *WM_operator_last_redo(const struct bContext *C);
/**
* Use for drag & drop a path or name with operators invoke() function.
+ * Returns null if no operator property is set to identify the file or ID to use.
*/
ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, short idcode);
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index c2a63c9db7a..63a7fb5ddaa 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -1153,9 +1153,17 @@ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win)
if (wm_software_cursor_needed()) {
struct GrabState grab_state;
- if (wm_software_cursor_needed_for_window(win, &grab_state) &&
- wm_software_cursor_motion_test(win)) {
- return true;
+ if (wm_software_cursor_needed_for_window(win, &grab_state)) {
+ if (wm_software_cursor_motion_test(win)) {
+ return true;
+ }
+ }
+ else {
+ /* Detect the edge case when the previous draw used the software cursor but this one doesn't,
+ * it's important to redraw otherwise the software cursor will remain displayed. */
+ if (g_software_cursor.winid != -1) {
+ return true;
+ }
}
}
diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc
index 7420e756b31..d3ae4177e4d 100644
--- a/source/blender/windowmanager/intern/wm_event_system.cc
+++ b/source/blender/windowmanager/intern/wm_event_system.cc
@@ -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;
@@ -903,7 +903,7 @@ bool WM_operator_check_ui_empty(wmOperatorType *ot)
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;
}
@@ -1180,7 +1180,7 @@ bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
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);
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
if (otm && otm->exec == nullptr) {
return false;
}
@@ -1260,7 +1260,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
/* 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, nullptr);
@@ -1276,7 +1276,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
}
else {
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, nullptr);
BLI_addtail(&motherop->macro, opm);
@@ -1289,7 +1289,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
}
}
- WM_operator_properties_sanitize(op->ptr, 0);
+ WM_operator_properties_sanitize(op->ptr, false);
return op;
}
@@ -1649,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);
}
@@ -1659,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;
}
@@ -1827,7 +1827,7 @@ 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);
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
if (otm != nullptr) {
flag |= otm->flag;
}
@@ -2396,11 +2396,11 @@ 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 = nullptr;
if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
@@ -2770,7 +2770,7 @@ static const char *keymap_handler_log_kmi_op_str(bContext *C,
/* The key-map item properties can further help distinguish this item from others. */
char *kmi_props = nullptr;
if (kmi->properties != nullptr) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
if (ot) {
kmi_props = RNA_pointer_as_string_keywords(C, kmi->ptr, false, false, true, 512);
}
@@ -3031,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;
@@ -3179,7 +3179,7 @@ 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;
@@ -4604,7 +4604,7 @@ wmOperator *WM_operator_find_modal_by_type(wmWindow *win, const wmOperatorType *
return handler->op;
}
}
- return NULL;
+ return nullptr;
}
#if 0
@@ -4942,7 +4942,11 @@ 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 nullptr;
@@ -4951,8 +4955,9 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi
/* 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). */
@@ -4962,9 +4967,9 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi
}
}
- 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;
}
}
@@ -5632,7 +5637,7 @@ 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;
}
@@ -5882,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);
}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 330231f3f18..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);
}
}
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index 531da3cf2e8..0817b10f86e 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -270,7 +270,10 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
break;
}
}
- else if (STRPREFIX(opname, "CURVES_SCULPT_OT")) {
+ else if (STRPREFIX(opname, "CURVES_OT")) {
+ km = WM_keymap_find_all(wm, "Curves", 0, 0);
+ }
+ else if (STRPREFIX(opname, "SCULPT_CURVES_OT")) {
km = WM_keymap_find_all(wm, "Sculpt Curves", 0, 0);
}
else if (STRPREFIX(opname, "MBALL_OT")) {
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 7b768bd8c70..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;
}
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 7cd54a7e191..3100e6e4fd3 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);
@@ -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);
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 7b5de5b53b8..104eda220cc 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/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>