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:
authorLukas Tönne <lukas.toenne@gmail.com>2021-07-24 17:32:28 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2021-07-24 17:32:28 +0300
commit9bff211ac9e38de090ac2cddd2bbe9636443af6f (patch)
treecfea5324a6b776729b5520ea007bfb9200e30eec
parent23209dc8f9aedf90ddf4cc53d7170d38ddaeb5d7 (diff)
parent05c7d935e77025b87c5593dcbae38de42ed5a3ce (diff)
Merge branch 'master' into node-group-single-socket-nodes
-rwxr-xr-xbuild_files/cmake/cmake_netbeans_project.py2
-rwxr-xr-xdoc/manpage/blender.1.py2
-rw-r--r--doc/python_api/sphinx_doc_gen.py2
-rw-r--r--extern/rangetree/intern/generic_alloc_impl.h2
-rw-r--r--intern/cycles/blender/addon/ui.py13
-rw-r--r--intern/cycles/render/osl.cpp2
-rw-r--r--intern/ghost/GHOST_C-api.h2
-rw-r--r--intern/ghost/GHOST_IWindow.h2
-rw-r--r--intern/ghost/GHOST_Types.h4
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm17
-rw-r--r--intern/ghost/intern/GHOST_ContextEGL.cpp22
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.cpp5
-rw-r--r--intern/ghost/intern/GHOST_DisplayManager.cpp10
-rw-r--r--intern/ghost/intern/GHOST_DropTargetX11.cpp6
-rw-r--r--intern/ghost/intern/GHOST_EventDragnDrop.h2
-rw-r--r--intern/ghost/intern/GHOST_EventManager.cpp8
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp126
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.h95
-rw-r--r--intern/ghost/intern/GHOST_Rect.cpp12
-rw-r--r--intern/ghost/intern/GHOST_System.cpp16
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp31
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h4
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp20
-rw-r--r--intern/ghost/intern/GHOST_TimerManager.cpp10
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h12
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.cpp2
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp6
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_XrSession.cpp49
-rw-r--r--intern/ghost/intern/GHOST_XrSession.h1
-rw-r--r--intern/libmv/CMakeLists.txt64
-rw-r--r--intern/memutil/MEM_Allocator.h4
-rw-r--r--intern/opensubdiv/CMakeLists.txt2
-rw-r--r--intern/rigidbody/RBI_api.h2
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/userdef/userdef_default.c2
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_cli.py2
-rw-r--r--release/scripts/modules/nodeitems_utils.py2
-rw-r--r--release/scripts/modules/rna_manual_reference.py45
-rw-r--r--release/scripts/startup/bl_operators/assets.py1
-rw-r--r--release/scripts/startup/bl_operators/geometry_nodes.py5
-rw-r--r--release/scripts/startup/bl_operators/rigidbody.py21
-rw-r--r--release/scripts/startup/bl_operators/sequencer.py13
-rw-r--r--release/scripts/startup/bl_ui/properties_collection.py11
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py16
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py27
-rw-r--r--release/scripts/startup/nodeitems_builtins.py2
-rw-r--r--release/scripts/templates_py/custom_nodes.py2
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h2
-rw-r--r--source/blender/blenkernel/BKE_action.hh35
-rw-r--r--source/blender/blenkernel/BKE_armature.hh48
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_cloth.h28
-rw-r--r--source/blender/blenkernel/BKE_curve.h1
-rw-r--r--source/blender/blenkernel/BKE_customdata.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h31
-rw-r--r--source/blender/blenkernel/BKE_mesh_iterators.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh_types.h1
-rw-r--r--source/blender/blenkernel/BKE_node.h2
-rw-r--r--source/blender/blenkernel/BKE_object.h4
-rw-r--r--source/blender/blenkernel/BKE_spline.hh4
-rw-r--r--source/blender/blenkernel/CMakeLists.txt6
-rw-r--r--source/blender/blenkernel/intern/action_bones.cc48
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c8
-rw-r--r--source/blender/blenkernel/intern/armature_deform.c8
-rw-r--r--source/blender/blenkernel/intern/armature_pose.cc58
-rw-r--r--source/blender/blenkernel/intern/armature_selection.cc78
-rw-r--r--source/blender/blenkernel/intern/armature_test.cc81
-rw-r--r--source/blender/blenkernel/intern/attribute.c74
-rw-r--r--source/blender/blenkernel/intern/boids.c79
-rw-r--r--source/blender/blenkernel/intern/curve.c22
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc16
-rw-r--r--source/blender/blenkernel/intern/editmesh.c2
-rw-r--r--source/blender/blenkernel/intern/effect.c2
-rw-r--r--source/blender/blenkernel/intern/fcurve.c2
-rw-r--r--source/blender/blenkernel/intern/fluid.c2
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc10
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc5
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc (renamed from source/blender/blenkernel/intern/gpencil_geom.c)495
-rw-r--r--source/blender/blenkernel/intern/icons.cc2
-rw-r--r--source/blender/blenkernel/intern/image_save.c4
-rw-r--r--source/blender/blenkernel/intern/layer.c2
-rw-r--r--source/blender/blenkernel/intern/main_idmap.c4
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c124
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c9
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c4
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc30
-rw-r--r--source/blender/blenkernel/intern/node.cc10
-rw-r--r--source/blender/blenkernel/intern/object.c2
-rw-r--r--source/blender/blenkernel/intern/object_update.c21
-rw-r--r--source/blender/blenkernel/intern/paint.c2
-rw-r--r--source/blender/blenkernel/intern/particle.c4
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c10
-rw-r--r--source/blender/blenkernel/intern/scene.c6
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc2
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c2
-rw-r--r--source/blender/blenkernel/intern/unit.c2
-rw-r--r--source/blender/blenkernel/intern/workspace.c2
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c7
-rw-r--r--source/blender/blenlib/BLI_array.h2
-rw-r--r--source/blender/blenlib/BLI_color.hh4
-rw-r--r--source/blender/blenlib/BLI_compiler_typecheck.h2
-rw-r--r--source/blender/blenlib/BLI_delaunay_2d.h8
-rw-r--r--source/blender/blenlib/BLI_dlrbTree.h15
-rw-r--r--source/blender/blenlib/BLI_float4x4.hh8
-rw-r--r--source/blender/blenlib/BLI_ghash.h6
-rw-r--r--source/blender/blenlib/BLI_link_utils.h2
-rw-r--r--source/blender/blenlib/BLI_linklist_stack.h2
-rw-r--r--source/blender/blenlib/BLI_math.h40
-rw-r--r--source/blender/blenlib/intern/BLI_dynstr.c2
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c2
-rw-r--r--source/blender/blenlib/intern/BLI_ghash_utils.c4
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c4
-rw-r--r--source/blender/blenlib/intern/BLI_memiter.c2
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c4
-rw-r--r--source/blender/blenlib/intern/BLI_mmap.c6
-rw-r--r--source/blender/blenlib/intern/DLRB_tree.c10
-rw-r--r--source/blender/blenlib/intern/array_store.c6
-rw-r--r--source/blender/blenlib/intern/convexhull_2d.c2
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.cc370
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c6
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c6
-rw-r--r--source/blender/blenlib/intern/math_geom.c10
-rw-r--r--source/blender/blenlib/intern/math_geom_inline.c8
-rw-r--r--source/blender/blenlib/intern/math_interp.c2
-rw-r--r--source/blender/blenlib/intern/math_matrix.c6
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c2
-rw-r--r--source/blender/blenlib/intern/memory_utils.c2
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc6
-rw-r--r--source/blender/blenlib/intern/mesh_intersect.cc65
-rw-r--r--source/blender/blenlib/intern/noise.c37
-rw-r--r--source/blender/blenlib/intern/polyfill_2d.c6
-rw-r--r--source/blender/blenlib/intern/smallhash.c6
-rw-r--r--source/blender/blenlib/intern/string.c4
-rw-r--r--source/blender/blenlib/intern/string_utils.c6
-rw-r--r--source/blender/blenlib/intern/task_pool.cc2
-rw-r--r--source/blender/blenlib/intern/timecode.c6
-rw-r--r--source/blender/blenlib/intern/winstuff.c2
-rw-r--r--source/blender/blenlib/tests/BLI_delaunay_2d_test.cc181
-rw-r--r--source/blender/blenlib/tests/BLI_mesh_intersect_test.cc10
-rw-r--r--source/blender/blenloader/intern/readfile.c2
-rw-r--r--source/blender/blenloader/intern/versioning_250.c46
-rw-r--r--source/blender/blenloader/intern/versioning_260.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.c153
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c5
-rw-r--r--source/blender/blenloader/intern/writefile.c2
-rw-r--r--source/blender/bmesh/bmesh.h22
-rw-r--r--source/blender/bmesh/bmesh_class.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.c1244
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c2
-rw-r--r--source/blender/compositor/CMakeLists.txt3
-rw-r--r--source/blender/compositor/COM_defines.h24
-rw-r--r--source/blender/compositor/intern/COM_BufferArea.h215
-rw-r--r--source/blender/compositor/intern/COM_BufferRange.h171
-rw-r--r--source/blender/compositor/intern/COM_BuffersIterator.h195
-rw-r--r--source/blender/compositor/intern/COM_ConstantFolder.cc8
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc45
-rw-r--r--source/blender/compositor/intern/COM_Debug.h17
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.cc18
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cc14
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h29
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.cc2
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.cc45
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc1086
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h12
-rw-r--r--source/blender/compositor/operations/COM_EllipseMaskOperation.cc73
-rw-r--r--source/blender/compositor/operations/COM_EllipseMaskOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc43
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.cc555
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.h89
-rw-r--r--source/blender/compositor/operations/COM_MovieClipOperation.cc24
-rw-r--r--source/blender/compositor/operations/COM_MovieClipOperation.h12
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.cc10
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cc73
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.h12
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cc45
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.h14
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc102
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc68
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc9
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc23
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc10
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.h10
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c2
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl2
-rw-r--r--source/blender/draw/engines/overlay/overlay_outline.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c2
-rw-r--r--source/blender/draw/intern/DRW_render.h2
-rw-r--r--source/blender/draw/intern/draw_cache.c4
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h13
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc37
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_private.h20
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.c248
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.cc2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c15
-rw-r--r--source/blender/draw/intern/draw_instance_data.c2
-rw-r--r--source/blender/draw/intern/draw_manager.c4
-rw-r--r--source/blender/draw/intern/draw_manager_data.c4
-rw-r--r--source/blender/draw/intern/draw_manager_text.c2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc109
-rw-r--r--source/blender/editors/animation/CMakeLists.txt1
-rw-r--r--source/blender/editors/animation/anim_draw.c1
-rw-r--r--source/blender/editors/animation/anim_markers.c2
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c2
-rw-r--r--source/blender/editors/animation/keyframes_draw.c758
-rw-r--r--source/blender/editors/animation/keyframes_keylist.c793
-rw-r--r--source/blender/editors/armature/CMakeLists.txt2
-rw-r--r--source/blender/editors/armature/pose_backup.cc (renamed from source/blender/editors/armature/pose_backup.c)70
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_lib_2.c6
-rw-r--r--source/blender/editors/armature/pose_slide.c530
-rw-r--r--source/blender/editors/asset/CMakeLists.txt20
-rw-r--r--source/blender/editors/asset/ED_asset_handle.h45
-rw-r--r--source/blender/editors/asset/ED_asset_library.h35
-rw-r--r--source/blender/editors/asset/ED_asset_list.h54
-rw-r--r--source/blender/editors/asset/ED_asset_list.hh38
-rw-r--r--source/blender/editors/asset/ED_asset_mark_clear.h37
-rw-r--r--source/blender/editors/asset/ED_asset_temp_id_consumer.h48
-rw-r--r--source/blender/editors/asset/asset_edit.cc155
-rw-r--r--source/blender/editors/asset/intern/asset_handle.cc75
-rw-r--r--source/blender/editors/asset/intern/asset_library_reference.cc50
-rw-r--r--source/blender/editors/asset/intern/asset_library_reference.hh46
-rw-r--r--source/blender/editors/asset/intern/asset_library_reference_enum.cc156
-rw-r--r--source/blender/editors/asset/intern/asset_list.cc (renamed from source/blender/editors/asset/asset_list.cc)74
-rw-r--r--source/blender/editors/asset/intern/asset_mark_clear.cc83
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc (renamed from source/blender/editors/asset/asset_ops.cc)0
-rw-r--r--source/blender/editors/asset/intern/asset_temp_id_consumer.cc (renamed from source/blender/editors/asset/asset_temp_id_consumer.cc)7
-rw-r--r--source/blender/editors/geometry/geometry_attributes.c17
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c3
-rw-r--r--source/blender/editors/include/ED_asset.h77
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h149
-rw-r--r--source/blender/editors/include/ED_keyframes_keylist.h192
-rw-r--r--source/blender/editors/include/ED_render.h5
-rw-r--r--source/blender/editors/include/ED_util.h19
-rw-r--r--source/blender/editors/include/UI_interface.h5
-rw-r--r--source/blender/editors/interface/interface.c11
-rw-r--r--source/blender/editors/interface/interface_context_menu.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c8
-rw-r--r--source/blender/editors/interface/interface_icons.c1
-rw-r--r--source/blender/editors/interface/interface_ops.c2
-rw-r--r--source/blender/editors/interface/interface_template_asset_view.cc21
-rw-r--r--source/blender/editors/interface/interface_template_list.cc10
-rw-r--r--source/blender/editors/interface/view2d.c2
-rw-r--r--source/blender/editors/mask/mask_add.c6
-rw-r--r--source/blender/editors/mesh/mesh_data.c65
-rw-r--r--source/blender/editors/mesh/mesh_ops.c8
-rw-r--r--source/blender/editors/object/object_data_transfer.c87
-rw-r--r--source/blender/editors/object/object_facemap_ops.c17
-rw-r--r--source/blender/editors/object/object_vgroup.c6
-rw-r--r--source/blender/editors/physics/particle_edit.c4
-rw-r--r--source/blender/editors/render/render_preview.c98
-rw-r--r--source/blender/editors/render/render_shading.c9
-rw-r--r--source/blender/editors/render/render_update.c2
-rw-r--r--source/blender/editors/screen/screen_context.c2
-rw-r--r--source/blender/editors/screen/screen_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c2
-rw-r--r--source/blender/editors/space_action/action_select.c2
-rw-r--r--source/blender/editors/space_file/file_draw.c6
-rw-r--r--source/blender/editors/space_file/file_ops.c4
-rw-r--r--source/blender/editors/space_file/filelist.c8
-rw-r--r--source/blender/editors/space_file/filelist.h4
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_file/space_file.c7
-rw-r--r--source/blender/editors/space_graph/graph_edit.c8
-rw-r--r--source/blender/editors/space_graph/graph_view.c2
-rw-r--r--source/blender/editors/space_image/image_buttons.c2
-rw-r--r--source/blender/editors/space_nla/nla_draw.c1
-rw-r--r--source/blender/editors/space_node/node_edit.cc16
-rw-r--r--source/blender/editors/space_node/node_relationships.cc2
-rw-r--r--source/blender/editors/space_node/node_select.cc2
-rw-r--r--source/blender/editors/space_node/node_templates.cc5
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c11
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_context.cc2
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c4
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c28
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c8
-rw-r--r--source/blender/editors/transform/transform_generics.c4
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c3
-rw-r--r--source/blender/editors/transform/transform_orientations.c4
-rw-r--r--source/blender/editors/transform/transform_snap_object.c122
-rw-r--r--source/blender/editors/util/ed_draw.c460
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c8
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp2
-rw-r--r--source/blender/freestyle/intern/geometry/FastGrid.cpp4
-rw-r--r--source/blender/freestyle/intern/view_map/Interface0D.h4
-rw-r--r--source/blender/freestyle/intern/view_map/Silhouette.h6
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMap.h12
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.cpp22
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c51
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c9
-rw-r--r--source/blender/gpu/GPU_vertex_format.h2
-rw-r--r--source/blender/gpu/intern/gpu_batch.cc4
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c2
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc10
-rw-r--r--source/blender/gpu/intern/gpu_texture_private.hh10
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.cc2
-rw-r--r--source/blender/gpu/opengl/gl_texture.hh8
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.cc2
-rw-r--r--source/blender/imbuf/intern/iris.c2
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp2
-rw-r--r--source/blender/imbuf/intern/scaling.c496
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_mesh.cc2
-rw-r--r--source/blender/io/collada/AnimationImporter.cpp2
-rw-r--r--source/blender/io/collada/BCAnimationSampler.cpp10
-rw-r--r--source/blender/io/collada/ControllerExporter.cpp2
-rw-r--r--source/blender/io/collada/DocumentExporter.cpp2
-rw-r--r--source/blender/io/collada/MeshImporter.cpp2
-rw-r--r--source/blender/io/collada/TransformReader.cpp8
-rw-r--r--source/blender/io/collada/collada_utils.cpp12
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc25
-rw-r--r--source/blender/makesdna/DNA_ID.h9
-rw-r--r--source/blender/makesdna/DNA_action_types.h4
-rw-r--r--source/blender/makesdna/DNA_anim_types.h24
-rw-r--r--source/blender/makesdna/DNA_asset_types.h3
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h10
-rw-r--r--source/blender/makesdna/DNA_documentation.h2
-rw-r--r--source/blender/makesdna/DNA_ipo_types.h8
-rw-r--r--source/blender/makesdna/DNA_light_types.h2
-rw-r--r--source/blender/makesdna/DNA_mask_types.h4
-rw-r--r--source/blender/makesdna/DNA_material_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_material_types.h46
-rw-r--r--source/blender/makesdna/DNA_modifier_defaults.h3
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h13
-rw-r--r--source/blender/makesdna/DNA_node_types.h29
-rw-r--r--source/blender/makesdna/DNA_object_types.h2
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h4
-rw-r--r--source/blender/makesdna/DNA_scene_types.h2
-rw-r--r--source/blender/makesdna/DNA_screen_types.h2
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h21
-rw-r--r--source/blender/makesdna/DNA_space_types.h21
-rw-r--r--source/blender/makesdna/DNA_texture_types.h3
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h6
-rw-r--r--source/blender/makesdna/DNA_view2d_types.h2
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h2
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h2
-rw-r--r--source/blender/makesdna/DNA_xr_types.h1
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c6
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h1
-rw-r--r--source/blender/makesrna/RNA_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_access.c4
-rw-r--r--source/blender/makesrna/intern/rna_asset.c92
-rw-r--r--source/blender/makesrna/intern/rna_collection.c6
-rw-r--r--source/blender/makesrna/intern/rna_context.c4
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c20
-rw-r--r--source/blender/makesrna/intern/rna_internal.h2
-rw-r--r--source/blender/makesrna/intern/rna_material.c8
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c15
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c88
-rw-r--r--source/blender/makesrna/intern/rna_object.c31
-rw-r--r--source/blender/makesrna/intern/rna_rna.c44
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c60
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c38
-rw-r--r--source/blender/makesrna/intern/rna_space.c109
-rw-r--r--source/blender/makesrna/intern/rna_volume.c2
-rw-r--r--source/blender/makesrna/intern/rna_wm.c2
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c12
-rw-r--r--source/blender/makesrna/intern/rna_xr.c88
-rw-r--r--source/blender/modifiers/intern/MOD_array.c4
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc14
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c4
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c4
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c99
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c6
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c7
-rw-r--r--source/blender/nodes/CMakeLists.txt2
-rw-r--r--source/blender/nodes/NOD_geometry.h2
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh3
-rw-r--r--source/blender/nodes/NOD_static_types.h4
-rw-r--r--source/blender/nodes/composite/node_composite_tree.c9
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_common.c5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc149
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc72
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc410
-rw-r--r--source/blender/nodes/intern/derived_node_tree.cc4
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc18
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.c6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_common.c6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_rotate.c2
-rw-r--r--source/blender/python/BPY_extern.h2
-rw-r--r--source/blender/python/generic/py_capi_utils.c2
-rw-r--r--source/blender/python/gpu/gpu_py.c4
-rw-r--r--source/blender/python/gpu/gpu_py_api.c4
-rw-r--r--source/blender/python/gpu/gpu_py_batch.c6
-rw-r--r--source/blender/python/gpu/gpu_py_buffer.c4
-rw-r--r--source/blender/python/gpu/gpu_py_capabilities.c4
-rw-r--r--source/blender/python/gpu/gpu_py_element.c4
-rw-r--r--source/blender/python/gpu/gpu_py_framebuffer.c61
-rw-r--r--source/blender/python/gpu/gpu_py_matrix.c4
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c4
-rw-r--r--source/blender/python/gpu/gpu_py_platform.c4
-rw-r--r--source/blender/python/gpu/gpu_py_select.c4
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c4
-rw-r--r--source/blender/python/gpu/gpu_py_state.c4
-rw-r--r--source/blender/python/gpu/gpu_py_texture.c4
-rw-r--r--source/blender/python/gpu/gpu_py_types.c4
-rw-r--r--source/blender/python/gpu/gpu_py_uniformbuffer.c4
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_buffer.c4
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_format.c4
-rw-r--r--source/blender/python/intern/bpy_app_ffmpeg.c2
-rw-r--r--source/blender/python/intern/bpy_operator.c2
-rw-r--r--source/blender/python/intern/bpy_rna.c15
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c2
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c13
-rw-r--r--source/blender/python/intern/bpy_utils_units.c2
-rw-r--r--source/blender/python/mathutils/mathutils.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c6
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c26
-rw-r--r--source/blender/python/mathutils/mathutils_noise.c3
-rw-r--r--source/blender/render/intern/bake.c8
-rw-r--r--source/blender/render/intern/texture_image.c4
-rw-r--r--source/blender/sequencer/SEQ_effects.h3
-rw-r--r--source/blender/sequencer/intern/effects.c92
-rw-r--r--source/blender/sequencer/intern/strip_edit.c6
-rw-r--r--source/blender/sequencer/intern/strip_time.c4
-rw-r--r--source/blender/sequencer/intern/strip_transform.c6
-rw-r--r--source/blender/shader_fx/intern/FX_ui_common.c2
-rw-r--r--source/blender/simulation/intern/SIM_mass_spring.cpp39
-rw-r--r--source/blender/simulation/intern/hair_volume.cpp35
-rw-r--r--source/blender/simulation/intern/implicit_blender.c24
-rw-r--r--source/blender/simulation/intern/implicit_eigen.cpp6
-rw-r--r--source/blender/windowmanager/WM_types.h4
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c2
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c20
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c1
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c8
-rw-r--r--source/blender/windowmanager/intern/wm_files.c2
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c4
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c17
-rw-r--r--source/blender/windowmanager/wm_surface.h4
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_draw.c20
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h8
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c90
m---------source/tools0
-rw-r--r--tests/performance/api/config.py23
-rw-r--r--tests/performance/api/environment.py99
-rw-r--r--tests/performance/api/graph.py3
-rwxr-xr-xtests/performance/benchmark29
467 files changed, 10366 insertions, 5567 deletions
diff --git a/build_files/cmake/cmake_netbeans_project.py b/build_files/cmake/cmake_netbeans_project.py
index cfc3ff6b6fa..a16fc42c9b7 100755
--- a/build_files/cmake/cmake_netbeans_project.py
+++ b/build_files/cmake/cmake_netbeans_project.py
@@ -82,7 +82,7 @@ def create_nb_project_main():
make_exe = cmake_cache_var("CMAKE_MAKE_PROGRAM")
make_exe_basename = os.path.basename(make_exe)
- # --------------- NB specific
+ # --------------- NetBeans specific.
defines = [("%s=%s" % cdef) if cdef[1] else cdef[0] for cdef in defines]
defines += [cdef.replace("#define", "").strip() for cdef in cmake_compiler_defines()]
diff --git a/doc/manpage/blender.1.py b/doc/manpage/blender.1.py
index 950a2119f91..020bab05a21 100755
--- a/doc/manpage/blender.1.py
+++ b/doc/manpage/blender.1.py
@@ -122,7 +122,7 @@ is a full-featured 3D application. It supports the entirety of the 3D pipeline -
'''modeling, rigging, animation, simulation, rendering, compositing, motion tracking, and video editing.
Use Blender to create 3D images and animations, films and commercials, content for games, '''
-r'''architectural and industrial visualizatons, and scientific visualizations.
+r'''architectural and industrial visualizations, and scientific visualizations.
https://www.blender.org''')
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 4be27e0f0e8..d6c1d7b51b8 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -1047,6 +1047,7 @@ context_type_map = {
"annotation_data": ("GreasePencil", False),
"annotation_data_owner": ("ID", False),
"armature": ("Armature", False),
+ "asset_library": ("AssetLibraryReference", False),
"bone": ("Bone", False),
"brush": ("Brush", False),
"camera": ("Camera", False),
@@ -1113,6 +1114,7 @@ context_type_map = {
"texture_slot": ("MaterialTextureSlot", False),
"texture_user": ("ID", False),
"texture_user_property": ("Property", False),
+ "ui_list": ("UIList", False),
"vertex_paint_object": ("Object", False),
"view_layer": ("ViewLayer", False),
"visible_bones": ("EditBone", True),
diff --git a/extern/rangetree/intern/generic_alloc_impl.h b/extern/rangetree/intern/generic_alloc_impl.h
index 0f9f5184637..fd6e85a155a 100644
--- a/extern/rangetree/intern/generic_alloc_impl.h
+++ b/extern/rangetree/intern/generic_alloc_impl.h
@@ -32,7 +32,7 @@
* - #TPOOL_STRUCT: Name for pool struct name.
* - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined.
*
- * \note #TPOOL_ALLOC_TYPE must be at least ``sizeof(void *)``.
+ * \note #TPOOL_ALLOC_TYPE must be at least `sizeof(void *)`.
*
* Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function.
*
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 30892cdbbc0..058528aeff5 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -1136,7 +1136,7 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel):
col = row.column(align=True)
col.operator("object.material_slot_add", icon='ADD', text="")
col.operator("object.material_slot_remove", icon='REMOVE', text="")
-
+ col.separator()
col.menu("MATERIAL_MT_context_menu", icon='DOWNARROW_HLT', text="")
if is_sortable:
@@ -1151,16 +1151,15 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel):
row.operator("object.material_slot_select", text="Select")
row.operator("object.material_slot_deselect", text="Deselect")
- split = layout.split(factor=0.65)
+ row = layout.row()
if ob:
- split.template_ID(ob, "active_material", new="material.new")
- row = split.row()
+ row.template_ID(ob, "active_material", new="material.new")
if slot:
- row.prop(slot, "link", text="")
- else:
- row.label()
+ icon_link = 'MESH_DATA' if slot.link == 'DATA' else 'OBJECT_DATA'
+ row.prop(slot, "link", text="", icon=icon_link, icon_only=True)
+
elif mat:
split.template_ID(space, "pin_id")
split.separator()
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 9bd6e3a5e2d..7dc79f48145 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -993,7 +993,7 @@ void OSLCompiler::parameter_array(const char *name, const float f[], int arrayle
void OSLCompiler::parameter_color_array(const char *name, const array<float3> &f)
{
- /* NB: cycles float3 type is actually 4 floats! need to use an explicit array */
+ /* NOTE: cycles float3 type is actually 4 floats! need to use an explicit array. */
array<float[3]> table(f.size());
for (int i = 0; i < f.size(); ++i) {
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index db3f9bd561e..3dec4f4a7d1 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -628,7 +628,7 @@ extern void GHOST_ScreenToClient(
GHOST_WindowHandle windowhandle, int32_t inX, int32_t inY, int32_t *outX, int32_t *outY);
/**
- * Converts a point in screen coordinates to client rectangle coordinates
+ * Converts a point in client rectangle coordinates to screen coordinates.
* \param windowhandle: The handle to the window.
* \param inX: The x-coordinate in the client rectangle.
* \param inY: The y-coordinate in the client rectangle.
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index f870791b345..5f9bd808c8c 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -133,7 +133,7 @@ class GHOST_IWindow {
virtual void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const = 0;
/**
- * Converts a point in screen coordinates to client rectangle coordinates
+ * Converts a point in client rectangle coordinates to screen coordinates.
* \param inX: The x-coordinate in the client rectangle.
* \param inY: The y-coordinate in the client rectangle.
* \param outX: The x-coordinate on the screen.
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index ff93de4f203..ddebfa7e816 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -683,6 +683,10 @@ typedef struct GHOST_XrDrawViewInfo {
/** Set if the buffer should be submitted with a SRGB transfer applied. */
char expects_srgb_buffer;
+
+ /** The view that this info represents. Not necessarily the "eye index" (e.g. for quad view
+ * systems, etc). */
+ char view_idx;
} GHOST_XrDrawViewInfo;
typedef struct GHOST_XrError {
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index 687173ded09..7af243846c2 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -217,7 +217,7 @@ static void makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs,
attribs.push_back(NSOpenGLPFAOpenGLProfile);
attribs.push_back(coreProfile ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy);
- // Pixel Format Attributes for the windowed NSOpenGLContext
+ /* Pixel Format Attributes for the windowed NSOpenGLContext. */
attribs.push_back(NSOpenGLPFADoubleBuffer);
if (softwareGL) {
@@ -250,7 +250,8 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
static const bool needAlpha = false;
#endif
- static bool softwareGL = getenv("BLENDER_SOFTWAREGL"); // command-line argument would be better
+ /* Command-line argument would be better. */
+ static bool softwareGL = getenv("BLENDER_SOFTWAREGL");
std::vector<NSOpenGLPixelFormatAttribute> attribs;
attribs.reserve(40);
@@ -287,7 +288,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
if (m_metalView) {
if (m_defaultFramebuffer == 0) {
- // Create a virtual framebuffer
+ /* Create a virtual frame-buffer. */
[m_openGLContext makeCurrentContext];
metalInitFramebuffer();
initClearGL();
@@ -342,11 +343,11 @@ void GHOST_ContextCGL::metalInit()
/* clang-format on */
id<MTLDevice> device = m_metalLayer.device;
- // Create a command queue for blit/present operation
+ /* Create a command queue for blit/present operation. */
m_metalCmdQueue = (MTLCommandQueue *)[device newCommandQueue];
[m_metalCmdQueue retain];
- // Create shaders for blit operation
+ /* Create shaders for blit operation. */
NSString *source = @R"msl(
using namespace metal;
@@ -387,7 +388,7 @@ void GHOST_ContextCGL::metalInit()
"GHOST_ContextCGL::metalInit: newLibraryWithSource:options:error: failed!");
}
- // Create a render pipeline for blit operation
+ /* Create a render pipeline for blit operation. */
MTLRenderPipelineDescriptor *desc = [[[MTLRenderPipelineDescriptor alloc] init] autorelease];
desc.fragmentFunction = [library newFunctionWithName:@"fragment_shader"];
@@ -460,7 +461,7 @@ void GHOST_ContextCGL::metalUpdateFramebuffer()
"GHOST_ContextCGL::metalUpdateFramebuffer: CVPixelBufferCreate failed!");
}
- // Create an OpenGL texture
+ /* Create an OpenGL texture. */
CVOpenGLTextureCacheRef cvGLTexCache = nil;
cvret = CVOpenGLTextureCacheCreate(kCFAllocatorDefault,
nil,
@@ -485,7 +486,7 @@ void GHOST_ContextCGL::metalUpdateFramebuffer()
unsigned int glTex;
glTex = CVOpenGLTextureGetName(cvGLTex);
- // Create a Metal texture
+ /* Create a Metal texture. */
CVMetalTextureCacheRef cvMetalTexCache = nil;
cvret = CVMetalTextureCacheCreate(
kCFAllocatorDefault, nil, m_metalLayer.device, nil, &cvMetalTexCache);
diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp
index 0fee200ea1a..a64b2aef6a5 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextEGL.cpp
@@ -283,8 +283,8 @@ GHOST_TSuccess GHOST_ContextEGL::setSwapInterval(int interval)
GHOST_TSuccess GHOST_ContextEGL::getSwapInterval(int &intervalOut)
{
- // This is a bit of a kludge because there does not seem to
- // be a way to query the swap interval with EGL.
+ /* This is a bit of a kludge because there does not seem to
+ * be a way to query the swap interval with EGL. */
intervalOut = m_swap_interval;
return GHOST_kSuccess;
@@ -365,21 +365,21 @@ static const std::string &api_string(EGLenum api)
GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
{
- // objects have to be declared here due to the use of goto
+ /* Objects have to be declared here due to the use of `goto`. */
std::vector<EGLint> attrib_list;
EGLint num_config = 0;
if (m_stereoVisual)
fprintf(stderr, "Warning! Stereo OpenGL ES contexts are not supported.\n");
- m_stereoVisual = false; // It doesn't matter what the Window wants.
+ m_stereoVisual = false; /* It doesn't matter what the Window wants. */
if (!initContextEGLEW()) {
return GHOST_kFailure;
}
#ifdef WITH_GL_ANGLE
- // d3dcompiler_XX.dll needs to be loaded before ANGLE will work
+ /* `d3dcompiler_XX.dll` needs to be loaded before ANGLE will work. */
if (s_d3dcompiler == NULL) {
s_d3dcompiler = LoadLibrary(D3DCOMPILER);
@@ -410,13 +410,13 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
if (!bindAPI(m_api))
goto error;
- // build attribute list
+ /* Build attribute list. */
attrib_list.reserve(20);
if (m_api == EGL_OPENGL_ES_API && EGLEW_VERSION_1_2) {
- // According to the spec it seems that you are required to set EGL_RENDERABLE_TYPE,
- // but some implementations (ANGLE) do not seem to care.
+ /* According to the spec it seems that you are required to set EGL_RENDERABLE_TYPE,
+ * but some implementations (ANGLE) do not seem to care. */
if (m_contextMajorVersion == 1) {
attrib_list.push_back(EGL_RENDERABLE_TYPE);
@@ -469,7 +469,7 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
#endif
if (m_nativeWindow == 0) {
- // off-screen surface
+ /* Off-screen surface. */
attrib_list.push_back(EGL_SURFACE_TYPE);
attrib_list.push_back(EGL_PBUFFER_BIT);
}
@@ -479,8 +479,8 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &m_config, 1, &num_config)))
goto error;
- // A common error is to assume that ChooseConfig worked because it returned EGL_TRUE
- if (num_config != 1) // num_config should be exactly 1
+ /* A common error is to assume that ChooseConfig worked because it returned EGL_TRUE. */
+ if (num_config != 1) /* `num_config` should be exactly 1. */
goto error;
if (m_nativeWindow != 0) {
diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp
index ddb34a8afd9..b5b3fab838d 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextWGL.cpp
@@ -335,10 +335,11 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
if (!WIN32_CHK(::wglMakeCurrent(dummyHDC, dummyHGLRC)))
goto finalize;
- if (GLEW_CHK(glewInit()) != GLEW_OK)
+ if (GLEW_CHK(glewInit()) != GLEW_OK) {
fprintf(stderr, "Warning! Dummy GLEW/WGLEW failed to initialize properly.\n");
+ }
- // the following are not technially WGLEW, but they also require a context to work
+ /* The following are not technically WGLEW, but they also require a context to work. */
#ifndef NDEBUG
free((void *)m_dummyRenderer);
diff --git a/intern/ghost/intern/GHOST_DisplayManager.cpp b/intern/ghost/intern/GHOST_DisplayManager.cpp
index fe12a76753d..9abc652378a 100644
--- a/intern/ghost/intern/GHOST_DisplayManager.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManager.cpp
@@ -51,7 +51,7 @@ GHOST_TSuccess GHOST_DisplayManager::initialize(void)
GHOST_TSuccess GHOST_DisplayManager::getNumDisplays(uint8_t & /*numDisplays*/) const
{
- // Don't know if we have a display...
+ /* Don't know if we have a display. */
return GHOST_kFailure;
}
@@ -120,18 +120,18 @@ GHOST_TSuccess GHOST_DisplayManager::findMatch(uint8_t display,
(int)setting.xPixels, (int)setting.yPixels, (int)setting.bpp, (int)setting.frequency};
int capabilities[4];
double field, score;
- double best = 1e12; // A big number
+ double best = 1e12; /* A big number. */
int found = 0;
- // Look at all the display modes
+ /* Look at all the display modes. */
for (int i = 0; (i < (int)m_settings[display].size()); i++) {
- // Store the capabilities of the display device
+ /* Store the capabilities of the display device. */
capabilities[0] = m_settings[display][i].xPixels;
capabilities[1] = m_settings[display][i].yPixels;
capabilities[2] = m_settings[display][i].bpp;
capabilities[3] = m_settings[display][i].frequency;
- // Match against all the fields of the display settings
+ /* Match against all the fields of the display settings. */
score = 0;
for (int j = 0; j < 4; j++) {
field = capabilities[j] - criteria[j];
diff --git a/intern/ghost/intern/GHOST_DropTargetX11.cpp b/intern/ghost/intern/GHOST_DropTargetX11.cpp
index 8758a27930e..dba1d305144 100644
--- a/intern/ghost/intern/GHOST_DropTargetX11.cpp
+++ b/intern/ghost/intern/GHOST_DropTargetX11.cpp
@@ -115,8 +115,10 @@ GHOST_DropTargetX11::~GHOST_DropTargetX11()
/* Based on: https://stackoverflow.com/a/2766963/432509 */
typedef enum DecodeState_e {
- STATE_SEARCH = 0, ///< searching for an ampersand to convert
- STATE_CONVERTING ///< convert the two proceeding characters from hex
+ /** 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)
diff --git a/intern/ghost/intern/GHOST_EventDragnDrop.h b/intern/ghost/intern/GHOST_EventDragnDrop.h
index 537717b1717..0095cedb8c8 100644
--- a/intern/ghost/intern/GHOST_EventDragnDrop.h
+++ b/intern/ghost/intern/GHOST_EventDragnDrop.h
@@ -90,7 +90,7 @@ class GHOST_EventDragnDrop : public GHOST_Event {
~GHOST_EventDragnDrop()
{
- // Free the dropped object data
+ /* Free the dropped object data. */
if (m_dragnDropEventData.data == NULL)
return;
diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp
index 15befb9afcb..6ddc362ac77 100644
--- a/intern/ghost/intern/GHOST_EventManager.cpp
+++ b/intern/ghost/intern/GHOST_EventManager.cpp
@@ -108,12 +108,12 @@ GHOST_TSuccess GHOST_EventManager::addConsumer(GHOST_IEventConsumer *consumer)
GHOST_TSuccess success;
GHOST_ASSERT(consumer, "invalid consumer");
- // Check to see whether the consumer is already in our list
+ /* Check to see whether the consumer is already in our list. */
TConsumerVector::const_iterator iter = std::find(
m_consumers.begin(), m_consumers.end(), consumer);
if (iter == m_consumers.end()) {
- // Add the consumer
+ /* Add the consumer. */
m_consumers.push_back(consumer);
success = GHOST_kSuccess;
}
@@ -128,11 +128,11 @@ GHOST_TSuccess GHOST_EventManager::removeConsumer(GHOST_IEventConsumer *consumer
GHOST_TSuccess success;
GHOST_ASSERT(consumer, "invalid consumer");
- // Check to see whether the consumer is in our list
+ /* Check to see whether the consumer is in our list. */
TConsumerVector::iterator iter = std::find(m_consumers.begin(), m_consumers.end(), consumer);
if (iter != m_consumers.end()) {
- // Remove the consumer
+ /* Remove the consumer. */
m_consumers.erase(iter);
success = GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index 079ad67f737..0317c175273 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -22,51 +22,51 @@
#include <limits.h>
#include <math.h>
-#include <stdio.h> // for error/info reporting
-#include <string.h> // for memory functions
+#include <stdio.h> /* For error/info reporting. */
+#include <string.h> /* For memory functions. */
#ifdef DEBUG_NDOF_MOTION
-// printable version of each GHOST_TProgress value
+/* Printable version of each GHOST_TProgress value. */
static const char *progress_string[] = {
"not started", "starting", "in progress", "finishing", "finished"};
#endif
#ifdef DEBUG_NDOF_BUTTONS
static const char *ndof_button_names[] = {
- // used internally, never sent
+ /* used internally, never sent */
"NDOF_BUTTON_NONE",
- // these two are available from any 3Dconnexion device
+ /* these two are available from any 3Dconnexion device */
"NDOF_BUTTON_MENU",
"NDOF_BUTTON_FIT",
- // standard views
+ /* standard views */
"NDOF_BUTTON_TOP",
"NDOF_BUTTON_BOTTOM",
"NDOF_BUTTON_LEFT",
"NDOF_BUTTON_RIGHT",
"NDOF_BUTTON_FRONT",
"NDOF_BUTTON_BACK",
- // more views
+ /* more views */
"NDOF_BUTTON_ISO1",
"NDOF_BUTTON_ISO2",
- // 90 degree rotations
+ /* 90 degree rotations */
"NDOF_BUTTON_ROLL_CW",
"NDOF_BUTTON_ROLL_CCW",
"NDOF_BUTTON_SPIN_CW",
"NDOF_BUTTON_SPIN_CCW",
"NDOF_BUTTON_TILT_CW",
"NDOF_BUTTON_TILT_CCW",
- // device control
+ /* device control */
"NDOF_BUTTON_ROTATE",
"NDOF_BUTTON_PANZOOM",
"NDOF_BUTTON_DOMINANT",
"NDOF_BUTTON_PLUS",
"NDOF_BUTTON_MINUS",
- // keyboard emulation
+ /* keyboard emulation */
"NDOF_BUTTON_ESC",
"NDOF_BUTTON_ALT",
"NDOF_BUTTON_SHIFT",
"NDOF_BUTTON_CTRL",
- // general-purpose buttons
+ /* general-purpose buttons */
"NDOF_BUTTON_1",
"NDOF_BUTTON_2",
"NDOF_BUTTON_3",
@@ -77,17 +77,17 @@ static const char *ndof_button_names[] = {
"NDOF_BUTTON_8",
"NDOF_BUTTON_9",
"NDOF_BUTTON_10",
- // more general-purpose buttons
+ /* more general-purpose buttons */
"NDOF_BUTTON_A",
"NDOF_BUTTON_B",
"NDOF_BUTTON_C",
- // the end
+ /* the end */
"NDOF_BUTTON_LAST"};
#endif
-// shared by the latest 3Dconnexion hardware
-// SpacePilotPro uses all of these
-// smaller devices use only some, based on button mask
+/* Shared by the latest 3Dconnexion hardware
+ * SpacePilotPro uses all of these
+ * smaller devices use only some, based on button mask. */
static const NDOF_ButtonT Modern3Dx_HID_map[] = {
NDOF_BUTTON_MENU, NDOF_BUTTON_FIT, NDOF_BUTTON_TOP, NDOF_BUTTON_LEFT,
NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_BOTTOM, NDOF_BUTTON_BACK,
@@ -116,15 +116,15 @@ static const NDOF_ButtonT SpaceExplorer_HID_map[] = {
NDOF_BUTTON_ROTATE,
};
-// this is the older SpacePilot (sans Pro)
-// thanks to polosson for info about this device
+/* This is the older SpacePilot (sans Pro)
+ * thanks to polosson for info about this device. */
static const NDOF_ButtonT SpacePilot_HID_map[] = {
NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_3, NDOF_BUTTON_4,
NDOF_BUTTON_5, NDOF_BUTTON_6, NDOF_BUTTON_TOP, NDOF_BUTTON_LEFT,
NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_ESC, NDOF_BUTTON_ALT,
NDOF_BUTTON_SHIFT, NDOF_BUTTON_CTRL, NDOF_BUTTON_FIT, NDOF_BUTTON_MENU,
NDOF_BUTTON_PLUS, NDOF_BUTTON_MINUS, NDOF_BUTTON_DOMINANT, NDOF_BUTTON_ROTATE,
- NDOF_BUTTON_NONE // the CONFIG button -- what does it do?
+ NDOF_BUTTON_NONE /* the CONFIG button -- what does it do? */
};
static const NDOF_ButtonT Generic_HID_map[] = {
@@ -146,7 +146,7 @@ static const int genericButtonCount = sizeof(Generic_HID_map) / sizeof(NDOF_Butt
GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System &sys)
: m_system(sys),
- m_deviceType(NDOF_UnknownDevice), // each platform has its own device detection code
+ m_deviceType(NDOF_UnknownDevice), /* Each platform has its own device detection code. */
m_buttonCount(genericButtonCount),
m_buttonMask(0),
m_hidMap(Generic_HID_map),
@@ -157,37 +157,37 @@ GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System &sys)
m_motionEventPending(false),
m_deadZone(0.0f)
{
- // to avoid the rare situation where one triple is updated and
- // the other is not, initialize them both here:
+ /* To avoid the rare situation where one triple is updated and
+ * the other is not, initialize them both here: */
memset(m_translation, 0, sizeof(m_translation));
memset(m_rotation, 0, sizeof(m_rotation));
}
bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short product_id)
{
- // call this function until it returns true
- // it's a good idea to stop calling it after that, as it will "forget"
- // whichever device it already found
+ /* Call this function until it returns true
+ * it's a good idea to stop calling it after that, as it will "forget"
+ * whichever device it already found */
- // default to safe generic behavior for "unknown" devices
- // unidentified devices will emit motion events like normal
- // rogue buttons do nothing by default, but can be customized by the user
+ /* Default to safe generic behavior for "unknown" devices
+ * unidentified devices will emit motion events like normal
+ * rogue buttons do nothing by default, but can be customized by the user. */
m_deviceType = NDOF_UnknownDevice;
m_hidMap = Generic_HID_map;
m_buttonCount = genericButtonCount;
m_buttonMask = 0;
- // "mystery device" owners can help build a HID_map for their hardware
- // A few users have already contributed information about several older devices
- // that I don't have access to. Thanks!
+ /* "mystery device" owners can help build a HID_map for their hardware
+ * A few users have already contributed information about several older devices
+ * that I don't have access to. Thanks! */
switch (vendor_id) {
- case 0x046D: // Logitech (3Dconnexion was a subsidiary)
+ case 0x046D: /* Logitech (3Dconnexion was a subsidiary). */
switch (product_id) {
- // -- current devices --
- case 0xC626: // full-size SpaceNavigator
- case 0xC628: // the "for Notebooks" one
+ /* -- current devices -- */
+ case 0xC626: /* full-size SpaceNavigator */
+ case 0xC628: /* the "for Notebooks" one */
puts("ndof: using SpaceNavigator");
m_deviceType = NDOF_SpaceNavigator;
m_buttonCount = 2;
@@ -209,12 +209,12 @@ bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ
puts("ndof: using SpaceMouse Pro");
m_deviceType = NDOF_SpaceMousePro;
m_buttonCount = 27;
- // ^^ actually has 15 buttons, but their HID codes range from 0 to 26
+ /* ^^ actually has 15 buttons, but their HID codes range from 0 to 26 */
m_buttonMask = 0x07C0F137;
m_hidMap = Modern3Dx_HID_map;
break;
- // -- older devices --
+ /* -- older devices -- */
case 0xC625:
puts("ndof: using SpacePilot");
m_deviceType = NDOF_SpacePilot;
@@ -236,21 +236,21 @@ bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ
printf("ndof: unknown Logitech product %04hx\n", product_id);
}
break;
- case 0x256F: // 3Dconnexion
+ case 0x256F: /* 3Dconnexion */
switch (product_id) {
- case 0xC62E: // plugged in
- case 0xC62F: // wireless
+ case 0xC62E: /* Plugged in. */
+ case 0xC62F: /* Wireless. */
puts("ndof: using SpaceMouse Wireless");
m_deviceType = NDOF_SpaceMouseWireless;
m_buttonCount = 2;
m_hidMap = Modern3Dx_HID_map;
break;
- case 0xC631: // plugged in
- case 0xC632: // wireless
+ case 0xC631: /* Plugged in. */
+ case 0xC632: /* Wireless. */
puts("ndof: using SpaceMouse Pro Wireless");
m_deviceType = NDOF_SpaceMouseProWireless;
m_buttonCount = 27;
- // ^^ actually has 15 buttons, but their HID codes range from 0 to 26
+ /* ^^ actually has 15 buttons, but their HID codes range from 0 to 26. */
m_buttonMask = 0x07C0F137;
m_hidMap = Modern3Dx_HID_map;
break;
@@ -364,16 +364,16 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t tim
int mask = 1 << button_number;
if (press) {
- m_buttons |= mask; // set this button's bit
+ m_buttons |= mask; /* Set this button's bit. */
}
else {
- m_buttons &= ~mask; // clear this button's bit
+ m_buttons &= ~mask; /* Clear this button's bit. */
}
}
void GHOST_NDOFManager::updateButtons(int button_bits, uint64_t time)
{
- button_bits &= m_buttonMask; // discard any "garbage" bits
+ button_bits &= m_buttonMask; /* Discard any "garbage" bits. */
int diff = m_buttons ^ button_bits;
@@ -390,11 +390,11 @@ void GHOST_NDOFManager::updateButtons(int button_bits, uint64_t time)
void GHOST_NDOFManager::setDeadZone(float dz)
{
if (dz < 0.0f) {
- // negative values don't make sense, so clamp at zero
+ /* Negative values don't make sense, so clamp at zero. */
dz = 0.0f;
}
else if (dz > 0.5f) {
- // warn the rogue user/developer, but allow it
+ /* Warn the rogue user/developer, but allow it. */
GHOST_PRINTF("ndof: dead zone of %.2f is rather high...\n", dz);
}
m_deadZone = dz;
@@ -426,22 +426,22 @@ bool GHOST_NDOFManager::sendMotionEvent()
if (!m_motionEventPending)
return false;
- m_motionEventPending = false; // any pending motion is handled right now
+ m_motionEventPending = false; /* Any pending motion is handled right now. */
GHOST_IWindow *window = m_system.getWindowManager()->getActiveWindow();
if (window == NULL) {
- m_motionState = GHOST_kNotStarted; // avoid large 'dt' times when changing windows
- return false; // delivery will fail, so don't bother sending
+ m_motionState = GHOST_kNotStarted; /* Avoid large `dt` times when changing windows. */
+ return false; /* Delivery will fail, so don't bother sending. */
}
GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(m_motionTime, window);
GHOST_TEventNDOFMotionData *data = (GHOST_TEventNDOFMotionData *)event->getData();
- // scale axis values here to normalize them to around +/- 1
- // they are scaled again for overall sensitivity in the WM based on user prefs
+ /* Scale axis values here to normalize them to around +/- 1
+ * they are scaled again for overall sensitivity in the WM based on user preferences. */
- const float scale = 1.0f / 350.0f; // 3Dconnexion devices send +/- 350 usually
+ const float scale = 1.0f / 350.0f; /* 3Dconnexion devices send +/- 350 usually */
data->tx = scale * m_translation[0];
data->ty = scale * m_translation[1];
@@ -451,24 +451,24 @@ bool GHOST_NDOFManager::sendMotionEvent()
data->ry = scale * m_rotation[1];
data->rz = scale * m_rotation[2];
- data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds
+ data->dt = 0.001f * (m_motionTime - m_prevMotionTime); /* In seconds. */
m_prevMotionTime = m_motionTime;
bool weHaveMotion = !nearHomePosition(data, m_deadZone);
- // determine what kind of motion event to send (Starting, InProgress, Finishing)
- // and where that leaves this NDOF manager (NotStarted, InProgress, Finished)
+ /* Determine what kind of motion event to send `(Starting, InProgress, Finishing)`
+ * and where that leaves this NDOF manager `(NotStarted, InProgress, Finished)`. */
switch (m_motionState) {
case GHOST_kNotStarted:
case GHOST_kFinished:
if (weHaveMotion) {
data->progress = GHOST_kStarting;
m_motionState = GHOST_kInProgress;
- // prev motion time will be ancient, so just make up a reasonable time delta
+ /* Previous motion time will be ancient, so just make up a reasonable time delta. */
data->dt = 0.0125f;
}
else {
- // send no event and keep current state
+ /* Send no event and keep current state. */
#ifdef DEBUG_NDOF_MOTION
printf("ndof motion ignored -- %s\n", progress_string[data->progress]);
#endif
@@ -479,20 +479,22 @@ bool GHOST_NDOFManager::sendMotionEvent()
case GHOST_kInProgress:
if (weHaveMotion) {
data->progress = GHOST_kInProgress;
- // remain 'InProgress'
+ /* Remain 'InProgress'. */
}
else {
data->progress = GHOST_kFinishing;
m_motionState = GHOST_kFinished;
}
break;
- default:; // will always be one of the above
+ default:
+ /* Will always be one of the above. */
+ break;
}
#ifdef DEBUG_NDOF_MOTION
printf("ndof motion sent -- %s\n", progress_string[data->progress]);
- // show details about this motion event
+ /* Show details about this motion event. */
printf(" T=(%d,%d,%d) R=(%d,%d,%d) raw\n",
m_translation[0],
m_translation[1],
diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h
index 7be129c327c..31b11a352db 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.h
+++ b/intern/ghost/intern/GHOST_NDOFManager.h
@@ -28,7 +28,7 @@
typedef enum {
NDOF_UnknownDevice,
- // current devices
+ /* Current devices. */
NDOF_SpaceNavigator,
NDOF_SpaceExplorer,
NDOF_SpacePilotPro,
@@ -37,51 +37,51 @@ typedef enum {
NDOF_SpaceMouseProWireless,
NDOF_SpaceMouseEnterprise,
- // older devices
+ /* Older devices. */
NDOF_SpacePilot,
NDOF_Spaceball5000,
NDOF_SpaceTraveler
} NDOF_DeviceT;
-// NDOF device button event types
+/* NDOF device button event types */
typedef enum {
- // used internally, never sent
+ /* Used internally, never sent. */
NDOF_BUTTON_NONE,
- // these two are available from any 3Dconnexion device
+ /* These two are available from any 3Dconnexion device. */
NDOF_BUTTON_MENU,
NDOF_BUTTON_FIT,
- // standard views
+ /* Standard views. */
NDOF_BUTTON_TOP,
NDOF_BUTTON_BOTTOM,
NDOF_BUTTON_LEFT,
NDOF_BUTTON_RIGHT,
NDOF_BUTTON_FRONT,
NDOF_BUTTON_BACK,
- // more views
+ /* More views. */
NDOF_BUTTON_ISO1,
NDOF_BUTTON_ISO2,
- // 90 degree rotations
- // these don't all correspond to physical buttons
+ /* 90 degree rotations.
+ * These don't all correspond to physical buttons. */
NDOF_BUTTON_ROLL_CW,
NDOF_BUTTON_ROLL_CCW,
NDOF_BUTTON_SPIN_CW,
NDOF_BUTTON_SPIN_CCW,
NDOF_BUTTON_TILT_CW,
NDOF_BUTTON_TILT_CCW,
- // device control
+ /* Device control. */
NDOF_BUTTON_ROTATE,
NDOF_BUTTON_PANZOOM,
NDOF_BUTTON_DOMINANT,
NDOF_BUTTON_PLUS,
NDOF_BUTTON_MINUS,
- // keyboard emulation
+ /* Keyboard emulation. */
NDOF_BUTTON_ESC,
NDOF_BUTTON_ALT,
NDOF_BUTTON_SHIFT,
NDOF_BUTTON_CTRL,
- // general-purpose buttons
- // users can assign functions via keymap editor
+ /* General-purpose buttons.
+ * Users can assign functions via keymap editor. */
NDOF_BUTTON_1,
NDOF_BUTTON_2,
NDOF_BUTTON_3,
@@ -92,11 +92,11 @@ typedef enum {
NDOF_BUTTON_8,
NDOF_BUTTON_9,
NDOF_BUTTON_10,
- // more general-purpose buttons
+ /* More general-purpose buttons. */
NDOF_BUTTON_A,
NDOF_BUTTON_B,
NDOF_BUTTON_C,
- // the end
+ /* The end. */
NDOF_BUTTON_LAST
} NDOF_ButtonT;
@@ -107,40 +107,53 @@ class GHOST_NDOFManager {
{
}
- // whether multi-axis functionality is available (via the OS or driver)
- // does not imply that a device is plugged in or being used
+ /**
+ * Whether multi-axis functionality is available (via the OS or driver)
+ * does not imply that a device is plugged in or being used.
+ */
virtual bool available() = 0;
- // each platform's device detection should call this
- // use standard USB/HID identifiers
+ /**
+ * Each platform's device detection should call this
+ * use standard USB/HID identifiers.
+ */
bool setDevice(unsigned short vendor_id, unsigned short product_id);
- // filter out small/accidental/uncalibrated motions by
- // setting up a "dead zone" around home position
- // set to 0 to disable
- // 0.1 is a safe and reasonable value
+ /**
+ * Filter out small/accidental/un-calibrated motions by
+ * setting up a "dead zone" around home position
+ * set to 0 to disable
+ * 0.1 is a safe and reasonable value.
+ */
void setDeadZone(float);
- // the latest raw axis data from the device
- // NOTE: axis data should be in blender view coordinates
- // +X is to the right
- // +Y is up
- // +Z is out of the screen
- // for rotations, look from origin to each +axis
- // rotations are + when CCW, - when CW
- // each platform is responsible for getting axis data into this form
- // these values should not be scaled (just shuffled or flipped)
+ /**
+ * The latest raw axis data from the device.
+ *
+ * \note axis data should be in blender view coordinates
+ * - +X is to the right.
+ * - +Y is up.
+ * - +Z is out of the screen.
+ * - for rotations, look from origin to each +axis.
+ * - rotations are + when CCW, - when CW.
+ * Each platform is responsible for getting axis data into this form
+ * these values should not be scaled (just shuffled or flipped).
+ */
void updateTranslation(const int t[3], uint64_t time);
void updateRotation(const int r[3], uint64_t time);
- // the latest raw button data from the device
- // use HID button encoding (not NDOF_ButtonT)
+ /**
+ * The latest raw button data from the device
+ * use HID button encoding (not #NDOF_ButtonT).
+ */
void updateButton(int button_number, bool press, uint64_t time);
void updateButtons(int button_bits, uint64_t time);
- // NDOFButton events are sent immediately
+ /* #NDOFButton events are sent immediately */
- // processes and sends most recent raw data as an NDOFMotion event
- // returns whether an event was sent
+ /**
+ * Processes and sends most recent raw data as an #NDOFMotion event
+ * returns whether an event was sent.
+ */
bool sendMotionEvent();
protected:
@@ -157,12 +170,12 @@ class GHOST_NDOFManager {
int m_translation[3];
int m_rotation[3];
- int m_buttons; // bit field
+ int m_buttons; /* Bit field. */
- uint64_t m_motionTime; // in milliseconds
- uint64_t m_prevMotionTime; // time of most recent Motion event sent
+ uint64_t m_motionTime; /* In milliseconds. */
+ uint64_t m_prevMotionTime; /* Time of most recent motion event sent. */
GHOST_TProgress m_motionState;
bool m_motionEventPending;
- float m_deadZone; // discard motion with each component < this
+ float m_deadZone; /* Discard motion with each component < this. */
};
diff --git a/intern/ghost/intern/GHOST_Rect.cpp b/intern/ghost/intern/GHOST_Rect.cpp
index 8ef9486f35a..78c88cb0a71 100644
--- a/intern/ghost/intern/GHOST_Rect.cpp
+++ b/intern/ghost/intern/GHOST_Rect.cpp
@@ -26,14 +26,14 @@
void GHOST_Rect::inset(int32_t i)
{
if (i > 0) {
- // Grow the rectangle
+ /* Grow the rectangle. */
m_l -= i;
m_r += i;
m_t -= i;
m_b += i;
}
else if (i < 0) {
- // Shrink the rectangle, check for insets larger than half the size
+ /* Shrink the rectangle, check for insets larger than half the size. */
int32_t i2 = i * 2;
if (getWidth() > i2) {
m_l += i;
@@ -62,12 +62,12 @@ GHOST_TVisibility GHOST_Rect::getVisibility(GHOST_Rect &r) const
bool rb = isInside(r.m_r, r.m_b);
GHOST_TVisibility v;
if (lt && rt && lb && rb) {
- // All points inside, rectangle is inside this
+ /* All points inside, rectangle is inside this. */
v = GHOST_kFullyVisible;
}
else if (!(lt || rt || lb || rb)) {
- // None of the points inside
- // Check to see whether the rectangle is larger than this one
+ /* None of the points inside.
+ * Check to see whether the rectangle is larger than this one. */
if ((r.m_l < m_l) && (r.m_t < m_t) && (r.m_r > m_r) && (r.m_b > m_b)) {
v = GHOST_kPartiallyVisible;
}
@@ -76,7 +76,7 @@ GHOST_TVisibility GHOST_Rect::getVisibility(GHOST_Rect &r) const
}
}
else {
- // Some of the points inside, rectangle is partially inside
+ /* Some of the points inside, rectangle is partially inside. */
v = GHOST_kPartiallyVisible;
}
return v;
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index f6659cf50dc..d09c167cb95 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -72,7 +72,7 @@ GHOST_ITimerTask *GHOST_System::installTimer(uint64_t delay,
GHOST_TimerTask *timer = new GHOST_TimerTask(millis + delay, interval, timerProc, userData);
if (timer) {
if (m_timerManager->addTimer(timer) == GHOST_kSuccess) {
- // Check to see whether we need to fire the timer right away
+ /* Check to see whether we need to fire the timer right away. */
m_timerManager->fireTimers(millis);
}
else {
@@ -208,7 +208,7 @@ bool GHOST_System::getFullScreen(void)
void GHOST_System::dispatchEvents()
{
#ifdef WITH_INPUT_NDOF
- // NDOF Motion event is sent only once per dispatch, so do it now:
+ /* NDOF Motion event is sent only once per dispatch, so do it now: */
if (m_ndofManager) {
m_ndofManager->sendMotionEvent();
}
@@ -260,10 +260,10 @@ GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent *event)
GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bool &isDown) const
{
GHOST_ModifierKeys keys;
- // Get the state of all modifier keys
+ /* Get the state of all modifier keys. */
GHOST_TSuccess success = getModifierKeys(keys);
if (success) {
- // Isolate the state of the key requested
+ /* Isolate the state of the key requested. */
isDown = keys.get(mask);
}
return success;
@@ -272,10 +272,10 @@ GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bo
GHOST_TSuccess GHOST_System::getButtonState(GHOST_TButtonMask mask, bool &isDown) const
{
GHOST_Buttons buttons;
- // Get the state of all mouse buttons
+ /* Get the state of all mouse buttons. */
GHOST_TSuccess success = getButtons(buttons);
if (success) {
- // Isolate the state of the mouse button requested
+ /* Isolate the state of the mouse button requested. */
isDown = buttons.get(mask);
}
return success;
@@ -311,7 +311,7 @@ GHOST_TSuccess GHOST_System::init()
m_eventPrinter = new GHOST_EventPrinter();
m_eventManager->addConsumer(m_eventPrinter);
}
-#endif // WITH_GHOST_DEBUG
+#endif /* WITH_GHOST_DEBUG */
if (m_timerManager && m_windowManager && m_eventManager) {
return GHOST_kSuccess;
@@ -359,7 +359,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
if (alphaBackground)
glSettings.flags |= GHOST_glAlphaBackground;
- /* note: don't use getCurrentDisplaySetting() because on X11 we may
+ /* NOTE: don't use #getCurrentDisplaySetting() because on X11 we may
* be zoomed in and the desktop may be bigger than the viewport. */
GHOST_ASSERT(m_displayManager,
"GHOST_System::createFullScreenWindow(): invalid display manager");
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index f2f1b26b8e5..0309a4f9c52 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -143,7 +143,7 @@ GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GLSettings glSetti
{
GHOST_Context *context = new GHOST_ContextSDL(0,
NULL,
- 0, // profile bit
+ 0, /* Profile bit. */
3,
3,
GHOST_OPENGL_SDL_CONTEXT_FLAGS,
@@ -279,7 +279,7 @@ static GHOST_TKey convertSDLKey(SDL_Scancode key)
GXMAP(type, SDL_SCANCODE_AUDIOPLAY, GHOST_kKeyMediaPlay);
GXMAP(type, SDL_SCANCODE_AUDIOSTOP, GHOST_kKeyMediaStop);
GXMAP(type, SDL_SCANCODE_AUDIOPREV, GHOST_kKeyMediaFirst);
- // GXMAP(type,XF86XK_AudioRewind, GHOST_kKeyMediaFirst);
+ // GXMAP(type, XF86XK_AudioRewind, GHOST_kKeyMediaFirst);
GXMAP(type, SDL_SCANCODE_AUDIONEXT, GHOST_kKeyMediaLast);
default:
@@ -315,7 +315,10 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
SDL_WindowEvent &sdl_sub_evt = sdl_event->window;
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
- // assert(window != NULL); // can be NULL on close window.
+ /* Can be NULL on close window. */
+#if 0
+ assert(window != NULL);
+#endif
switch (sdl_sub_evt.event) {
case SDL_WINDOWEVENT_EXPOSED:
@@ -376,14 +379,14 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
bounds.wrapPoint(x_new, y_new, 8, window->getCursorGrabAxis());
window->getCursorGrabAccum(x_accum, y_accum);
- // can't use setCursorPosition because the mouse may have no focus!
+ /* Can't use #setCursorPosition because the mouse may have no focus! */
if (x_new != x_root || y_new != y_root) {
- if (1) { //xme.time > m_last_warp) {
+ if (1 /* `xme.time > m_last_warp` */ ) {
/* when wrapping we don't need to add an event because the
- * setCursorPosition call will cause a new event after */
+ * #setCursorPosition call will cause a new event after */
SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win); /* wrap */
window->setCursorGrabAccum(x_accum + (x_root - x_new), y_accum + (y_root - y_new));
- // m_last_warp= lastEventTime(xme.time);
+ // m_last_warp = lastEventTime(xme.time);
}
else {
// setCursorPosition(x_new, y_new); /* wrap but don't accumulate */
@@ -659,8 +662,8 @@ bool GHOST_SystemSDL::generateWindowExposeEvents()
bool GHOST_SystemSDL::processEvents(bool waitForEvent)
{
- // Get all the current events -- translate them into
- // ghost events and call base class pushEvent() method.
+ /* Get all the current events - translate them into
+ * ghost events and call base class #pushEvent() method. */
bool anyProcessed = false;
@@ -679,7 +682,7 @@ bool GHOST_SystemSDL::processEvents(bool waitForEvent)
if (maxSleep >= 0) {
SDL_WaitEventTimeout(NULL, next - getMilliSeconds());
- // SleepTillEvent(m_display, next - getMilliSeconds()); // X11
+ // SleepTillEvent(m_display, next - getMilliSeconds()); /* X11. */
}
}
}
@@ -707,10 +710,10 @@ GHOST_WindowSDL *GHOST_SystemSDL::findGhostWindow(SDL_Window *sdl_win)
if (sdl_win == NULL)
return NULL;
- // It is not entirely safe to do this as the backptr may point
- // to a window that has recently been removed.
- // We should always check the window manager's list of windows
- // and only process events on these windows.
+ /* It is not entirely safe to do this as the backptr may point
+ * to a window that has recently been removed.
+ * We should always check the window manager's list of windows
+ * and only process events on these windows. */
const std::vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 6c786aedfb1..17e9adff8bc 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -360,8 +360,8 @@ class GHOST_SystemWin32 : public GHOST_System {
static GHOST_EventKey *processKeyEvent(GHOST_WindowWin32 *window, RAWINPUT const &raw);
/**
- * Process special keys (VK_OEM_*), to see if current key layout
- * gives us anything special, like ! on french AZERTY.
+ * Process special keys `VK_OEM_*`, to see if current key layout
+ * gives us anything special, like `!` on French AZERTY.
* \param vKey: The virtual key from #hardKey.
* \param scanCode: The ScanCode of pressed key (similar to PS/2 Set 1).
*/
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 172fcbeb3de..e36bfd1aaeb 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -396,15 +396,15 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
*/
GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSettings)
{
- // During development:
- // try 4.x compatibility profile
- // try 3.3 compatibility profile
- // fall back to 3.0 if needed
- //
- // Final Blender 2.8:
- // try 4.x core profile
- // try 3.3 core profile
- // no fallbacks
+ /* During development:
+ * try 4.x compatibility profile
+ * try 3.3 compatibility profile
+ * fall back to 3.0 if needed
+ *
+ * Final Blender 2.8:
+ * try 4.x core profile
+ * try 3.3 core profile
+ * no fall-backs. */
const bool debug_context = (glSettings.flags & GHOST_glDebugContext) != 0;
@@ -2014,7 +2014,7 @@ void GHOST_SystemX11::getClipboard_xcout(const XEvent *evt,
return;
}
- // not using INCR mechanism, just read the property
+ /* Not using INCR mechanism, just read the property. */
XGetWindowProperty(m_display,
win,
m_atom.XCLIP_OUT,
diff --git a/intern/ghost/intern/GHOST_TimerManager.cpp b/intern/ghost/intern/GHOST_TimerManager.cpp
index 195135f5f85..0c88150381f 100644
--- a/intern/ghost/intern/GHOST_TimerManager.cpp
+++ b/intern/ghost/intern/GHOST_TimerManager.cpp
@@ -55,7 +55,7 @@ GHOST_TSuccess GHOST_TimerManager::addTimer(GHOST_TimerTask *timer)
{
GHOST_TSuccess success;
if (!getTimerFound(timer)) {
- // Add the timer task
+ /* Add the timer task. */
m_timers.push_back(timer);
success = GHOST_kSuccess;
}
@@ -70,7 +70,7 @@ GHOST_TSuccess GHOST_TimerManager::removeTimer(GHOST_TimerTask *timer)
GHOST_TSuccess success;
TTimerVector::iterator iter = std::find(m_timers.begin(), m_timers.end(), timer);
if (iter != m_timers.end()) {
- // Remove the timer task
+ /* Remove the timer task. */
m_timers.erase(iter);
delete timer;
success = GHOST_kSuccess;
@@ -113,14 +113,14 @@ bool GHOST_TimerManager::fireTimer(uint64_t time, GHOST_TimerTask *task)
{
uint64_t next = task->getNext();
- // Check if the timer should be fired
+ /* Check if the timer should be fired. */
if (time > next) {
- // Fire the timer
+ /* Fire the timer. */
GHOST_TimerProcPtr timerProc = task->getTimerProc();
uint64_t start = task->getStart();
timerProc(task, time - start);
- // Update the time at which we will fire it again
+ /* Update the time at which we will fire it again. */
uint64_t interval = task->getInterval();
uint64_t numCalls = (next - start) / interval;
numCalls++;
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index 0fd70514ac6..68ac507f0e0 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -157,7 +157,7 @@ class GHOST_WindowCocoa : public GHOST_Window {
void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const;
/**
- * Converts a point in screen coordinates to client rectangle coordinates
+ * Converts a point in client rectangle coordinates to screen coordinates.
* \param inX: The x-coordinate in the client rectangle.
* \param inY: The y-coordinate in the client rectangle.
* \param outX: The x-coordinate on the screen.
@@ -166,7 +166,7 @@ class GHOST_WindowCocoa : public GHOST_Window {
void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const;
/**
- * Converts a point in screen coordinates to client rectangle coordinates
+ * Converts a point in client rectangle coordinates to screen coordinates.
* but without the y coordinate conversion needed for ghost compatibility.
* \param inX: The x-coordinate in the client rectangle.
* \param inY: The y-coordinate in the client rectangle.
@@ -178,10 +178,10 @@ class GHOST_WindowCocoa : public GHOST_Window {
/**
* Converts a point in screen coordinates to client rectangle coordinates,
* but without the y coordinate conversion needed for ghost compatibility.
- * \param inX: The x-coordinate in the client rectangle.
- * \param inY: The y-coordinate in the client rectangle.
- * \param outX: The x-coordinate on the screen.
- * \param outY: The y-coordinate on the screen.
+ * \param inX: The x-coordinate on the screen.
+ * \param inY: The y-coordinate on the screen.
+ * \param outX: The x-coordinate in the client rectangle.
+ * \param outY: The y-coordinate in the client rectangle.
*/
void screenToClientIntern(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const;
diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp
index eec4bc5f7d0..4cb80884209 100644
--- a/intern/ghost/intern/GHOST_WindowManager.cpp
+++ b/intern/ghost/intern/GHOST_WindowManager.cpp
@@ -45,7 +45,7 @@ GHOST_TSuccess GHOST_WindowManager::addWindow(GHOST_IWindow *window)
GHOST_TSuccess success = GHOST_kFailure;
if (window) {
if (!getWindowFound(window)) {
- // Store the pointer to the window
+ /* Store the pointer to the window. */
m_windows.push_back(window);
success = GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index d0c8cfb9e73..71062a4b6d6 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -34,7 +34,7 @@ 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
+ /* Outputs on which the window is currently shown on. */
std::unordered_set<const output_t *> outputs;
uint16_t dpi = 0;
int scale = 1;
@@ -154,8 +154,8 @@ static bool update_scale(GHOST_WindowWayland *window)
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
+ /* 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;
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index 40a658bf88b..ed5292f1712 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -183,7 +183,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const;
/**
- * Converts a point in screen coordinates to client rectangle coordinates
+ * Converts a point in client rectangle coordinates to screen coordinates.
* \param inX: The x-coordinate in the client rectangle.
* \param inY: The y-coordinate in the client rectangle.
* \param outX: The x-coordinate on the screen.
diff --git a/intern/ghost/intern/GHOST_XrSession.cpp b/intern/ghost/intern/GHOST_XrSession.cpp
index 35280e77e22..6140b2aab46 100644
--- a/intern/ghost/intern/GHOST_XrSession.cpp
+++ b/intern/ghost/intern/GHOST_XrSession.cpp
@@ -120,7 +120,7 @@ static void create_reference_spaces(OpenXRSessionData &oxr, const GHOST_XrPose &
XrReferenceSpaceCreateInfo create_info = {XR_TYPE_REFERENCE_SPACE_CREATE_INFO};
create_info.poseInReferenceSpace.orientation.w = 1.0f;
- create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
+ create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
#if 0
/* TODO
*
@@ -144,8 +144,47 @@ static void create_reference_spaces(OpenXRSessionData &oxr, const GHOST_XrPose &
(void)base_pose;
#endif
- CHECK_XR(xrCreateReferenceSpace(oxr.session, &create_info, &oxr.reference_space),
- "Failed to create reference space.");
+ XrResult result = xrCreateReferenceSpace(oxr.session, &create_info, &oxr.reference_space);
+
+ if (XR_FAILED(result)) {
+ /* One of the rare cases where we don't want to immediately throw an exception on failure,
+ * since runtimes are not required to support the stage reference space. Although we need the
+ * stage reference space for absolute tracking, if the runtime doesn't support it then just
+ * fallback to the local space. */
+ if (result == XR_ERROR_REFERENCE_SPACE_UNSUPPORTED) {
+ printf(
+ "Warning: XR runtime does not support stage reference space, disabling absolute "
+ "tracking.\n");
+
+ create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
+ CHECK_XR(xrCreateReferenceSpace(oxr.session, &create_info, &oxr.reference_space),
+ "Failed to create local reference space.");
+ }
+ else {
+ throw GHOST_XrException("Failed to create stage reference space.", result);
+ }
+ }
+ else {
+ /* Check if tracking bounds are valid. Tracking bounds may be invalid if the user did not
+ * define a tracking space via the XR runtime. */
+ XrExtent2Df extents;
+ CHECK_XR(xrGetReferenceSpaceBoundsRect(oxr.session, XR_REFERENCE_SPACE_TYPE_STAGE, &extents),
+ "Failed to get stage reference space bounds.");
+ if (extents.width == 0.0f || extents.height == 0.0f) {
+ printf(
+ "Warning: Invalid stage reference space bounds, disabling absolute tracking. To enable "
+ "absolute tracking, please define a tracking space via the XR runtime.\n");
+
+ /* Fallback to local space. */
+ if (oxr.reference_space != XR_NULL_HANDLE) {
+ CHECK_XR(xrDestroySpace(oxr.reference_space), "Failed to destroy stage reference space.");
+ }
+
+ create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
+ CHECK_XR(xrCreateReferenceSpace(oxr.session, &create_info, &oxr.reference_space),
+ "Failed to create local reference space.");
+ }
+ }
create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW;
CHECK_XR(xrCreateReferenceSpace(oxr.session, &create_info, &oxr.view_space),
@@ -370,6 +409,7 @@ void GHOST_XrSession::drawView(GHOST_XrSwapchain &swapchain,
XrCompositionLayerProjectionView &r_proj_layer_view,
XrSpaceLocation &view_location,
XrView &view,
+ uint32_t view_idx,
void *draw_customdata)
{
XrSwapchainImageBaseHeader *swapchain_image = swapchain.acquireDrawableSwapchainImage();
@@ -380,6 +420,8 @@ void GHOST_XrSession::drawView(GHOST_XrSwapchain &swapchain,
r_proj_layer_view.fov = view.fov;
swapchain.updateCompositionLayerProjectViewSubImage(r_proj_layer_view.subImage);
+ assert(view_idx < 256);
+ draw_view_info.view_idx = (char)view_idx;
draw_view_info.expects_srgb_buffer = swapchain.isBufferSRGB();
draw_view_info.ofsx = r_proj_layer_view.subImage.imageRect.offset.x;
draw_view_info.ofsy = r_proj_layer_view.subImage.imageRect.offset.y;
@@ -429,6 +471,7 @@ XrCompositionLayerProjection GHOST_XrSession::drawLayer(
r_proj_layer_views[view_idx],
view_location,
m_oxr->views[view_idx],
+ view_idx,
draw_customdata);
}
diff --git a/intern/ghost/intern/GHOST_XrSession.h b/intern/ghost/intern/GHOST_XrSession.h
index c871b98da46..d448585d14c 100644
--- a/intern/ghost/intern/GHOST_XrSession.h
+++ b/intern/ghost/intern/GHOST_XrSession.h
@@ -117,6 +117,7 @@ class GHOST_XrSession {
XrCompositionLayerProjectionView &r_proj_layer_view,
XrSpaceLocation &view_location,
XrView &view,
+ uint32_t view_idx,
void *draw_customdata);
void beginFrameDrawing();
void endFrameDrawing(std::vector<XrCompositionLayerBaseHeader *> &layers);
diff --git a/intern/libmv/CMakeLists.txt b/intern/libmv/CMakeLists.txt
index 6fcf664d1f5..91ef1f4d038 100644
--- a/intern/libmv/CMakeLists.txt
+++ b/intern/libmv/CMakeLists.txt
@@ -217,39 +217,39 @@ if(WITH_LIBMV)
if(WITH_GTESTS)
include(GTestTesting)
- blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "" "" "")
+ blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "${INC}" "${INC_SYS}" "")
- BLENDER_SRC_GTEST("libmv_predict_tracks" "./libmv/autotrack/predict_tracks_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_tracks" "./libmv/autotrack/tracks_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_scoped_ptr" "./libmv/base/scoped_ptr_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_vector" "./libmv/base/vector_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_array_nd" "./libmv/image/array_nd_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_convolve" "./libmv/image/convolve_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_image" "./libmv/image/image_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_sample" "./libmv/image/sample_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_tuple" "./libmv/image/tuple_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_euclidean_resection" "./libmv/multiview/euclidean_resection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_fundamental" "./libmv/multiview/fundamental_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_homography" "./libmv/multiview/homography_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_nviewtriangulation" "./libmv/multiview/nviewtriangulation_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_panography" "./libmv/multiview/panography_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_projection" "./libmv/multiview/projection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_resection" "./libmv/multiview/resection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_triangulation" "./libmv/multiview/triangulation_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_dogleg" "./libmv/numeric/dogleg_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_function_derivative" "./libmv/numeric/function_derivative_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_levenberg_marquardt" "./libmv/numeric/levenberg_marquardt_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_numeric" "./libmv/numeric/numeric_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_poly" "./libmv/numeric/poly_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_camera_intrinsics" "./libmv/simple_pipeline/camera_intrinsics_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_detect" "./libmv/simple_pipeline/detect_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_intersect" "./libmv/simple_pipeline/intersect_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_keyframe_selection" "./libmv/simple_pipeline/keyframe_selection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_modal_solver" "./libmv/simple_pipeline/modal_solver_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_resect" "./libmv/simple_pipeline/resect_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_brute_region_tracker" "./libmv/tracking/brute_region_tracker_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_klt_region_tracker" "./libmv/tracking/klt_region_tracker_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_pyramid_region_tracker" "./libmv/tracking/pyramid_region_tracker_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_predict_tracks" "./libmv/autotrack/predict_tracks_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_tracks" "./libmv/autotrack/tracks_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_scoped_ptr" "./libmv/base/scoped_ptr_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_vector" "./libmv/base/vector_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_array_nd" "./libmv/image/array_nd_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_convolve" "./libmv/image/convolve_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_image" "./libmv/image/image_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_sample" "./libmv/image/sample_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_tuple" "./libmv/image/tuple_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_euclidean_resection" "./libmv/multiview/euclidean_resection_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_fundamental" "./libmv/multiview/fundamental_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_homography" "./libmv/multiview/homography_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_nviewtriangulation" "./libmv/multiview/nviewtriangulation_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_panography" "./libmv/multiview/panography_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_projection" "./libmv/multiview/projection_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_resection" "./libmv/multiview/resection_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_triangulation" "./libmv/multiview/triangulation_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_dogleg" "./libmv/numeric/dogleg_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_function_derivative" "./libmv/numeric/function_derivative_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_levenberg_marquardt" "./libmv/numeric/levenberg_marquardt_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_numeric" "./libmv/numeric/numeric_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_poly" "./libmv/numeric/poly_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_camera_intrinsics" "./libmv/simple_pipeline/camera_intrinsics_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_detect" "./libmv/simple_pipeline/detect_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_intersect" "./libmv/simple_pipeline/intersect_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_keyframe_selection" "./libmv/simple_pipeline/keyframe_selection_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_modal_solver" "./libmv/simple_pipeline/modal_solver_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_resect" "./libmv/simple_pipeline/resect_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_brute_region_tracker" "./libmv/tracking/brute_region_tracker_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_klt_region_tracker" "./libmv/tracking/klt_region_tracker_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ blender_add_test_executable("libmv_pyramid_region_tracker" "./libmv/tracking/pyramid_region_tracker_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
endif()
else()
list(APPEND SRC
diff --git a/intern/memutil/MEM_Allocator.h b/intern/memutil/MEM_Allocator.h
index 50a3e978197..1dbb2d5a9f7 100644
--- a/intern/memutil/MEM_Allocator.h
+++ b/intern/memutil/MEM_Allocator.h
@@ -62,8 +62,8 @@ template<typename _Tp> struct MEM_Allocator {
return &__x;
}
- // NB: __n is permitted to be 0. The C++ standard says nothing
- // about what the return value is when __n == 0.
+ /* NOTE: `__n` is permitted to be 0.
+ * The C++ standard says nothing about what the return value is when `__n == 0`. */
_Tp *allocate(size_type __n, const void * = 0)
{
_Tp *__ret = NULL;
diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt
index 16334a80761..bce8a8baa84 100644
--- a/intern/opensubdiv/CMakeLists.txt
+++ b/intern/opensubdiv/CMakeLists.txt
@@ -129,5 +129,5 @@ if(WITH_GTESTS AND WITH_OPENSUBDIV)
add_definitions(${GLOG_DEFINES})
add_definitions(-DBLENDER_GFLAGS_NAMESPACE=${GFLAGS_NAMESPACE})
- BLENDER_SRC_GTEST(opensubdiv_mesh_topology_test "internal/topology/mesh_topology_test.cc" "${LIB};bf_intern_opensubdiv")
+ blender_add_test_executable(opensubdiv_mesh_topology_test "internal/topology/mesh_topology_test.cc" "${INC}" "${INC_SYS}" "${LIB};bf_intern_opensubdiv")
endif()
diff --git a/intern/rigidbody/RBI_api.h b/intern/rigidbody/RBI_api.h
index 2e09f8952cb..f13f321a2c6 100644
--- a/intern/rigidbody/RBI_api.h
+++ b/intern/rigidbody/RBI_api.h
@@ -64,7 +64,7 @@ typedef struct rbConstraint rbConstraint;
/* Setup ---------------------------- */
/* Create a new dynamics world instance */
-// TODO: add args to set the type of constraint solvers, etc.
+/* TODO: add args to set the type of constraint solvers, etc. */
rbDynamicsWorld *RB_dworld_new(const float gravity[3]);
/* Delete the given dynamics world, and free any extra data it may require */
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 4833954c0ac85cc407e1d5a153aa11b1d1823ec
+Subproject 62e82958a760dad775d9b3387d7fb535fd6de4c
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c
index 6220edce28f..d51a82c482b 100644
--- a/release/datafiles/userdef/userdef_default.c
+++ b/release/datafiles/userdef/userdef_default.c
@@ -113,7 +113,7 @@ const UserDef U_default = {
.gp_eraser = 25,
.gp_settings = 0,
- /** Initialized by: #BKE_studiolight_default . */
+ /** Initialized by: #BKE_studiolight_default. */
.light_param = {{0}},
.light_ambient = {0, 0, 0},
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject f86f25e62217264495d05f116ccb09d575fe984
+Subproject 1adb56d8b01cf1327f58c6fb8b1ccc8b7efd76a
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 5a82baad9f986722104280e8354a4427d8e9eab
+Subproject 788441f2930465bbfba8f0797b12dcef1d46694
diff --git a/release/scripts/modules/bl_i18n_utils/utils_cli.py b/release/scripts/modules/bl_i18n_utils/utils_cli.py
index e18491fa042..ea74ba832d9 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_cli.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_cli.py
@@ -71,7 +71,7 @@ def rtl_process_po(args, settings):
po.write(kind="PO", dest=args.dst)
-def language_menu(_args, settings):
+def language_menu(args, settings):
# 'DEFAULT' and en_US are always valid, fully-translated "languages"!
stats = {"DEFAULT": 1.0, "en_US": 1.0}
diff --git a/release/scripts/modules/nodeitems_utils.py b/release/scripts/modules/nodeitems_utils.py
index a50997fab5f..a5c18cee463 100644
--- a/release/scripts/modules/nodeitems_utils.py
+++ b/release/scripts/modules/nodeitems_utils.py
@@ -77,7 +77,7 @@ class NodeItem:
else:
return bpy.app.translations.contexts.default
- # NB: is a staticmethod because called with an explicit self argument
+ # NOTE: is a staticmethod because called with an explicit self argument
# NodeItemCustom sets this as a variable attribute in __init__
@staticmethod
def draw(self, layout, _context):
diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py
index 57fcd6f9752..f9756811bde 100644
--- a/release/scripts/modules/rna_manual_reference.py
+++ b/release/scripts/modules/rna_manual_reference.py
@@ -139,6 +139,7 @@ url_manual_mapping = (
("bpy.types.fluiddomainsettings.use_resumable_cache*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-use-resumable-cache"),
("bpy.types.fluiddomainsettings.use_spray_particles*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-use-spray-particles"),
("bpy.types.fluiddomainsettings.vector_display_type*", "physics/fluid/type/domain/gas/viewport_display.html#bpy-types-fluiddomainsettings-vector-display-type"),
+ ("bpy.types.geometrynodecurveprimitivebeziersegment*", "modeling/geometry_nodes/curve_primitives/bezier_segment.html#bpy-types-geometrynodecurveprimitivebeziersegment"),
("bpy.types.linestylegeometrymodifier_perlinnoise1d*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/perlin_noise_1d.html#bpy-types-linestylegeometrymodifier-perlinnoise1d"),
("bpy.types.linestylegeometrymodifier_perlinnoise2d*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/perlin_noise_2d.html#bpy-types-linestylegeometrymodifier-perlinnoise2d"),
("bpy.types.materialgpencilstyle.use_stroke_holdout*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-stroke-holdout"),
@@ -215,6 +216,7 @@ url_manual_mapping = (
("bpy.types.spacesequenceeditor.proxy_render_size*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-proxy-render-size"),
("bpy.types.spacesequenceeditor.show_strip_offset*", "video_editing/sequencer/navigating.html#bpy-types-spacesequenceeditor-show-strip-offset"),
("bpy.types.spacesequenceeditor.show_strip_source*", "video_editing/sequencer/navigating.html#bpy-types-spacesequenceeditor-show-strip-source"),
+ ("bpy.types.spacespreadsheetrowfilter.column_name*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-column-name"),
("bpy.types.toolsettings.gpencil_stroke_placement*", "grease_pencil/modes/draw/stroke_placement.html#bpy-types-toolsettings-gpencil-stroke-placement"),
("bpy.types.toolsettings.use_keyframe_cycle_aware*", "editors/timeline.html#bpy-types-toolsettings-use-keyframe-cycle-aware"),
("bpy.types.toolsettings.use_keyframe_insert_auto*", "editors/timeline.html#bpy-types-toolsettings-use-keyframe-insert-auto"),
@@ -233,6 +235,7 @@ url_manual_mapping = (
("bpy.types.rendersettings.resolution_percentage*", "render/output/properties/dimensions.html#bpy-types-rendersettings-resolution-percentage"),
("bpy.types.rendersettings_simplify_gpencil_tint*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-tint"),
("bpy.types.spaceoutliner.use_filter_object_mesh*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-mesh"),
+ ("bpy.types.spaceoutliner.use_filter_view_layers*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-view-layers"),
("bpy.types.spacesequenceeditor.show_overexposed*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-show-overexposed"),
("bpy.types.toolsettings.use_gpencil_draw_onback*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-onback"),
("bpy.types.toolsettings.use_snap_align_rotation*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-align-rotation"),
@@ -273,6 +276,8 @@ url_manual_mapping = (
("bpy.types.spacesequenceeditor.show_safe_areas*", "video_editing/preview/introduction.html#bpy-types-spacesequenceeditor-show-safe-areas"),
("bpy.types.spacesequenceeditor.show_strip_name*", "video_editing/sequencer/navigating.html#bpy-types-spacesequenceeditor-show-strip-name"),
("bpy.types.spacespreadsheet.show_only_selected*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-show-only-selected"),
+ ("bpy.types.spacespreadsheetrowfilter.operation*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-operation"),
+ ("bpy.types.spacespreadsheetrowfilter.threshold*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-threshold"),
("bpy.types.toolsettings.use_snap_grid_absolute*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-grid-absolute"),
("bpy.types.view3doverlay.show_face_orientation*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-face-orientation"),
("bpy.ops.object.blenderkit_material_thumbnail*", "addons/3d_view/blenderkit.html#bpy-ops-object-blenderkit-material-thumbnail"),
@@ -343,6 +348,7 @@ url_manual_mapping = (
("bpy.types.spaceoutliner.use_filter_complete*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-complete"),
("bpy.types.spacesequenceeditor.show_metadata*", "video_editing/preview/introduction.html#bpy-types-spacesequenceeditor-show-metadata"),
("bpy.types.spacespreadsheet.attribute_domain*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-attribute-domain"),
+ ("bpy.types.spacespreadsheetrowfilter.enabled*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-enabled"),
("bpy.types.spaceview3d.transform_orientation*", "editors/3dview/controls/orientation.html#bpy-types-spaceview3d-transform-orientation"),
("bpy.types.spaceview3d.use_local_collections*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-use-local-collections"),
("bpy.types.toolsettings.use_snap_peel_object*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-peel-object"),
@@ -350,7 +356,6 @@ url_manual_mapping = (
("bpy.types.view3doverlay.wireframe_threshold*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-wireframe-threshold"),
("bpy.ops.object.constraint_add_with_targets*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-constraint-add-with-targets"),
("bpy.ops.object.material_slot_remove_unused*", "scene_layout/object/editing/cleanup.html#bpy-ops-object-material-slot-remove-unused"),
- ("bpy.ops.object.vertex_group_copy_to_linked*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-copy-to-linked"),
("bpy.ops.outliner.collection_disable_render*", "editors/outliner/editing.html#bpy-ops-outliner-collection-disable-render"),
("bpy.types.brush.cloth_simulation_area_type*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-simulation-area-type"),
("bpy.types.brushgpencilsettings.fill_factor*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-factor"),
@@ -372,6 +377,7 @@ url_manual_mapping = (
("bpy.types.fluidflowsettings.use_plane_init*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-use-plane-init"),
("bpy.types.fluidflowsettings.velocity_coord*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-velocity-coord"),
("bpy.types.fluidflowsettings.volume_density*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-volume-density"),
+ ("bpy.types.geometrynodecurvequadraticbezier*", "modeling/geometry_nodes/curve_primitives/quadratic_bezier.html#bpy-types-geometrynodecurvequadraticbezier"),
("bpy.types.materialgpencilstyle.show_stroke*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-show-stroke"),
("bpy.types.movietrackingcamera.focal_length*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-focal-length"),
("bpy.types.movietrackingcamera.pixel_aspect*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-pixel-aspect"),
@@ -471,6 +477,7 @@ url_manual_mapping = (
("bpy.types.geometrynodeattributecolorramp*", "modeling/geometry_nodes/attribute/attribute_color_ramp.html#bpy-types-geometrynodeattributecolorramp"),
("bpy.types.geometrynodeattributeproximity*", "modeling/geometry_nodes/attribute/attribute_proximity.html#bpy-types-geometrynodeattributeproximity"),
("bpy.types.geometrynodeattributerandomize*", "modeling/geometry_nodes/attribute/attribute_randomize.html#bpy-types-geometrynodeattributerandomize"),
+ ("bpy.types.geometrynodecurvequadrilateral*", "modeling/geometry_nodes/curve_primitives/quadrilateral.html#bpy-types-geometrynodecurvequadrilateral"),
("bpy.types.geometrynodeseparatecomponents*", "modeling/geometry_nodes/geometry/separate_components.html#bpy-types-geometrynodeseparatecomponents"),
("bpy.types.geometrynodesubdivisionsurface*", "modeling/geometry_nodes/mesh/subdivision_surface.html#bpy-types-geometrynodesubdivisionsurface"),
("bpy.types.imageformatsettings.color_mode*", "render/output/properties/output.html#bpy-types-imageformatsettings-color-mode"),
@@ -490,7 +497,7 @@ url_manual_mapping = (
("bpy.types.rendersettings.use_compositing*", "render/output/properties/post_processing.html#bpy-types-rendersettings-use-compositing"),
("bpy.types.rendersettings.use_placeholder*", "render/output/properties/output.html#bpy-types-rendersettings-use-placeholder"),
("bpy.types.shadernodesubsurfacescattering*", "render/shader_nodes/shader/sss.html#bpy-types-shadernodesubsurfacescattering"),
- ("bpy.types.spaceclipeditor.lock_selection*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-lock-selection"),
+ ("bpy.types.spaceclipeditor.lock_selection*", "editors/clip/introduction.html#bpy-types-spaceclipeditor-lock-selection"),
("bpy.types.spacedopesheeteditor.auto_snap*", "editors/dope_sheet/editing.html#bpy-types-spacedopesheeteditor-auto-snap"),
("bpy.types.spaceoutliner.show_mode_column*", "editors/outliner/interface.html#bpy-types-spaceoutliner-show-mode-column"),
("bpy.types.spacetexteditor.use_match_case*", "editors/text_editor.html#bpy-types-spacetexteditor-use-match-case"),
@@ -508,6 +515,7 @@ url_manual_mapping = (
("bpy.ops.outliner.collection_show_inside*", "editors/outliner/editing.html#bpy-ops-outliner-collection-show-inside"),
("bpy.ops.preferences.reset_default_theme*", "editors/preferences/themes.html#bpy-ops-preferences-reset-default-theme"),
("bpy.ops.sequencer.strip_transform_clear*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-strip-transform-clear"),
+ ("bpy.ops.spreadsheet.add_row_filter_rule*", "editors/spreadsheet.html#bpy-ops-spreadsheet-add-row-filter-rule"),
("bpy.types.animdata.action_extrapolation*", "editors/nla/sidebar.html#bpy-types-animdata-action-extrapolation"),
("bpy.types.bakesettings.max_ray_distance*", "render/cycles/baking.html#bpy-types-bakesettings-max-ray-distance"),
("bpy.types.brush.multiplane_scrape_angle*", "sculpt_paint/sculpting/tools/multiplane_scrape.html#bpy-types-brush-multiplane-scrape-angle"),
@@ -695,6 +703,7 @@ url_manual_mapping = (
("bpy.types.fmodifierfunctiongenerator*", "editors/graph_editor/fcurves/sidebar/modifiers.html#bpy-types-fmodifierfunctiongenerator"),
("bpy.types.geometrynodeattributeclamp*", "modeling/geometry_nodes/attribute/attribute_clamp.html#bpy-types-geometrynodeattributeclamp"),
("bpy.types.geometrynodecollectioninfo*", "modeling/geometry_nodes/input/collection_info.html#bpy-types-geometrynodecollectioninfo"),
+ ("bpy.types.geometrynodecurveendpoints*", "modeling/geometry_nodes/curve/curve_endpoints.html#bpy-types-geometrynodecurveendpoints"),
("bpy.types.geometrynodecurvesubdivide*", "modeling/geometry_nodes/curve/curve_subdivide.html#bpy-types-geometrynodecurvesubdivide"),
("bpy.types.geometrynodedeletegeometry*", "modeling/geometry_nodes/geometry/delete_geometry.html#bpy-types-geometrynodedeletegeometry"),
("bpy.types.geometrynodematerialassign*", "modeling/geometry_nodes/material/assign.html#bpy-types-geometrynodematerialassign"),
@@ -765,6 +774,7 @@ url_manual_mapping = (
("bpy.types.geometrynodecurvetopoints*", "modeling/geometry_nodes/curve/curve_to_points.html#bpy-types-geometrynodecurvetopoints"),
("bpy.types.geometrynodeinputmaterial*", "modeling/geometry_nodes/input/material.html#bpy-types-geometrynodeinputmaterial"),
("bpy.types.geometrynodemeshicosphere*", "modeling/geometry_nodes/mesh_primitives/icosphere.html#bpy-types-geometrynodemeshicosphere"),
+ ("bpy.types.geometrynodemeshsubdivide*", "modeling/geometry_nodes/mesh/subdivide.html#bpy-types-geometrynodemeshsubdivide"),
("bpy.types.geometrynodepointinstance*", "modeling/geometry_nodes/point/point_instance.html#bpy-types-geometrynodepointinstance"),
("bpy.types.geometrynodepointseparate*", "modeling/geometry_nodes/point/point_separate.html#bpy-types-geometrynodepointseparate"),
("bpy.types.geometrynoderesamplecurve*", "modeling/geometry_nodes/curve/resample_curve.html#bpy-types-geometrynoderesamplecurve"),
@@ -795,6 +805,7 @@ url_manual_mapping = (
("bpy.types.spline.tilt_interpolation*", "modeling/curves/properties/active_spline.html#bpy-types-spline-tilt-interpolation"),
("bpy.types.transformorientation.name*", "editors/3dview/controls/orientation.html#bpy-types-transformorientation-name"),
("bpy.types.volumedisplay.slice_depth*", "modeling/volumes/properties.html#bpy-types-volumedisplay-slice-depth"),
+ ("bpy.ops.clip.lock_selection_toggle*", "editors/clip/introduction.html#bpy-ops-clip-lock-selection-toggle"),
("bpy.ops.mesh.customdata_mask_clear*", "sculpt_paint/sculpting/editing/mask.html#bpy-ops-mesh-customdata-mask-clear"),
("bpy.ops.mesh.extrude_vertices_move*", "modeling/meshes/editing/vertex/extrude_vertices.html#bpy-ops-mesh-extrude-vertices-move"),
("bpy.ops.mesh.mod_weighted_strength*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-mesh-mod-weighted-strength"),
@@ -802,7 +813,6 @@ url_manual_mapping = (
("bpy.ops.mesh.select_interior_faces*", "modeling/meshes/selecting/all_by_trait.html#bpy-ops-mesh-select-interior-faces"),
("bpy.ops.mesh.select_similar_region*", "modeling/meshes/selecting/similar.html#bpy-ops-mesh-select-similar-region"),
("bpy.ops.mesh.tris_convert_to_quads*", "modeling/meshes/editing/face/triangles_quads.html#bpy-ops-mesh-tris-convert-to-quads"),
- ("bpy.ops.node.active_preview_toggle*", "modeling/geometry_nodes/introduction.html#bpy-ops-node-active-preview-toggle"),
("bpy.ops.object.datalayout_transfer*", "scene_layout/object/editing/link_transfer/transfer_mesh_data_layout.html#bpy-ops-object-datalayout-transfer"),
("bpy.ops.object.multires_base_apply*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-base-apply"),
("bpy.ops.object.randomize_transform*", "scene_layout/object/editing/transform/randomize.html#bpy-ops-object-randomize-transform"),
@@ -872,6 +882,7 @@ url_manual_mapping = (
("bpy.types.volumedisplay.slice_axis*", "modeling/volumes/properties.html#bpy-types-volumedisplay-slice-axis"),
("bpy.ops.anim.channels_clean_empty*", "editors/nla/editing.html#bpy-ops-anim-channels-clean-empty"),
("bpy.ops.armature.select_hierarchy*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-hierarchy"),
+ ("bpy.ops.armature.switch_direction*", "animation/armatures/bones/editing/switch_direction.html#bpy-ops-armature-switch-direction"),
("bpy.ops.clip.apply_solution_scale*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-apply-solution-scale"),
("bpy.ops.clip.set_center_principal*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-set-center-principal"),
("bpy.ops.clip.setup_tracking_scene*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-setup-tracking-scene"),
@@ -925,7 +936,9 @@ url_manual_mapping = (
("bpy.types.functionnodeinputstring*", "modeling/geometry_nodes/input/string.html#bpy-types-functionnodeinputstring"),
("bpy.types.functionnodeinputvector*", "modeling/geometry_nodes/input/vector.html#bpy-types-functionnodeinputvector"),
("bpy.types.functionnoderandomfloat*", "modeling/geometry_nodes/input/random_float.html#bpy-types-functionnoderandomfloat"),
+ ("bpy.types.geometrynodecurvecircle*", "modeling/geometry_nodes/curve_primitives/circle.html#bpy-types-geometrynodecurvecircle"),
("bpy.types.geometrynodecurvelength*", "modeling/geometry_nodes/curve/curve_length.html#bpy-types-geometrynodecurvelength"),
+ ("bpy.types.geometrynodecurvespiral*", "modeling/geometry_nodes/curve_primitives/spiral.html#bpy-types-geometrynodecurvespiral"),
("bpy.types.geometrynodecurvetomesh*", "modeling/geometry_nodes/curve/curve_to_mesh.html#bpy-types-geometrynodecurvetomesh"),
("bpy.types.geometrynodemeshtocurve*", "modeling/geometry_nodes/curve/mesh_to_curve.html#bpy-types-geometrynodemeshtocurve"),
("bpy.types.geometrynodepointrotate*", "modeling/geometry_nodes/point/point_rotate.html#bpy-types-geometrynodepointrotate"),
@@ -989,6 +1002,7 @@ url_manual_mapping = (
("bpy.ops.sequencer.select_handles*", "video_editing/sequencer/selecting.html#bpy-ops-sequencer-select-handles"),
("bpy.ops.uv.average_islands_scale*", "modeling/meshes/uv/editing.html#bpy-ops-uv-average-islands-scale"),
("bpy.ops.view3d.blenderkit_search*", "addons/3d_view/blenderkit.html#bpy-ops-view3d-blenderkit-search"),
+ ("bpy.types.armature.axes_position*", "animation/armatures/properties/display.html#bpy-types-armature-axes-position"),
("bpy.types.armature.pose_position*", "animation/armatures/properties/skeleton.html#bpy-types-armature-pose-position"),
("bpy.types.bakesettings.use_clear*", "render/cycles/baking.html#bpy-types-bakesettings-use-clear"),
("bpy.types.bone.envelope_distance*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-envelope-distance"),
@@ -1024,6 +1038,7 @@ url_manual_mapping = (
("bpy.types.editbone.bbone_scalein*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-scalein"),
("bpy.types.editbone.inherit_scale*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-inherit-scale"),
("bpy.types.geometrynodeconvexhull*", "modeling/geometry_nodes/geometry/convex_hull.html#bpy-types-geometrynodeconvexhull"),
+ ("bpy.types.geometrynodefloattoint*", "modeling/geometry_nodes/utilities/float_to_int.html#bpy-types-geometrynodefloattoint"),
("bpy.types.geometrynodeisviewport*", "modeling/geometry_nodes/input/is_viewport.html#bpy-types-geometrynodeisviewport"),
("bpy.types.geometrynodemeshcircle*", "modeling/geometry_nodes/mesh_primitives/circle.html#bpy-types-geometrynodemeshcircle"),
("bpy.types.geometrynodeobjectinfo*", "modeling/geometry_nodes/input/object_info.html#bpy-types-geometrynodeobjectinfo"),
@@ -1051,6 +1066,8 @@ url_manual_mapping = (
("bpy.types.volumerender.step_size*", "modeling/volumes/properties.html#bpy-types-volumerender-step-size"),
("bpy.types.weightednormalmodifier*", "modeling/modifiers/modify/weighted_normal.html#bpy-types-weightednormalmodifier"),
("bpy.ops.armature.autoside_names*", "animation/armatures/bones/editing/naming.html#bpy-ops-armature-autoside-names"),
+ ("bpy.ops.armature.calculate_roll*", "animation/armatures/bones/editing/bone_roll.html#bpy-ops-armature-calculate-roll"),
+ ("bpy.ops.armature.duplicate_move*", "animation/armatures/bones/editing/duplicate.html#bpy-ops-armature-duplicate-move"),
("bpy.ops.armature.select_similar*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-similar"),
("bpy.ops.clip.create_plane_track*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-create-plane-track"),
("bpy.ops.curve.spline_weight_set*", "modeling/curves/editing/other.html#bpy-ops-curve-spline-weight-set"),
@@ -1099,6 +1116,7 @@ url_manual_mapping = (
("bpy.ops.wm.operator_cheat_sheet*", "advanced/operators.html#bpy-ops-wm-operator-cheat-sheet"),
("bpy.ops.wm.previews_batch_clear*", "files/blend/previews.html#bpy-ops-wm-previews-batch-clear"),
("bpy.ops.wm.recover_last_session*", "files/blend/open_save.html#bpy-ops-wm-recover-last-session"),
+ ("bpy.types.armature.display_type*", "animation/armatures/properties/display.html#bpy-types-armature-display-type"),
("bpy.types.armature.use_mirror_x*", "animation/armatures/bones/tools/tool_settings.html#bpy-types-armature-use-mirror-x"),
("bpy.types.bakesettings.normal_b*", "render/cycles/baking.html#bpy-types-bakesettings-normal-b"),
("bpy.types.bakesettings.normal_g*", "render/cycles/baking.html#bpy-types-bakesettings-normal-g"),
@@ -1127,8 +1145,10 @@ url_manual_mapping = (
("bpy.types.editbone.bbone_rollin*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-rollin"),
("bpy.types.fluideffectorsettings*", "physics/fluid/type/effector.html#bpy-types-fluideffectorsettings"),
("bpy.types.followtrackconstraint*", "animation/constraints/motion_tracking/follow_track.html#bpy-types-followtrackconstraint"),
+ ("bpy.types.geometrynodecurveline*", "modeling/geometry_nodes/curve_primitives/line.html#bpy-types-geometrynodecurveline"),
+ ("bpy.types.geometrynodecurvestar*", "modeling/geometry_nodes/curve_primitives/star.html#bpy-types-geometrynodecurvestar"),
+ ("bpy.types.geometrynodecurvetrim*", "modeling/geometry_nodes/curve/curve_trim.html#bpy-types-geometrynodecurvetrim"),
("bpy.types.geometrynodeedgesplit*", "modeling/geometry_nodes/mesh/edge_split.html#bpy-types-geometrynodeedgesplit"),
- ("bpy.types.geometrynodesubdivide*", "modeling/geometry_nodes/mesh/subdivide.html#bpy-types-geometrynodesubdivide"),
("bpy.types.geometrynodetransform*", "modeling/geometry_nodes/geometry/transform.html#bpy-types-geometrynodetransform"),
("bpy.types.gpencilsculptsettings*", "grease_pencil/properties/index.html#bpy-types-gpencilsculptsettings"),
("bpy.types.light.cutoff_distance*", "render/eevee/lighting.html#bpy-types-light-cutoff-distance"),
@@ -1247,6 +1267,8 @@ url_manual_mapping = (
("bpy.types.volumetomeshmodifier*", "modeling/modifiers/generate/volume_to_mesh.html#bpy-types-volumetomeshmodifier"),
("bpy.types.whitebalancemodifier*", "video_editing/sequencer/sidebar/modifiers.html#bpy-types-whitebalancemodifier"),
("bpy.ops.anim.channels_ungroup*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-ungroup"),
+ ("bpy.ops.armature.extrude_move*", "animation/armatures/bones/editing/extrude.html#bpy-ops-armature-extrude-move"),
+ ("bpy.ops.armature.parent_clear*", "animation/armatures/bones/editing/parenting.html#bpy-ops-armature-parent-clear"),
("bpy.ops.clip.clear_track_path*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-clear-track-path"),
("bpy.ops.clip.set_scene_frames*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-set-scene-frames"),
("bpy.ops.curve.handle_type_set*", "modeling/curves/editing/control_points.html#bpy-ops-curve-handle-type-set"),
@@ -1424,6 +1446,7 @@ url_manual_mapping = (
("bpy.types.freestylelinestyle*", "render/freestyle/parameter_editor/line_style/index.html#bpy-types-freestylelinestyle"),
("bpy.types.gammacrosssequence*", "video_editing/sequencer/strips/transitions/gamma_cross.html#bpy-types-gammacrosssequence"),
("bpy.types.geometrynodeswitch*", "modeling/geometry_nodes/utilities/switch.html#bpy-types-geometrynodeswitch"),
+ ("bpy.types.geometrynodeviewer*", "modeling/geometry_nodes/output/viewer.html#bpy-types-geometrynodeviewer"),
("bpy.types.gpencilsculptguide*", "grease_pencil/modes/draw/guides.html#bpy-types-gpencilsculptguide"),
("bpy.types.huecorrectmodifier*", "video_editing/sequencer/sidebar/modifiers.html#bpy-types-huecorrectmodifier"),
("bpy.types.imagepaint.stencil*", "sculpt_paint/texture_paint/tool_settings/mask.html#bpy-types-imagepaint-stencil"),
@@ -1462,7 +1485,9 @@ url_manual_mapping = (
("bpy.ops.anim.channels_group*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-group"),
("bpy.ops.anim.keyframe_clear*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-clear"),
("bpy.ops.armature.flip_names*", "animation/armatures/bones/editing/naming.html#bpy-ops-armature-flip-names"),
+ ("bpy.ops.armature.parent_set*", "animation/armatures/bones/editing/parenting.html#bpy-ops-armature-parent-set"),
("bpy.ops.armature.select_all*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-all"),
+ ("bpy.ops.armature.symmetrize*", "animation/armatures/bones/editing/symmetrize.html#bpy-ops-armature-symmetrize"),
("bpy.ops.clip.average_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-average-tracks"),
("bpy.ops.clip.refine_markers*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-refine-markers"),
("bpy.ops.clip.select_grouped*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-select-grouped"),
@@ -1501,6 +1526,8 @@ url_manual_mapping = (
("bpy.ops.object.shade_smooth*", "scene_layout/object/editing/shading.html#bpy-ops-object-shade-smooth"),
("bpy.ops.object.voxel_remesh*", "modeling/meshes/retopology.html#bpy-ops-object-voxel-remesh"),
("bpy.ops.pose.armature_apply*", "animation/armatures/posing/editing/apply.html#bpy-ops-pose-armature-apply"),
+ ("bpy.ops.pose.group_deselect*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-deselect"),
+ ("bpy.ops.pose.group_unassign*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-unassign"),
("bpy.ops.pose.select_grouped*", "animation/armatures/posing/selecting.html#bpy-ops-pose-select-grouped"),
("bpy.ops.poselib.pose_remove*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-pose-remove"),
("bpy.ops.poselib.pose_rename*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-pose-rename"),
@@ -1574,6 +1601,7 @@ url_manual_mapping = (
("bpy.types.wireframemodifier*", "modeling/modifiers/generate/wireframe.html#bpy-types-wireframemodifier"),
("bpy.types.worldmistsettings*", "render/cycles/world_settings.html#bpy-types-worldmistsettings"),
("bpy.ops.anim.channels_move*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-move"),
+ ("bpy.ops.armature.subdivide*", "animation/armatures/bones/editing/subdivide.html#bpy-ops-armature-subdivide"),
("bpy.ops.buttons.toggle_pin*", "editors/properties_editor.html#bpy-ops-buttons-toggle-pin"),
("bpy.ops.clip.filter_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-filter-tracks"),
("bpy.ops.clip.select_circle*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-select-circle"),
@@ -1675,6 +1703,8 @@ url_manual_mapping = (
("bpy.types.texturenodegroup*", "editors/texture_node/types/groups.html#bpy-types-texturenodegroup"),
("bpy.types.texturenodeimage*", "editors/texture_node/types/input/image.html#bpy-types-texturenodeimage"),
("bpy.types.viewlayer.use_ao*", "render/layers/introduction.html#bpy-types-viewlayer-use-ao"),
+ ("bpy.ops.armature.dissolve*", "animation/armatures/bones/editing/delete.html#bpy-ops-armature-dissolve"),
+ ("bpy.ops.armature.separate*", "animation/armatures/bones/editing/separate_bones.html#bpy-ops-armature-separate"),
("bpy.ops.clip.clean_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-clean-tracks"),
("bpy.ops.clip.delete_track*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-delete-track"),
("bpy.ops.clip.solve_camera*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-solve-camera"),
@@ -1703,6 +1733,8 @@ url_manual_mapping = (
("bpy.ops.object.proxy_make*", "files/linked_libraries/library_proxies.html#bpy-ops-object-proxy-make"),
("bpy.ops.object.select_all*", "scene_layout/object/selecting.html#bpy-ops-object-select-all"),
("bpy.ops.object.shade_flat*", "scene_layout/object/editing/shading.html#bpy-ops-object-shade-flat"),
+ ("bpy.ops.pose.group_assign*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-assign"),
+ ("bpy.ops.pose.group_select*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-select"),
("bpy.ops.poselib.pose_move*", "animation/armatures/properties/pose_library.html#bpy-ops-poselib-pose-move"),
("bpy.ops.preferences.addon*", "editors/preferences/addons.html#bpy-ops-preferences-addon"),
("bpy.ops.scene.light_cache*", "render/eevee/render_settings/indirect_lighting.html#bpy-ops-scene-light-cache"),
@@ -1872,6 +1904,7 @@ url_manual_mapping = (
("bpy.ops.wm.owner_enable*", "interface/window_system/workspaces.html#bpy-ops-wm-owner-enable"),
("bpy.ops.wm.redraw_timer*", "advanced/operators.html#bpy-ops-wm-redraw-timer"),
("bpy.types.*light.shadow*", "render/eevee/lighting.html#bpy-types-light-shadow"),
+ ("bpy.types.armature.show*", "animation/armatures/properties/display.html#bpy-types-armature-show"),
("bpy.types.armaturebones*", "animation/armatures/bones/index.html#bpy-types-armaturebones"),
("bpy.types.arraymodifier*", "modeling/modifiers/generate/array.html#bpy-types-arraymodifier"),
("bpy.types.bevelmodifier*", "modeling/modifiers/generate/bevel.html#bpy-types-bevelmodifier"),
@@ -1919,6 +1952,8 @@ url_manual_mapping = (
("bpy.types.volumedisplay*", "modeling/volumes/properties.html#bpy-types-volumedisplay"),
("bpy.types.windowmanager*", "interface/index.html#bpy-types-windowmanager"),
("bpy.ops.*.select_lasso*", "interface/selecting.html#bpy-ops-select-lasso"),
+ ("bpy.ops.armature.align*", "animation/armatures/bones/editing/transform.html#bpy-ops-armature-align"),
+ ("bpy.ops.armature.split*", "animation/armatures/bones/editing/split.html#bpy-ops-armature-split"),
("bpy.ops.clip.set_plane*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-plane"),
("bpy.ops.clip.set_scale*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-scale"),
("bpy.ops.curve.decimate*", "modeling/curves/editing/curve.html#bpy-ops-curve-decimate"),
@@ -1993,6 +2028,7 @@ url_manual_mapping = (
("bpy.types.wavemodifier*", "modeling/modifiers/deform/wave.html#bpy-types-wavemodifier"),
("bpy.types.weldmodifier*", "modeling/modifiers/generate/weld.html#bpy-types-weldmodifier"),
("bpy.types.wipesequence*", "video_editing/sequencer/strips/transitions/wipe.html#bpy-types-wipesequence"),
+ ("bpy.ops.armature.fill*", "animation/armatures/bones/editing/fill_between_joints.html#bpy-ops-armature-fill"),
("bpy.ops.clip.prefetch*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-prefetch"),
("bpy.ops.clip.set_axis*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-axis"),
("bpy.ops.file.pack_all*", "files/blend/packed_data.html#bpy-ops-file-pack-all"),
@@ -2064,6 +2100,7 @@ url_manual_mapping = (
("bpy.ops.uv.mark_seam*", "modeling/meshes/uv/unwrapping/seams.html#bpy-ops-uv-mark-seam"),
("bpy.ops.view3d.ruler*", "editors/3dview/toolbar/measure.html#bpy-ops-view3d-ruler"),
("bpy.types.areaspaces*", "interface/window_system/areas.html#bpy-types-areaspaces"),
+ ("bpy.types.bonegroups*", "animation/armatures/properties/bone_groups.html#bpy-types-bonegroups"),
("bpy.types.bpy_struct*", "files/data_blocks.html#bpy-types-bpy-struct"),
("bpy.types.collection*", "scene_layout/collections/collections.html#bpy-types-collection"),
("bpy.types.compositor*", "compositing/index.html#bpy-types-compositor"),
diff --git a/release/scripts/startup/bl_operators/assets.py b/release/scripts/startup/bl_operators/assets.py
index d2655784afd..c782cd0646e 100644
--- a/release/scripts/startup/bl_operators/assets.py
+++ b/release/scripts/startup/bl_operators/assets.py
@@ -18,7 +18,6 @@
# <pep8 compliant>
from __future__ import annotations
-from pathlib import Path
import bpy
from bpy.types import Operator
diff --git a/release/scripts/startup/bl_operators/geometry_nodes.py b/release/scripts/startup/bl_operators/geometry_nodes.py
index 71ef89a066b..ec2887a1a74 100644
--- a/release/scripts/startup/bl_operators/geometry_nodes.py
+++ b/release/scripts/startup/bl_operators/geometry_nodes.py
@@ -81,7 +81,10 @@ class NewGeometryNodeTreeAssign(Operator):
return geometry_modifier_poll(context)
def execute(self, context):
- modifier = context.object.modifiers.active
+ if context.area.type == 'PROPERTIES':
+ modifier = context.modifier
+ else:
+ modifier = context.object.modifiers.active
if not modifier:
return {'CANCELLED'}
diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py
index bc80500c888..7f5edac4dfb 100644
--- a/release/scripts/startup/bl_operators/rigidbody.py
+++ b/release/scripts/startup/bl_operators/rigidbody.py
@@ -60,17 +60,22 @@ class CopyRigidbodySettings(Operator):
def execute(self, context):
obj_act = context.object
- view_layer = context.view_layer
- # deselect all but mesh objects
+ # Deselect all non mesh objects and objects that
+ # already have a rigid body attached.
+ rb_objects = []
for o in context.selected_objects:
- if o.type != 'MESH':
+ if o.type != 'MESH' or o.rigid_body is not None:
o.select_set(False)
- elif o.rigid_body is None:
- # Add rigidbody to object!
- view_layer.objects.active = o
- bpy.ops.rigidbody.object_add()
- view_layer.objects.active = obj_act
+ if o.rigid_body is not None:
+ rb_objects.append(o)
+
+ bpy.ops.rigidbody.objects_add()
+
+ # Ensure that the rigid body objects
+ # we've de-selected are selected again.
+ for o in rb_objects:
+ o.select_set(True)
objects = context.selected_objects
if objects:
diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py
index 48a02a4c5c6..8f678896e61 100644
--- a/release/scripts/startup/bl_operators/sequencer.py
+++ b/release/scripts/startup/bl_operators/sequencer.py
@@ -108,14 +108,13 @@ class SequencerSplitMulticam(Operator):
if s.multicam_source == camera or camera >= s.channel:
return {'FINISHED'}
- if not s.select:
- s.select = True
-
cfra = context.scene.frame_current
- bpy.ops.sequencer.split(frame=cfra, type='SOFT', side='RIGHT')
- for s in context.scene.sequence_editor.sequences_all:
- if s.select and s.type == 'MULTICAM' and s.frame_final_start <= cfra and cfra < s.frame_final_end:
- context.scene.sequence_editor.active_strip = s
+ right_strip = s.split(frame=cfra, split_method='SOFT')
+
+ if right_strip:
+ s.select = False
+ right_strip.select = True
+ context.scene.sequence_editor.active_strip = right_strip
context.scene.sequence_editor.active_strip.multicam_source = camera
return {'FINISHED'}
diff --git a/release/scripts/startup/bl_ui/properties_collection.py b/release/scripts/startup/bl_ui/properties_collection.py
index b51d7157c06..3f7c0735eec 100644
--- a/release/scripts/startup/bl_ui/properties_collection.py
+++ b/release/scripts/startup/bl_ui/properties_collection.py
@@ -86,12 +86,15 @@ class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
row = layout.row()
row.prop(collection, "lineart_usage")
- layout.prop(collection, "lineart_use_intersection_mask")
+ layout.prop(collection, "lineart_use_intersection_mask", text="Collection Mask")
- row = layout.row(align=True, heading="Masks")
- row.active = collection.lineart_use_intersection_mask
+ col = layout.column(align=True)
+ col.active = collection.lineart_use_intersection_mask
+ row = col.row(align=True, heading="Masks")
for i in range(8):
- row.prop(collection, "lineart_intersection_mask", index=i, text=str(i), toggle=True)
+ row.prop(collection, "lineart_intersection_mask", index=i, text=" ", toggle=True)
+ if i == 3:
+ row = col.row(align=True)
classes = (
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 7f4328bb25a..d9ad094ac4f 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -646,7 +646,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
if len(colliding_names) == 0:
return
- layout.label(text="Name Collisions: {}".format(", ".join(colliding_names)), icon='INFO')
+ layout.label(text="Name collisions: {}".format(", ".join(colliding_names)), icon='ERROR')
classes = (
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index b217e33de12..1c7f3639f0a 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -291,18 +291,18 @@ class MATERIAL_PT_lineart(MaterialButtonsPanel, Panel):
mat = context.material
lineart = mat.lineart
- layout.prop(lineart, "use_material_mask")
+ layout.prop(lineart, "use_material_mask", text="Material Mask")
- row = layout.row(align=True, heading="Masks")
- row.active = lineart.use_material_mask
+ col = layout.column(align=True)
+ col.active = lineart.use_material_mask
+ row = col.row(align=True, heading="Masks")
for i in range(8):
- row.prop(lineart, "use_material_mask_bits", text=str(i), index=i, toggle=True)
+ row.prop(lineart, "use_material_mask_bits", text=" ", index=i, toggle=True)
+ if i == 3:
+ row = col.row(align=True)
row = layout.row(align=True, heading="Custom Occlusion")
- row.prop(lineart, "use_mat_occlusion", text="")
- sub = row.row(align=False)
- sub.active = lineart.use_mat_occlusion
- sub.prop(lineart, "mat_occlusion", slider=True, text="Levels")
+ row.prop(lineart, "mat_occlusion", text="Levels")
classes = (
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 55714e0b0a5..47b04f9cdbc 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -1156,14 +1156,19 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
flow.prop(strip, "use_only_boost")
elif strip_type == 'SPEED':
- layout.prop(strip, "use_default_fade", text="Stretch to Input Strip Length")
- if not strip.use_default_fade:
- layout.prop(strip, "use_as_speed")
- if strip.use_as_speed:
- layout.prop(strip, "speed_factor")
- else:
- layout.prop(strip, "speed_factor", text="Frame Number")
- layout.prop(strip, "use_scale_to_length")
+ col = layout.column(align=True)
+ col.prop(strip, "speed_control", text="Speed Control")
+ if strip.speed_control == "MULTIPLY":
+ col.prop(strip, "speed_factor", text=" ")
+ elif strip.speed_control == "LENGTH":
+ col.prop(strip, "speed_length", text=" ")
+ elif strip.speed_control == "FRAME_NUMBER":
+ col.prop(strip, "speed_frame_number", text=" ")
+
+ row = layout.row(align=True)
+ row.enabled = strip.speed_control != "STRETCH"
+ row = layout.row(align=True, heading="Interpolation")
+ row.prop(strip, "use_frame_interpolate", text="")
elif strip_type == 'TRANSFORM':
col = layout.column()
@@ -1233,11 +1238,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
layout.prop(strip, "wrap_width", text="Wrap Width")
col = layout.column(align=True)
- if strip_type == 'SPEED':
- col.prop(strip, "multiply_speed")
- col.prop(strip, "use_frame_interpolate")
-
- elif strip_type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'OVER_DROP'}:
+ if strip_type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'OVER_DROP'}:
col.prop(strip, "use_default_fade", text="Default Fade")
if not strip.use_default_fade:
col.prop(strip, "effect_fader", text="Effect Fader")
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 2b0ac6046bc..f130a79ede0 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -544,8 +544,10 @@ geometry_node_categories = [
NodeItem("GeometryNodeMeshToCurve"),
NodeItem("GeometryNodeCurveToPoints"),
NodeItem("GeometryNodeCurveEndpoints"),
+ NodeItem("GeometryNodeCurveTrim"),
NodeItem("GeometryNodeCurveLength"),
NodeItem("GeometryNodeCurveReverse"),
+ NodeItem("GeometryNodeCurveSetHandles"),
]),
GeometryNodeCategory("GEO_PRIMITIVES_CURVE", "Curve Primitives", items=[
NodeItem("GeometryNodeCurvePrimitiveLine"),
diff --git a/release/scripts/templates_py/custom_nodes.py b/release/scripts/templates_py/custom_nodes.py
index ca9534e7cd3..fba94e23d0d 100644
--- a/release/scripts/templates_py/custom_nodes.py
+++ b/release/scripts/templates_py/custom_nodes.py
@@ -147,7 +147,7 @@ node_categories = [
MyNodeCategory('OTHERNODES', "Other Nodes", items=[
# the node item can have additional settings,
# which are applied to new nodes
- # NB: settings values are stored as string expressions,
+ # NOTE: settings values are stored as string expressions,
# for this reason they should be converted to strings using repr()
NodeItem("CustomNodeType", label="Node A", settings={
"my_string_prop": repr("Lorem ipsum dolor sit amet"),
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 904b7bb8718..e3954e134da 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -158,7 +158,7 @@ struct DerivedMesh {
int (*getNumPolys)(DerivedMesh *dm);
/** Copy a single vert/edge/tessellated face from the derived mesh into
- * ``*r_{vert/edge/face}``. note that the current implementation
+ * `*r_{vert/edge/face}`. note that the current implementation
* of this function can be quite slow, iterating over all
* elements (editmesh)
*/
diff --git a/source/blender/blenkernel/BKE_action.hh b/source/blender/blenkernel/BKE_action.hh
new file mode 100644
index 00000000000..b9f106d367e
--- /dev/null
+++ b/source/blender/blenkernel/BKE_action.hh
@@ -0,0 +1,35 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+#ifndef __cplusplus
+# error This is a C++ only header.
+#endif
+
+#include "BLI_function_ref.hh"
+
+struct bAction;
+struct FCurve;
+
+namespace blender::bke {
+
+using FoundFCurveCallback = blender::FunctionRef<void(FCurve *fcurve, const char *bone_name)>;
+void BKE_action_find_fcurves_with_bones(const bAction *action, FoundFCurveCallback callback);
+
+}; // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_armature.hh b/source/blender/blenkernel/BKE_armature.hh
new file mode 100644
index 00000000000..e3f5b528156
--- /dev/null
+++ b/source/blender/blenkernel/BKE_armature.hh
@@ -0,0 +1,48 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+#ifndef __cplusplus
+# error This is a C++ only header.
+#endif
+
+#include "BKE_armature.h"
+
+#include "BLI_function_ref.hh"
+#include "BLI_set.hh"
+
+namespace blender::bke {
+
+struct SelectedBonesResult {
+ bool all_bones_selected = true;
+ bool no_bones_selected = true;
+};
+
+using SelectedBoneCallback = blender::FunctionRef<void(Bone *bone)>;
+SelectedBonesResult BKE_armature_find_selected_bones(const bArmature *armature,
+ SelectedBoneCallback callback);
+
+using BoneNameSet = blender::Set<std::string>;
+/**
+ * Return a set of names of the selected bones. An empty set means "ignore bone
+ * selection", which either means all bones are selected, or none are.
+ */
+BoneNameSet BKE_armature_find_selected_bone_names(const bArmature *armature);
+
+}; // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 28903c4787c..28be2c0f30d 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 12
+#define BLENDER_FILE_SUBVERSION 13
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index a0e3d5dc142..dbf285feb92 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -39,14 +39,14 @@ struct Scene;
#define DO_INLINE MALWAYS_INLINE
-/* goal defines */
+/* Goal defines. */
#define SOFTGOALSNAP 0.999f
/* This is approximately the smallest number that can be
* represented by a float, given its precision. */
#define ALMOST_ZERO FLT_EPSILON
-/* Bits to or into the ClothVertex.flags. */
+/* Bits to or into the #ClothVertex.flags. */
typedef enum eClothVertexFlag {
CLOTH_VERT_FLAG_PINNED = (1 << 0),
CLOTH_VERT_FLAG_NOSELFCOLL = (1 << 1), /* vertex NOT used for self collisions */
@@ -150,7 +150,7 @@ typedef struct ClothSpring {
float target[3];
} ClothSpring;
-// some macro enhancements for vector treatment
+/* Some macro enhancements for vector treatment. */
#define VECSUBADDSS(v1, v2, aS, v3, bS) \
{ \
*(v1) -= *(v2)*aS + *(v3)*bS; \
@@ -211,9 +211,8 @@ typedef enum {
CLOTH_SPRING_FLAG_NEEDED = (1 << 2), /* Springs has values to be applied. */
} CLOTH_SPRINGS_FLAGS;
-/////////////////////////////////////////////////
-// collision.c
-////////////////////////////////////////////////
+/* -------------------------------------------------------------------- */
+/* collision.c */
struct CollPair;
@@ -225,20 +224,17 @@ typedef struct ColliderContacts {
int totcollisions;
} ColliderContacts;
-// needed for implicit.c
+/* needed for implicit.c */
int cloth_bvh_collision(struct Depsgraph *depsgraph,
struct Object *ob,
struct ClothModifierData *clmd,
float step,
float dt);
-////////////////////////////////////////////////
+/* -------------------------------------------------------------------- */
+/* cloth.c */
-/////////////////////////////////////////////////
-// cloth.c
-////////////////////////////////////////////////
-
-// needed for modifier.c
+/* Needed for modifier.c */
void cloth_free_modifier_extern(struct ClothModifierData *clmd);
void cloth_free_modifier(struct ClothModifierData *clmd);
void clothModifier_do(struct ClothModifierData *clmd,
@@ -250,18 +246,16 @@ void clothModifier_do(struct ClothModifierData *clmd,
int cloth_uses_vgroup(struct ClothModifierData *clmd);
-// needed for collision.c
+/* Needed for collision.c */
void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving, bool self);
-// needed for button_object.c
+/* Needed for button_object.c */
void cloth_clear_cache(struct Object *ob, struct ClothModifierData *clmd, float framenr);
void cloth_parallel_transport_hair_frame(float mat[3][3],
const float dir_old[3],
const float dir_new[3]);
-////////////////////////////////////////////////
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index c7c5f59cab2..5e474c0c5ac 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -97,7 +97,6 @@ struct BoundBox *BKE_curve_boundbox_get(struct Object *ob);
void BKE_curve_texspace_calc(struct Curve *cu);
void BKE_curve_texspace_ensure(struct Curve *cu);
-void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_size[3]);
bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]);
bool BKE_curve_center_median(struct Curve *cu, float cent[3]);
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index c4db8ee925e..7a44553c565 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -501,7 +501,7 @@ enum {
CD_FAKE = 1 << 8,
/* Vertices. */
- CD_FAKE_MDEFORMVERT = CD_FAKE | CD_MDEFORMVERT, /* *sigh* due to how vgroups are stored :( . */
+ CD_FAKE_MDEFORMVERT = CD_FAKE | CD_MDEFORMVERT, /* *sigh* due to how vgroups are stored :(. */
CD_FAKE_SHAPEKEY = CD_FAKE |
CD_SHAPEKEY, /* Not available as real CD layer in non-bmesh context. */
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 12560ebed7b..e3be9cd8ef8 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -126,8 +126,8 @@ void BKE_mesh_eval_delete(struct Mesh *mesh_eval);
struct Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference);
/* These functions construct a new Mesh,
- * contrary to BKE_mesh_from_nurbs which modifies ob itself. */
-struct Mesh *BKE_mesh_new_nomain_from_curve(struct Object *ob);
+ * contrary to BKE_mesh_to_curve_nurblist which modifies ob itself. */
+struct Mesh *BKE_mesh_new_nomain_from_curve(const struct Object *ob);
struct Mesh *BKE_mesh_new_nomain_from_curve_displist(const struct Object *ob,
const struct ListBase *dispbase);
@@ -143,32 +143,11 @@ int BKE_mesh_mface_index_validate(struct MFace *mface,
struct Mesh *BKE_mesh_from_object(struct Object *ob);
void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me);
void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me);
-int BKE_mesh_nurbs_to_mdata(struct Object *ob,
- struct MVert **r_allvert,
- int *r_totvert,
- struct MEdge **r_alledge,
- int *r_totedge,
- struct MLoop **r_allloop,
- struct MPoly **r_allpoly,
- int *r_totloop,
- int *r_totpoly);
-int BKE_mesh_nurbs_displist_to_mdata(const struct Object *ob,
- const struct ListBase *dispbase,
- struct MVert **r_allvert,
- int *r_totvert,
- struct MEdge **r_alledge,
- int *r_totedge,
- struct MLoop **r_allloop,
- struct MPoly **r_allpoly,
- struct MLoopUV **r_alluv,
- int *r_totloop,
- int *r_totpoly);
void BKE_mesh_from_nurbs_displist(struct Main *bmain,
struct Object *ob,
struct ListBase *dispbase,
const char *obdata_name,
bool temporary);
-void BKE_mesh_from_nurbs(struct Main *bmain, struct Object *ob);
void BKE_mesh_to_curve_nurblist(const struct Mesh *me,
struct ListBase *nurblist,
const int edge_users_test);
@@ -420,6 +399,12 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
const char data_type);
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr);
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr);
+
+void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr,
+ MLoopNorSpaceArray *lnors_spacearr_tls);
+void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr,
+ MLoopNorSpaceArray *lnors_spacearr_tls);
+
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr);
void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
const float lnor[3],
diff --git a/source/blender/blenkernel/BKE_mesh_iterators.h b/source/blender/blenkernel/BKE_mesh_iterators.h
index 103e7b5b78f..a65f25ee182 100644
--- a/source/blender/blenkernel/BKE_mesh_iterators.h
+++ b/source/blender/blenkernel/BKE_mesh_iterators.h
@@ -41,6 +41,7 @@ void BKE_mesh_foreach_mapped_vert(struct Mesh *mesh,
MeshForeachFlag flag);
void BKE_mesh_foreach_mapped_edge(
struct Mesh *mesh,
+ int tot_edges,
void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
void *userData);
void BKE_mesh_foreach_mapped_loop(struct Mesh *mesh,
diff --git a/source/blender/blenkernel/BKE_mesh_types.h b/source/blender/blenkernel/BKE_mesh_types.h
index b223d3872ff..aed8c44a031 100644
--- a/source/blender/blenkernel/BKE_mesh_types.h
+++ b/source/blender/blenkernel/BKE_mesh_types.h
@@ -27,7 +27,6 @@ typedef enum eMeshBatchDirtyMode {
BKE_MESH_BATCH_DIRTY_SELECT,
BKE_MESH_BATCH_DIRTY_SELECT_PAINT,
BKE_MESH_BATCH_DIRTY_SHADING,
- BKE_MESH_BATCH_DIRTY_DEFORM,
BKE_MESH_BATCH_DIRTY_UVEDIT_ALL,
BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT,
} eMeshBatchDirtyMode;
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 63b11a194ff..cecb3118038 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1464,6 +1464,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_CURVE_PRIMITIVE_LINE 1068
#define GEO_NODE_CURVE_ENDPOINTS 1069
#define GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL 1070
+#define GEO_NODE_CURVE_TRIM 1071
+#define GEO_NODE_CURVE_SET_HANDLES 1072
/** \} */
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index a16822fd7dd..4724e6dfab6 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -374,10 +374,6 @@ void BKE_object_runtime_free_data(struct Object *object);
void BKE_object_batch_cache_dirty_tag(struct Object *ob);
void BKE_object_data_batch_cache_dirty_tag(struct ID *object_data);
-void BKE_object_data_eval_batch_cache_dirty_tag(struct Depsgraph *depsgraph,
- struct ID *object_data);
-void BKE_object_data_eval_batch_cache_deform_tag(struct Depsgraph *depsgraph,
- struct ID *object_data);
/* this function returns a superset of the scenes selection based on relationships */
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index f85e62768f7..53485ecbd6b 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -306,6 +306,7 @@ class BezierSpline final : public Spline {
blender::MutableSpan<HandleType> handle_types_right();
blender::Span<blender::float3> handle_positions_right() const;
blender::MutableSpan<blender::float3> handle_positions_right();
+ void ensure_auto_handles() const;
void translate(const blender::float3 &translation) override;
void transform(const blender::float4x4 &matrix) override;
@@ -353,8 +354,6 @@ class BezierSpline final : public Spline {
void correct_end_tangents() const final;
void copy_settings(Spline &dst) const final;
void copy_data(Spline &dst) const final;
-
- void ensure_auto_handles() const;
};
/**
@@ -544,6 +543,7 @@ struct CurveEval {
blender::Span<SplinePtr> splines() const;
blender::MutableSpan<SplinePtr> splines();
+ bool has_spline_with_type(const Spline::Type type) const;
void resize(const int size);
void add_spline(SplinePtr spline);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 2c25b940578..e8f31ae72c0 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -69,6 +69,7 @@ set(SRC
intern/CCGSubSurf_util.c
intern/DerivedMesh.cc
intern/action.c
+ intern/action_bones.cc
intern/action_mirror.c
intern/addon.c
intern/anim_data.c
@@ -77,6 +78,7 @@ set(SRC
intern/anim_visualization.c
intern/appdir.c
intern/armature.c
+ intern/armature_selection.cc
intern/armature_deform.c
intern/armature_pose.cc
intern/armature_update.c
@@ -143,7 +145,7 @@ set(SRC
intern/geometry_set_instances.cc
intern/gpencil.c
intern/gpencil_curve.c
- intern/gpencil_geom.c
+ intern/gpencil_geom.cc
intern/gpencil_modifier.c
intern/hair.c
intern/icons.cc
@@ -287,6 +289,7 @@ set(SRC
BKE_DerivedMesh.h
BKE_action.h
+ BKE_action.hh
BKE_addon.h
BKE_anim_data.h
BKE_anim_path.h
@@ -294,6 +297,7 @@ set(SRC
BKE_animsys.h
BKE_appdir.h
BKE_armature.h
+ BKE_armature.hh
BKE_asset.h
BKE_attribute.h
BKE_attribute_access.hh
diff --git a/source/blender/blenkernel/intern/action_bones.cc b/source/blender/blenkernel/intern/action_bones.cc
new file mode 100644
index 00000000000..b8d185e6a81
--- /dev/null
+++ b/source/blender/blenkernel/intern/action_bones.cc
@@ -0,0 +1,48 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_action.hh"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+
+#include "MEM_guardedalloc.h"
+
+namespace blender::bke {
+
+void BKE_action_find_fcurves_with_bones(const bAction *action, FoundFCurveCallback callback)
+{
+ LISTBASE_FOREACH (FCurve *, fcu, &action->curves) {
+ char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
+ if (!bone_name) {
+ continue;
+ }
+ callback(fcu, bone_name);
+ MEM_freeN(bone_name);
+ }
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 2879a995ad6..ffc060bb64e 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -1947,7 +1947,7 @@ static void nlaevalchan_blendOrcombine(NlaEvalChannelSnapshot *lower_necs,
return;
}
default:
- BLI_assert("Mix mode should've been handled");
+ BLI_assert_msg(0, "Mix mode should've been handled");
}
return;
}
@@ -1960,7 +1960,7 @@ static void nlaevalchan_blendOrcombine(NlaEvalChannelSnapshot *lower_necs,
return;
}
default:
- BLI_assert("Blend mode should've been handled");
+ BLI_assert_msg(0, "Blend mode should've been handled");
}
}
@@ -2110,7 +2110,7 @@ static void nlaevalchan_blendOrcombine_get_inverted_upper_evalchan(
return;
}
default:
- BLI_assert("Mix mode should've been handled");
+ BLI_assert_msg(0, "Mix mode should've been handled");
}
return;
}
@@ -2123,7 +2123,7 @@ static void nlaevalchan_blendOrcombine_get_inverted_upper_evalchan(
return;
}
default:
- BLI_assert("Blend mode should've been handled");
+ BLI_assert_msg(0, "Blend mode should've been handled");
}
}
diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c
index 5e9259f05bb..5f721b49361 100644
--- a/source/blender/blenkernel/intern/armature_deform.c
+++ b/source/blender/blenkernel/intern/armature_deform.c
@@ -501,7 +501,7 @@ static void armature_deform_coords_impl(const Object *ob_arm,
BLI_assert(0);
}
- if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
+ if (BKE_object_supports_vertex_groups(ob_target)) {
/* get the def_nr for the overall armature vertex group if present */
armature_def_nr = BKE_object_defgroup_name_index(ob_target, defgrp_name);
@@ -529,11 +529,9 @@ static void armature_deform_coords_impl(const Object *ob_arm,
dverts_len = gps_target->totpoints;
}
}
- }
- /* get a vertex-deform-index to posechannel array */
- if (deformflag & ARM_DEF_VGROUP) {
- if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
+ /* get a vertex-deform-index to posechannel array */
+ if (deformflag & ARM_DEF_VGROUP) {
/* if we have a Mesh, only use dverts if it has them */
if (em_target) {
cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT);
diff --git a/source/blender/blenkernel/intern/armature_pose.cc b/source/blender/blenkernel/intern/armature_pose.cc
index 09e1c7d6615..a62a32d9633 100644
--- a/source/blender/blenkernel/intern/armature_pose.cc
+++ b/source/blender/blenkernel/intern/armature_pose.cc
@@ -23,8 +23,9 @@
* \ingroup bke
*/
+#include "BKE_action.hh"
#include "BKE_animsys.h"
-#include "BKE_armature.h"
+#include "BKE_armature.hh"
#include "BLI_function_ref.hh"
#include "BLI_set.hh"
@@ -36,14 +37,14 @@
#include "RNA_access.h"
+using namespace blender::bke;
+
namespace {
-using BoneNameSet = blender::Set<std::string>;
using ActionApplier =
blender::FunctionRef<void(PointerRNA *, bAction *, const AnimationEvalContext *)>;
-// Forward declarations.
-BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose);
+/* Forward declarations. */
void pose_apply_disable_fcurves_for_unselected_bones(bAction *action,
const BoneNameSet &selected_bone_names);
void pose_apply_restore_fcurves(bAction *action);
@@ -102,7 +103,7 @@ void pose_apply(struct Object *ob,
}
const bArmature *armature = (bArmature *)ob->data;
- const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(armature, pose);
+ const BoneNameSet selected_bone_names = BKE_armature_find_selected_bone_names(armature);
const bool limit_to_selected_bones = !selected_bone_names.is_empty();
if (limit_to_selected_bones) {
@@ -122,30 +123,6 @@ void pose_apply(struct Object *ob,
}
}
-BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose)
-{
- BoneNameSet selected_bone_names;
- bool all_bones_selected = true;
- bool no_bones_selected = true;
-
- LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
- const bool is_selected = PBONE_SELECTED(armature, pchan->bone);
- all_bones_selected &= is_selected;
- no_bones_selected &= !is_selected;
-
- if (is_selected) {
- /* Bone names are unique, so no need to check for duplicates. */
- selected_bone_names.add_new(pchan->name);
- }
- }
-
- /* If no bones are selected, act as if all are. */
- if (all_bones_selected || no_bones_selected) {
- return BoneNameSet(); /* An empty set means "ignore bone selection". */
- }
- return selected_bone_names;
-}
-
void pose_apply_restore_fcurves(bAction *action)
{
/* TODO(Sybren): Restore the FCurve flags, instead of just erasing the 'disabled' flag. */
@@ -157,24 +134,13 @@ void pose_apply_restore_fcurves(bAction *action)
void pose_apply_disable_fcurves_for_unselected_bones(bAction *action,
const BoneNameSet &selected_bone_names)
{
- LISTBASE_FOREACH (FCurve *, fcu, &action->curves) {
- if (!fcu->rna_path || !strstr(fcu->rna_path, "pose.bones[")) {
- continue;
- }
-
- /* Get bone name, and check if this bone is selected. */
- char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
- if (!bone_name) {
- continue;
- }
- const bool is_selected = selected_bone_names.contains(bone_name);
- MEM_freeN(bone_name);
- if (is_selected) {
- continue;
+ auto disable_unselected_fcurve = [&](FCurve *fcu, const char *bone_name) {
+ const bool is_bone_selected = selected_bone_names.contains(bone_name);
+ if (!is_bone_selected) {
+ fcu->flag |= FCURVE_DISABLED;
}
-
- fcu->flag |= FCURVE_DISABLED;
- }
+ };
+ BKE_action_find_fcurves_with_bones(action, disable_unselected_fcurve);
}
} // namespace
diff --git a/source/blender/blenkernel/intern/armature_selection.cc b/source/blender/blenkernel/intern/armature_selection.cc
new file mode 100644
index 00000000000..c7dbc9d05b1
--- /dev/null
+++ b/source/blender/blenkernel/intern/armature_selection.cc
@@ -0,0 +1,78 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_armature.hh"
+
+#include "BLI_listbase.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+
+namespace blender::bke {
+
+namespace {
+
+void find_selected_bones__visit_bone(const bArmature *armature,
+ SelectedBoneCallback callback,
+ SelectedBonesResult &result,
+ Bone *bone)
+{
+ const bool is_selected = PBONE_SELECTED(armature, bone);
+ result.all_bones_selected &= is_selected;
+ result.no_bones_selected &= !is_selected;
+
+ if (is_selected) {
+ callback(bone);
+ }
+
+ LISTBASE_FOREACH (Bone *, child_bone, &bone->childbase) {
+ find_selected_bones__visit_bone(armature, callback, result, child_bone);
+ }
+}
+} // namespace
+
+SelectedBonesResult BKE_armature_find_selected_bones(const bArmature *armature,
+ SelectedBoneCallback callback)
+{
+ SelectedBonesResult result;
+ LISTBASE_FOREACH (Bone *, root_bone, &armature->bonebase) {
+ find_selected_bones__visit_bone(armature, callback, result, root_bone);
+ }
+
+ return result;
+}
+
+BoneNameSet BKE_armature_find_selected_bone_names(const bArmature *armature)
+{
+ BoneNameSet selected_bone_names;
+
+ /* Iterate over the selected bones to fill the set of bone names. */
+ auto callback = [&](Bone *bone) { selected_bone_names.add(bone->name); };
+ SelectedBonesResult result = BKE_armature_find_selected_bones(armature, callback);
+
+ /* If no bones are selected, act as if all are. */
+ if (result.all_bones_selected || result.no_bones_selected) {
+ return BoneNameSet();
+ }
+
+ return selected_bone_names;
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/armature_test.cc b/source/blender/blenkernel/intern/armature_test.cc
index 589337d9d01..47853deec3e 100644
--- a/source/blender/blenkernel/intern/armature_test.cc
+++ b/source/blender/blenkernel/intern/armature_test.cc
@@ -17,10 +17,13 @@
* All rights reserved.
*/
-#include "BKE_armature.h"
+#include "BKE_armature.hh"
+#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "DNA_armature_types.h"
+
#include "testing/testing.h"
namespace blender::bke::tests {
@@ -157,4 +160,80 @@ TEST(vec_roll_to_mat3_normalized, Rotationmatrix)
}
}
+class BKE_armature_find_selected_bones_test : public testing::Test {
+ protected:
+ bArmature arm;
+ Bone bone1, bone2, bone3;
+
+ void SetUp() override
+ {
+ strcpy(bone1.name, "bone1");
+ strcpy(bone2.name, "bone2");
+ strcpy(bone3.name, "bone3");
+
+ arm.bonebase = {nullptr, nullptr};
+ bone1.childbase = {nullptr, nullptr};
+ bone2.childbase = {nullptr, nullptr};
+ bone3.childbase = {nullptr, nullptr};
+
+ BLI_addtail(&arm.bonebase, &bone1); // bone1 is root bone
+ BLI_addtail(&arm.bonebase, &bone2); // bone2 is root bone
+ BLI_addtail(&bone2.childbase, &bone3); // bone3 has bone2 as parent
+
+ // Make sure the armature & its bones are visible, to make them selectable.
+ arm.layer = bone1.layer = bone2.layer = bone3.layer = 1;
+ }
+};
+
+TEST_F(BKE_armature_find_selected_bones_test, some_bones_selected)
+{
+ bone1.flag = BONE_SELECTED;
+ bone2.flag = 0;
+ bone3.flag = BONE_SELECTED;
+
+ std::vector<Bone *> seen_bones;
+ auto callback = [&](Bone *bone) { seen_bones.push_back(bone); };
+
+ SelectedBonesResult result = BKE_armature_find_selected_bones(&arm, callback);
+
+ ASSERT_EQ(seen_bones.size(), 2) << "Expected 2 selected bones, got " << seen_bones.size();
+ EXPECT_EQ(seen_bones[0], &bone1);
+ EXPECT_EQ(seen_bones[1], &bone3);
+
+ EXPECT_FALSE(result.all_bones_selected); // Bone 2 was not selected.
+ EXPECT_FALSE(result.no_bones_selected); // Bones 1 and 3 were selected.
+}
+
+TEST_F(BKE_armature_find_selected_bones_test, no_bones_selected)
+{
+ bone1.flag = bone2.flag = bone3.flag = 0;
+
+ std::vector<Bone *> seen_bones;
+ auto callback = [&](Bone *bone) { seen_bones.push_back(bone); };
+
+ SelectedBonesResult result = BKE_armature_find_selected_bones(&arm, callback);
+
+ EXPECT_TRUE(seen_bones.empty()) << "Expected no selected bones, got " << seen_bones.size();
+ EXPECT_FALSE(result.all_bones_selected);
+ EXPECT_TRUE(result.no_bones_selected);
+}
+
+TEST_F(BKE_armature_find_selected_bones_test, all_bones_selected)
+{
+ bone1.flag = bone2.flag = bone3.flag = BONE_SELECTED;
+
+ std::vector<Bone *> seen_bones;
+ auto callback = [&](Bone *bone) { seen_bones.push_back(bone); };
+
+ SelectedBonesResult result = BKE_armature_find_selected_bones(&arm, callback);
+
+ ASSERT_EQ(seen_bones.size(), 3) << "Expected 3 selected bones, got " << seen_bones.size();
+ EXPECT_EQ(seen_bones[0], &bone1);
+ EXPECT_EQ(seen_bones[1], &bone2);
+ EXPECT_EQ(seen_bones[2], &bone3);
+
+ EXPECT_TRUE(result.all_bones_selected);
+ EXPECT_FALSE(result.no_bones_selected);
+}
+
} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.c
index ad2be4ffe30..e9444cf88a6 100644
--- a/source/blender/blenkernel/intern/attribute.c
+++ b/source/blender/blenkernel/intern/attribute.c
@@ -39,6 +39,7 @@
#include "BKE_attribute.h"
#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
#include "BKE_hair.h"
#include "BKE_pointcloud.h"
#include "BKE_report.h"
@@ -63,14 +64,28 @@ static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
}
case ID_ME: {
Mesh *mesh = (Mesh *)id;
- info[ATTR_DOMAIN_POINT].customdata = &mesh->vdata;
- info[ATTR_DOMAIN_POINT].length = mesh->totvert;
- info[ATTR_DOMAIN_EDGE].customdata = &mesh->edata;
- info[ATTR_DOMAIN_EDGE].length = mesh->totedge;
- info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata;
- info[ATTR_DOMAIN_CORNER].length = mesh->totloop;
- info[ATTR_DOMAIN_FACE].customdata = &mesh->pdata;
- info[ATTR_DOMAIN_FACE].length = mesh->totpoly;
+ BMEditMesh *em = mesh->edit_mesh;
+ if (em != NULL) {
+ BMesh *bm = em->bm;
+ info[ATTR_DOMAIN_POINT].customdata = &bm->vdata;
+ info[ATTR_DOMAIN_POINT].length = bm->totvert;
+ info[ATTR_DOMAIN_EDGE].customdata = &bm->edata;
+ info[ATTR_DOMAIN_EDGE].length = bm->totedge;
+ info[ATTR_DOMAIN_CORNER].customdata = &bm->ldata;
+ info[ATTR_DOMAIN_CORNER].length = bm->totloop;
+ info[ATTR_DOMAIN_FACE].customdata = &bm->pdata;
+ info[ATTR_DOMAIN_FACE].length = bm->totface;
+ }
+ else {
+ info[ATTR_DOMAIN_POINT].customdata = &mesh->vdata;
+ info[ATTR_DOMAIN_POINT].length = mesh->totvert;
+ info[ATTR_DOMAIN_EDGE].customdata = &mesh->edata;
+ info[ATTR_DOMAIN_EDGE].length = mesh->totedge;
+ info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata;
+ info[ATTR_DOMAIN_CORNER].length = mesh->totloop;
+ info[ATTR_DOMAIN_FACE].customdata = &mesh->pdata;
+ info[ATTR_DOMAIN_FACE].length = mesh->totpoly;
+ }
break;
}
case ID_HA: {
@@ -146,7 +161,24 @@ CustomDataLayer *BKE_id_attribute_new(
return NULL;
}
- CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name);
+ switch (GS(id->name)) {
+ case ID_ME: {
+ Mesh *me = (Mesh *)id;
+ BMEditMesh *em = me->edit_mesh;
+ if (em != NULL) {
+ BM_data_layer_add_named(em->bm, customdata, type, name);
+ }
+ else {
+ CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name);
+ }
+ break;
+ }
+ default: {
+ CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name);
+ break;
+ }
+ }
+
const int index = CustomData_get_named_layer_index(customdata, type, name);
return (index == -1) ? NULL : &(customdata->layers[index]);
}
@@ -168,8 +200,26 @@ bool BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports
return false;
}
- const int length = BKE_id_attribute_data_length(id, layer);
- CustomData_free_layer(customdata, layer->type, length, index);
+ switch (GS(id->name)) {
+ case ID_ME: {
+ Mesh *me = (Mesh *)id;
+ BMEditMesh *em = me->edit_mesh;
+ if (em != NULL) {
+ BM_data_layer_free(em->bm, customdata, layer->type);
+ }
+ else {
+ const int length = BKE_id_attribute_data_length(id, layer);
+ CustomData_free_layer(customdata, layer->type, length, index);
+ }
+ break;
+ }
+ default: {
+ const int length = BKE_id_attribute_data_length(id, layer);
+ CustomData_free_layer(customdata, layer->type, length, index);
+ break;
+ }
+ }
+
return true;
}
@@ -316,7 +366,7 @@ CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *laye
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
CustomData *customdata = info[domain].customdata;
- if (customdata && customdata->layers) {
+ if (customdata && customdata->layers && customdata->totlayer) {
if (customdata->layers == layers) {
use_next = true;
}
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index e69173cc1d5..9caf416cd0c 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -231,7 +231,7 @@ static bool rule_avoid_collision(BoidRule *rule,
int n, neighbors = 0, nearest = 0;
bool ret = 0;
- // check deflector objects first
+ /* Check deflector objects first. */
if (acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) {
ParticleCollision col;
BVHTreeRayHit hit;
@@ -293,7 +293,7 @@ static bool rule_avoid_collision(BoidRule *rule,
}
}
- // check boids in own system
+ /* Check boids in own system. */
if (acbr->options & BRULE_ACOLL_WITH_BOIDS) {
neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(bbd->sim->psys->tree,
pa->prev_state.co,
@@ -823,11 +823,13 @@ static boid_rule_cb boid_rules[] = {
rule_follow_leader,
rule_average_speed,
rule_fight,
- // rule_help,
- // rule_protect,
- // rule_hide,
- // rule_follow_path,
- // rule_follow_wall,
+#if 0
+ rule_help,
+ rule_protect,
+ rule_hide,
+ rule_follow_path,
+ rule_follow_wall,
+#endif
};
static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa)
@@ -1069,11 +1071,13 @@ static BoidState *get_boid_state(BoidSettings *boids, ParticleData *pa)
return state;
}
-// static int boid_condition_is_true(BoidCondition *cond)
-//{
-// /* TODO */
-// return 0;
-//}
+
+#if 0 /* TODO */
+static int boid_condition_is_true(BoidCondition *cond)
+{
+ return 0;
+}
+#endif
/* determines the velocity the boid wants to have */
void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
@@ -1085,7 +1089,6 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
BoidParticle *bpa = pa->boid;
ParticleSystem *psys = bbd->sim->psys;
int rand;
- // BoidCondition *cond;
if (bpa->data.health <= 0.0f) {
pa->alive = PARS_DYING;
@@ -1093,15 +1096,17 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
return;
}
- // planned for near future
- // cond = state->conditions.first;
- // for (; cond; cond=cond->next) {
- // if (boid_condition_is_true(cond)) {
- // pa->boid->state_id = cond->state_id;
- // state = get_boid_state(boids, pa);
- // break; /* only first true condition is used */
- // }
- //}
+ /* Planned for near future. */
+#if 0
+ BoidCondition *cond = state->conditions.first;
+ for (; cond; cond = cond->next) {
+ if (boid_condition_is_true(cond)) {
+ pa->boid->state_id = cond->state_id;
+ state = get_boid_state(boids, pa);
+ break; /* only first true condition is used */
+ }
+ }
+#endif
zero_v3(bbd->wanted_co);
bbd->wanted_speed = 0.0f;
@@ -1507,20 +1512,22 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa)
}
case eBoidMode_Climbing: {
boid_climb(boids, pa, ground_co, ground_nor);
- // float nor[3];
- // copy_v3_v3(nor, ground_nor);
-
- ///* gather apparent gravity to r_ve */
- // madd_v3_v3fl(pa->r_ve, ground_nor, -1.0);
- // normalize_v3(pa->r_ve);
-
- ///* raise boid it's size from surface */
- // mul_v3_fl(nor, pa->size * boids->height);
- // add_v3_v3v3(pa->state.co, ground_co, nor);
-
- ///* remove normal component from velocity */
- // project_v3_v3v3(v, pa->state.vel, ground_nor);
- // sub_v3_v3v3(pa->state.vel, pa->state.vel, v);
+#if 0
+ float nor[3];
+ copy_v3_v3(nor, ground_nor);
+
+ /* Gather apparent gravity to r_ve. */
+ madd_v3_v3fl(pa->r_ve, ground_nor, -1.0);
+ normalize_v3(pa->r_ve);
+
+ /* Raise boid it's size from surface. */
+ mul_v3_fl(nor, pa->size * boids->height);
+ add_v3_v3v3(pa->state.co, ground_co, nor);
+
+ /* Remove normal component from velocity. */
+ project_v3_v3v3(v, pa->state.vel, ground_nor);
+ sub_v3_v3v3(pa->state.vel, pa->state.vel, v);
+#endif
break;
}
case eBoidMode_OnLand: {
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 24615dd8c2b..f1369254347 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -332,16 +332,6 @@ IDTypeInfo IDType_ID_CU = {
.lib_override_apply_post = NULL,
};
-static int cu_isectLL(const float v1[3],
- const float v2[3],
- const float v3[3],
- const float v4[3],
- short cox,
- short coy,
- float *lambda,
- float *mu,
- float vec[3]);
-
/* frees editcurve entirely */
void BKE_curve_editfont_free(Curve *cu)
{
@@ -566,18 +556,6 @@ void BKE_curve_texspace_ensure(Curve *cu)
}
}
-void BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_size[3])
-{
- BKE_curve_texspace_ensure(cu);
-
- if (r_loc) {
- copy_v3_v3(r_loc, cu->loc);
- }
- if (r_size) {
- copy_v3_v3(r_size, cu->size);
- }
-}
-
bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3])
{
int tot = 0;
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index 8e1577ab072..5c18f6f3807 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -48,6 +48,22 @@ blender::MutableSpan<SplinePtr> CurveEval::splines()
return splines_;
}
+/**
+ * \return True if the curve contains a spline with the given type.
+ *
+ * \note If you are looping over all of the splines in the same scope anyway,
+ * it's better to avoid calling this function, in case there are many splines.
+ */
+bool CurveEval::has_spline_with_type(const Spline::Type type) const
+{
+ for (const SplinePtr &spline : this->splines()) {
+ if (spline->type() == type) {
+ return true;
+ }
+ }
+ return false;
+}
+
void CurveEval::resize(const int size)
{
splines_.resize(size);
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 9cae74e4e9a..83e03ef44f5 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -306,7 +306,7 @@ const float (*BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph
}
else if ((em->mesh_eval_final != NULL) &&
(em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
- /* If this is an edit-mesh type, leave NULL as we can use the vertex coords. . */
+ /* If this is an edit-mesh type, leave NULL as we can use the vertex coords. */
}
else {
/* Constructive modifiers have been used, we need to allocate coordinates. */
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 1b628b16802..fc1721eaf3a 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -547,7 +547,7 @@ static float eff_calc_visibility(ListBase *colliders,
return visibility;
}
-// noise function for wind e.g.
+/* Noise function for wind e.g. */
static float wind_func(struct RNG *rng, float strength)
{
int random = (BLI_rng_get_int(rng) + 1) % 128; /* max 2357 */
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 8f47a7e75d4..5decc7a1792 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -918,7 +918,7 @@ void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
}
/* The active keyframe should always be selected. */
- BLI_assert(BEZT_ISSEL_ANY(active_bezt) || !"active keyframe must be selected");
+ BLI_assert_msg(BEZT_ISSEL_ANY(active_bezt), "active keyframe must be selected");
fcu->active_keyframe_index = (int)offset;
}
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 2b48683a3a8..1d8dc97d2af 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -1545,7 +1545,7 @@ static void emit_from_particles(Object *flow_ob,
float dt)
{
if (ffs && ffs->psys && ffs->psys->part &&
- ELEM(ffs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected
+ ELEM(ffs->psys->part->type, PART_EMITTER, PART_FLUID)) /* Is particle system selected. */
{
ParticleSimulationData sim;
ParticleSystem *psys = ffs->psys;
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index b5c49dbb8b2..0b6ba966974 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -854,17 +854,9 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo
return {};
}
- bool curve_has_bezier_spline = false;
- for (SplinePtr &spline : curve->splines()) {
- if (spline->type() == Spline::Type::Bezier) {
- curve_has_bezier_spline = true;
- break;
- }
- }
-
/* Use the regular position virtual array when there aren't any Bezier splines
* to avoid the overhead of checking the spline type for every point. */
- if (!curve_has_bezier_spline) {
+ if (!curve->has_spline_with_type(Spline::Type::Bezier)) {
return BuiltinPointAttributeProvider<float3>::try_get_for_write(component);
}
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 47c8df03375..90a97264c8f 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -565,6 +565,7 @@ static PointCloud *join_pointcloud_position_attribute(Span<GeometryInstanceGroup
}
PointCloud *new_pointcloud = BKE_pointcloud_new_nomain(totpoint);
+ MutableSpan new_positions{(float3 *)new_pointcloud->co, new_pointcloud->totpoint};
/* Transform each instance's point locations into the new point cloud. */
int offset = 0;
@@ -576,9 +577,7 @@ static PointCloud *join_pointcloud_position_attribute(Span<GeometryInstanceGroup
}
for (const float4x4 &transform : set_group.transforms) {
for (const int i : IndexRange(pointcloud->totpoint)) {
- const float3 old_position = pointcloud->co[i];
- const float3 new_position = transform * old_position;
- copy_v3_v3(new_pointcloud->co[offset + i], new_position);
+ new_positions[offset + i] = transform * float3(pointcloud->co[i]);
}
offset += pointcloud->totpoint;
}
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.cc
index 4dcd94fdeec..f8a07939096 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -21,22 +21,24 @@
* \ingroup bke
*/
-#include <math.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cmath>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
#include "CLG_log.h"
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_float3.hh"
#include "BLI_ghash.h"
#include "BLI_hash.h"
#include "BLI_heap.h"
#include "BLI_math_vector.h"
#include "BLI_polyfill_2d.h"
+#include "BLI_span.hh"
#include "BLT_translation.h"
@@ -61,6 +63,9 @@
#include "DEG_depsgraph_query.h"
+using blender::float3;
+using blender::Span;
+
/* GP Object - Boundbox Support */
/**
*Get min/max coordinate bounds for single stroke.
@@ -75,20 +80,26 @@ bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps,
float r_min[3],
float r_max[3])
{
- const bGPDspoint *pt;
- int i;
- bool changed = false;
-
- if (ELEM(NULL, gps, r_min, r_max)) {
+ if (gps == nullptr) {
return false;
}
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {
- minmax_v3v3_v3(r_min, r_max, &pt->x);
+ bool changed = false;
+ if (use_select) {
+ for (const bGPDspoint &pt : Span(gps->points, gps->totpoints)) {
+ if (pt.flag & GP_SPOINT_SELECT) {
+ minmax_v3v3_v3(r_min, r_max, &pt.x);
+ changed = true;
+ }
+ }
+ }
+ else {
+ for (const bGPDspoint &pt : Span(gps->points, gps->totpoints)) {
+ minmax_v3v3_v3(r_min, r_max, &pt.x);
changed = true;
}
}
+
return changed;
}
@@ -105,14 +116,14 @@ bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3])
INIT_MINMAX(r_min, r_max);
- if (gpd == NULL) {
+ if (gpd == nullptr) {
return changed;
}
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
bGPDframe *gpf = gpl->actframe;
- if (gpf != NULL) {
+ if (gpf != nullptr) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
changed |= BKE_gpencil_stroke_minmax(gps, false, r_min, r_max);
}
@@ -129,11 +140,11 @@ bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3])
*/
void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
{
- float min[3], max[3], tot[3];
-
+ float3 min;
+ float3 max;
BKE_gpencil_data_minmax(gpd, min, max);
- add_v3_v3v3(tot, min, max);
+ const float3 tot = min + max;
mul_v3_v3fl(r_centroid, tot, 0.5f);
}
@@ -153,20 +164,18 @@ void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps)
*/
static void boundbox_gpencil(Object *ob)
{
- BoundBox *bb;
- bGPdata *gpd;
- float min[3], max[3];
-
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
}
- bb = ob->runtime.bb;
- gpd = ob->data;
+ BoundBox *bb = ob->runtime.bb;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ float3 min;
+ float3 max;
if (!BKE_gpencil_data_minmax(gpd, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
+ min = float3(-1);
+ max = float3(1);
}
BKE_boundbox_init_from_minmax(bb, min, max);
@@ -181,8 +190,8 @@ static void boundbox_gpencil(Object *ob)
*/
BoundBox *BKE_gpencil_boundbox_get(Object *ob)
{
- if (ELEM(NULL, ob, ob->data)) {
- return NULL;
+ if (ELEM(nullptr, ob, ob->data)) {
+ return nullptr;
}
bGPdata *gpd = (bGPdata *)ob->data;
@@ -196,9 +205,9 @@ BoundBox *BKE_gpencil_boundbox_get(Object *ob)
/* Update orig object's boundbox with re-computed evaluated values. This function can be
* called with the evaluated object and need update the original object bound box data
* to keep both values synchronized. */
- if (!ELEM(ob_orig, NULL, ob)) {
- if (ob_orig->runtime.bb == NULL) {
- ob_orig->runtime.bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
+ if (!ELEM(ob_orig, nullptr, ob)) {
+ if (ob_orig->runtime.bb == nullptr) {
+ ob_orig->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
}
for (int i = 0; i < 8; i++) {
copy_v3_v3(ob_orig->runtime.bb->vec[i], ob->runtime.bb->vec[i]);
@@ -227,7 +236,7 @@ static int stroke_march_next_point(const bGPDstroke *gps,
float step_start[3];
float point[3];
int next_point_index = index_next_pt;
- bGPDspoint *pt = NULL;
+ bGPDspoint *pt = nullptr;
if (!(next_point_index < gps->totpoints)) {
return -1;
@@ -295,7 +304,7 @@ static int stroke_march_next_point_no_interp(const bGPDstroke *gps,
float step_start[3];
float point[3];
int next_point_index = index_next_pt;
- bGPDspoint *pt = NULL;
+ bGPDspoint *pt = nullptr;
if (!(next_point_index < gps->totpoints)) {
return -1;
@@ -336,7 +345,7 @@ static int stroke_march_count(const bGPDstroke *gps, const float dist)
int point_count = 0;
float point[3];
int next_point_index = 1;
- bGPDspoint *pt = NULL;
+ bGPDspoint *pt = nullptr;
pt = &gps->points[0];
copy_v3_v3(point, &pt->x);
@@ -369,14 +378,14 @@ static void stroke_defvert_create_nr_list(MDeformVert *dv_list,
for (j = 0; j < dv->totweight; j++) {
bool found = false;
dw = &dv->dw[j];
- for (ld = result->first; ld; ld = ld->next) {
+ for (ld = (LinkData *)result->first; ld; ld = ld->next) {
if (ld->data == POINTER_FROM_INT(dw->def_nr)) {
found = true;
break;
}
}
if (!found) {
- ld = MEM_callocN(sizeof(LinkData), "def_nr_item");
+ ld = (LinkData *)MEM_callocN(sizeof(LinkData), "def_nr_item");
ld->data = POINTER_FROM_INT(dw->def_nr);
BLI_addtail(result, ld);
tw++;
@@ -391,14 +400,15 @@ static MDeformVert *stroke_defvert_new_count(int count, int totweight, ListBase
{
int i, j;
LinkData *ld;
- MDeformVert *dst = MEM_mallocN(count * sizeof(MDeformVert), "new_deformVert");
+ MDeformVert *dst = (MDeformVert *)MEM_mallocN(count * sizeof(MDeformVert), "new_deformVert");
for (i = 0; i < count; i++) {
- dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * totweight, "new_deformWeight");
+ dst[i].dw = (MDeformWeight *)MEM_mallocN(sizeof(MDeformWeight) * totweight,
+ "new_deformWeight");
dst[i].totweight = totweight;
j = 0;
/* re-assign deform groups */
- for (ld = def_nr_list->first; ld; ld = ld->next) {
+ for (ld = (LinkData *)def_nr_list->first; ld; ld = ld->next) {
dst[i].dw[j].def_nr = POINTER_AS_INT(ld->data);
j++;
}
@@ -429,10 +439,10 @@ static void stroke_interpolate_deform_weights(
bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, const bool select)
{
bGPDspoint *pt = gps->points;
- bGPDspoint *pt1 = NULL;
- bGPDspoint *pt2 = NULL;
+ bGPDspoint *pt1 = nullptr;
+ bGPDspoint *pt2 = nullptr;
LinkData *ld;
- ListBase def_nr_list = {0};
+ ListBase def_nr_list = {nullptr};
if (gps->totpoints < 2 || dist < FLT_EPSILON) {
return false;
@@ -440,12 +450,13 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist,
/* TODO: Implement feature point preservation. */
int count = stroke_march_count(gps, dist);
- bGPDspoint *new_pt = MEM_callocN(sizeof(bGPDspoint) * count, "gp_stroke_points_sampled");
- MDeformVert *new_dv = NULL;
+ bGPDspoint *new_pt = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * count,
+ "gp_stroke_points_sampled");
+ MDeformVert *new_dv = nullptr;
int result_totweight;
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
stroke_defvert_create_nr_list(gps->dvert, gps->totpoints, &def_nr_list, &result_totweight);
new_dv = stroke_defvert_new_count(count, result_totweight, &def_nr_list);
}
@@ -513,7 +524,7 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist,
/* Free original weight data. */
BKE_gpencil_free_stroke_weights(gps);
MEM_freeN(gps->dvert);
- while ((ld = BLI_pophead(&def_nr_list))) {
+ while ((ld = (LinkData *)BLI_pophead(&def_nr_list))) {
MEM_freeN(ld);
}
@@ -610,26 +621,27 @@ bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const
if (new_count == 1) {
BKE_gpencil_free_stroke_weights(gps);
MEM_freeN(gps->points);
- gps->points = NULL;
- gps->dvert = NULL;
+ gps->points = nullptr;
+ gps->dvert = nullptr;
gps->totpoints = 0;
return false;
}
- new_pt = MEM_callocN(sizeof(bGPDspoint) * new_count, "gp_stroke_points_trimmed");
+ new_pt = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * new_count, "gp_stroke_points_trimmed");
for (int i = 0; i < new_count; i++) {
memcpy(&new_pt[i], &pt[i + index_from], sizeof(bGPDspoint));
}
if (gps->dvert) {
- new_dv = MEM_callocN(sizeof(MDeformVert) * new_count, "gp_stroke_dverts_trimmed");
+ new_dv = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * new_count,
+ "gp_stroke_dverts_trimmed");
for (int i = 0; i < new_count; i++) {
dv = &gps->dvert[i + index_from];
new_dv[i].flag = dv->flag;
new_dv[i].totweight = dv->totweight;
- new_dv[i].dw = MEM_callocN(sizeof(MDeformWeight) * dv->totweight,
- "gp_stroke_dverts_dw_trimmed");
+ new_dv[i].dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight,
+ "gp_stroke_dverts_dw_trimmed");
for (int j = 0; j < dv->totweight; j++) {
new_dv[i].dw[j].weight = dv->dw[j].weight;
new_dv[i].dw[j].def_nr = dv->dw[j].def_nr;
@@ -685,14 +697,14 @@ bool BKE_gpencil_stroke_split(bGPdata *gpd,
}
if (gps->dvert) {
- new_dv = MEM_callocN(sizeof(MDeformVert) * new_count,
- "gp_stroke_dverts_remaining(MDeformVert)");
+ new_dv = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * new_count,
+ "gp_stroke_dverts_remaining(MDeformVert)");
for (int i = 0; i < new_count; i++) {
dv = &gps->dvert[i + before_index];
new_dv[i].flag = dv->flag;
new_dv[i].totweight = dv->totweight;
- new_dv[i].dw = MEM_callocN(sizeof(MDeformWeight) * dv->totweight,
- "gp_stroke_dverts_dw_remaining(MDeformWeight)");
+ new_dv[i].dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight,
+ "gp_stroke_dverts_dw_remaining(MDeformWeight)");
for (int j = 0; j < dv->totweight; j++) {
new_dv[i].dw[j].weight = dv->dw[j].weight;
new_dv[i].dw[j].def_nr = dv->dw[j].def_nr;
@@ -1301,11 +1313,12 @@ void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps)
/* allocate memory for temporary areas */
gps->tot_triangles = gps->totpoints - 2;
- uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles,
- "GP Stroke temp triangulation");
- float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints,
- "GP Stroke temp 2d points");
- float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
+ uint(*tmp_triangles)[3] = (uint(*)[3])MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles,
+ "GP Stroke temp triangulation");
+ float(*points2d)[2] = (float(*)[2])MEM_mallocN(sizeof(*points2d) * gps->totpoints,
+ "GP Stroke temp 2d points");
+ float(*uv)[2] = (float(*)[2])MEM_mallocN(sizeof(*uv) * gps->totpoints,
+ "GP Stroke temp 2d uv data");
int direction = 0;
@@ -1326,8 +1339,8 @@ void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps)
/* Save triangulation data. */
if (gps->tot_triangles > 0) {
MEM_SAFE_FREE(gps->triangles);
- gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles,
- "GP Stroke triangulation");
+ gps->triangles = (bGPDtriangle *)MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles,
+ "GP Stroke triangulation");
for (int i = 0; i < gps->tot_triangles; i++) {
memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3]));
@@ -1344,7 +1357,7 @@ void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps)
MEM_freeN(gps->triangles);
}
- gps->triangles = NULL;
+ gps->triangles = nullptr;
}
/* clear memory */
@@ -1359,7 +1372,7 @@ void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps)
*/
void BKE_gpencil_stroke_uv_update(bGPDstroke *gps)
{
- if (gps == NULL || gps->totpoints == 0) {
+ if (gps == nullptr || gps->totpoints == 0) {
return;
}
@@ -1379,11 +1392,11 @@ void BKE_gpencil_stroke_uv_update(bGPDstroke *gps)
*/
void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps)
{
- if (gps == NULL) {
+ if (gps == nullptr) {
return;
}
- if (gps->editcurve != NULL) {
+ if (gps->editcurve != nullptr) {
if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
/* curve geometry was updated: stroke needs recalculation */
if (gps->flag & GP_STROKE_NEEDS_CURVE_UPDATE) {
@@ -1519,20 +1532,20 @@ bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps)
if (intersect) {
/* save points */
- bGPDspoint *old_points = MEM_dupallocN(gps->points);
- MDeformVert *old_dvert = NULL;
- MDeformVert *dvert_src = NULL;
+ bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = nullptr;
+ MDeformVert *dvert_src = nullptr;
- if (gps->dvert != NULL) {
- old_dvert = MEM_dupallocN(gps->dvert);
+ if (gps->dvert != nullptr) {
+ old_dvert = (MDeformVert *)MEM_dupallocN(gps->dvert);
}
/* resize gps */
int newtot = end - start + 1;
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
- if (gps->dvert != NULL) {
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
+ gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
+ if (gps->dvert != nullptr) {
+ gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
}
for (int i = 0; i < newtot; i++) {
@@ -1540,7 +1553,7 @@ bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps)
bGPDspoint *pt_src = &old_points[idx];
bGPDspoint *pt_new = &gps->points[i];
memcpy(pt_new, pt_src, sizeof(bGPDspoint));
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
dvert_src = &old_dvert[idx];
MDeformVert *dvert = &gps->dvert[i];
memcpy(dvert, dvert_src, sizeof(MDeformVert));
@@ -1570,8 +1583,8 @@ bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps)
*/
bool BKE_gpencil_stroke_close(bGPDstroke *gps)
{
- bGPDspoint *pt1 = NULL;
- bGPDspoint *pt2 = NULL;
+ bGPDspoint *pt1 = nullptr;
+ bGPDspoint *pt2 = nullptr;
/* Only can close a stroke with 3 points or more. */
if (gps->totpoints < 3) {
@@ -1605,9 +1618,9 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps)
/* Resize stroke array. */
int old_tot = gps->totpoints;
gps->totpoints += tot_newpoints;
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
- if (gps->dvert != NULL) {
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != nullptr) {
+ gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
}
/* Generate new points */
@@ -1629,7 +1642,7 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps)
interp_v4_v4v4(pt->vert_color, pt1->vert_color, pt2->vert_color, step);
/* Set weights. */
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
MDeformVert *dvert1 = &gps->dvert[old_tot - 1];
MDeformWeight *dw1 = BKE_defvert_ensure_index(dvert1, 0);
float weight_1 = dw1 ? dw1->weight : 0.0f;
@@ -1663,7 +1676,7 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps)
void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, const short tag)
{
bGPDspoint *pt;
- MDeformVert *dvert = NULL;
+ MDeformVert *dvert = nullptr;
int i;
int tot = gps->totpoints; /* number of points in new buffer */
@@ -1693,30 +1706,32 @@ void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps,
}
else {
/* just copy all points to keep into a smaller buffer */
- bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy");
+ bGPDspoint *new_points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * tot,
+ "new gp stroke points copy");
bGPDspoint *npt = new_points;
- MDeformVert *new_dvert = NULL;
- MDeformVert *ndvert = NULL;
+ MDeformVert *new_dvert = nullptr;
+ MDeformVert *ndvert = nullptr;
- if (gps->dvert != NULL) {
- new_dvert = MEM_callocN(sizeof(MDeformVert) * tot, "new gp stroke weights copy");
+ if (gps->dvert != nullptr) {
+ new_dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * tot,
+ "new gp stroke weights copy");
ndvert = new_dvert;
}
- (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
+ (gps->dvert != nullptr) ? dvert = gps->dvert : nullptr;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if ((pt->flag & tag) == 0) {
*npt = *pt;
npt++;
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
*ndvert = *dvert;
- ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert->dw = (MDeformWeight *)MEM_dupallocN(dvert->dw);
ndvert++;
}
}
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
dvert++;
}
}
@@ -1789,15 +1804,15 @@ void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
*/
void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float epsilon)
{
- bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points);
int totpoints = gps->totpoints;
- char *marked = NULL;
+ char *marked = nullptr;
char work;
int start = 0;
int end = gps->totpoints - 1;
- marked = MEM_callocN(totpoints, "GP marked array");
+ marked = (char *)MEM_callocN(totpoints, "GP marked array");
marked[start] = 1;
marked[end] = 1;
@@ -1849,11 +1864,11 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float e
}
/* adding points marked */
- MDeformVert *old_dvert = NULL;
- MDeformVert *dvert_src = NULL;
+ MDeformVert *old_dvert = nullptr;
+ MDeformVert *dvert_src = nullptr;
- if (gps->dvert != NULL) {
- old_dvert = MEM_dupallocN(gps->dvert);
+ if (gps->dvert != nullptr) {
+ old_dvert = (MDeformVert *)MEM_dupallocN(gps->dvert);
}
/* resize gps */
int j = 0;
@@ -1863,7 +1878,7 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float e
if ((marked[i]) || (i == 0) || (i == totpoints - 1)) {
memcpy(pt, pt_src, sizeof(bGPDspoint));
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
dvert_src = &old_dvert[i];
MDeformVert *dvert = &gps->dvert[j];
memcpy(dvert, dvert_src, sizeof(MDeformVert));
@@ -1874,7 +1889,7 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float e
j++;
}
else {
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
dvert_src = &old_dvert[i];
BKE_gpencil_free_point_weights(dvert_src);
}
@@ -1903,12 +1918,12 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
}
/* save points */
- bGPDspoint *old_points = MEM_dupallocN(gps->points);
- MDeformVert *old_dvert = NULL;
- MDeformVert *dvert_src = NULL;
+ bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = nullptr;
+ MDeformVert *dvert_src = nullptr;
- if (gps->dvert != NULL) {
- old_dvert = MEM_dupallocN(gps->dvert);
+ if (gps->dvert != nullptr) {
+ old_dvert = (MDeformVert *)MEM_dupallocN(gps->dvert);
}
/* resize gps */
@@ -1918,9 +1933,9 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
}
newtot += 2;
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
- if (gps->dvert != NULL) {
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
+ gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
+ if (gps->dvert != nullptr) {
+ gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
}
int j = 0;
@@ -1930,7 +1945,7 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) {
memcpy(pt, pt_src, sizeof(bGPDspoint));
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
dvert_src = &old_dvert[i];
MDeformVert *dvert = &gps->dvert[j];
memcpy(dvert, dvert_src, sizeof(MDeformVert));
@@ -1941,7 +1956,7 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
j++;
}
else {
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
dvert_src = &old_dvert[i];
BKE_gpencil_free_point_weights(dvert_src);
}
@@ -1966,25 +1981,25 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int type)
{
bGPDspoint *temp_points;
- MDeformVert *temp_dverts = NULL;
- MDeformVert *dvert = NULL;
- MDeformVert *dvert_final = NULL;
- MDeformVert *dvert_next = NULL;
+ MDeformVert *temp_dverts = nullptr;
+ MDeformVert *dvert = nullptr;
+ MDeformVert *dvert_final = nullptr;
+ MDeformVert *dvert_next = nullptr;
int totnewpoints, oldtotpoints;
int i2;
for (int s = 0; s < level; s++) {
totnewpoints = gps->totpoints - 1;
/* duplicate points in a temp area */
- temp_points = MEM_dupallocN(gps->points);
+ temp_points = (bGPDspoint *)MEM_dupallocN(gps->points);
oldtotpoints = gps->totpoints;
/* resize the points arrays */
gps->totpoints += totnewpoints;
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
- if (gps->dvert != NULL) {
- temp_dverts = MEM_dupallocN(gps->dvert);
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != nullptr) {
+ temp_dverts = (MDeformVert *)MEM_dupallocN(gps->dvert);
+ gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
}
/* move points from last to first to new place */
@@ -2002,7 +2017,7 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int
pt_final->runtime.idx_orig = pt->runtime.idx_orig;
copy_v4_v4(pt_final->vert_color, pt->vert_color);
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
dvert = &temp_dverts[i];
dvert_final = &gps->dvert[i2];
dvert_final->totweight = dvert->totweight;
@@ -2023,17 +2038,17 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int
pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt_final->time = interpf(pt->time, next->time, 0.5f);
- pt_final->runtime.pt_orig = NULL;
+ pt_final->runtime.pt_orig = nullptr;
pt_final->flag = 0;
interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f);
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
dvert = &temp_dverts[i];
dvert_next = &temp_dverts[i + 1];
dvert_final = &gps->dvert[i2];
dvert_final->totweight = dvert->totweight;
- dvert_final->dw = MEM_dupallocN(dvert->dw);
+ dvert_final->dw = (MDeformWeight *)MEM_dupallocN(dvert->dw);
/* interpolate weight values */
for (int d = 0; d < dvert->totweight; d++) {
@@ -2055,7 +2070,7 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int
/* Move points to smooth stroke (not simple type). */
if (type != GP_SUBDIV_SIMPLE) {
/* duplicate points in a temp area with the new subdivide data */
- temp_points = MEM_dupallocN(gps->points);
+ temp_points = (bGPDspoint *)MEM_dupallocN(gps->points);
/* extreme points are not changed */
for (int i = 0; i < gps->totpoints - 2; i++) {
@@ -2079,13 +2094,14 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int
/**
* Reduce a series of points when the distance is below a threshold.
- * Special case for first and last points (both are keeped) for other points,
+ * Special case for first and last points (both are kept) for other points,
* the merge point always is at first point.
- * \param gpd: Grease pencil data-block
- * \param gpf: Grease Pencil frame
- * \param gps: Grease Pencil stroke
- * \param threshold: Distance between points
- * \param use_unselected: Set to true to analyze all stroke and not only selected points
+ *
+ * \param gpd: Grease pencil data-block.
+ * \param gpf: Grease Pencil frame.
+ * \param gps: Grease Pencil stroke.
+ * \param threshold: Distance between points.
+ * \param use_unselected: Set to true to analyze all stroke and not only selected points.
*/
void BKE_gpencil_stroke_merge_distance(bGPdata *gpd,
bGPDframe *gpf,
@@ -2093,8 +2109,8 @@ void BKE_gpencil_stroke_merge_distance(bGPdata *gpd,
const float threshold,
const bool use_unselected)
{
- bGPDspoint *pt = NULL;
- bGPDspoint *pt_next = NULL;
+ bGPDspoint *pt = nullptr;
+ bGPDspoint *pt_next = nullptr;
float tagged = false;
/* Use square distance to speed up loop */
const float th_square = threshold * threshold;
@@ -2160,7 +2176,7 @@ void BKE_gpencil_stroke_merge_distance(bGPdata *gpd,
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
-typedef struct GpEdge {
+struct GpEdge {
uint v1, v2;
/* Coordinates. */
float v1_co[3], v2_co[3];
@@ -2169,7 +2185,7 @@ typedef struct GpEdge {
/* Direction of the segment. */
float vec[3];
int flag;
-} GpEdge;
+};
static int gpencil_next_edge(
GpEdge *gp_edges, int totedges, GpEdge *gped_init, const float threshold, const bool reverse)
@@ -2261,14 +2277,14 @@ static void gpencil_generate_edgeloops(Object *ob,
}
/* Arrays for all edge vertices (forward and backward) that form a edge loop.
- * This is reused for each edgeloop to create gpencil stroke. */
- uint *stroke = MEM_callocN(sizeof(uint) * me->totedge * 2, __func__);
- uint *stroke_fw = MEM_callocN(sizeof(uint) * me->totedge, __func__);
- uint *stroke_bw = MEM_callocN(sizeof(uint) * me->totedge, __func__);
+ * This is reused for each edge-loop to create gpencil stroke. */
+ uint *stroke = (uint *)MEM_callocN(sizeof(uint) * me->totedge * 2, __func__);
+ uint *stroke_fw = (uint *)MEM_callocN(sizeof(uint) * me->totedge, __func__);
+ uint *stroke_bw = (uint *)MEM_callocN(sizeof(uint) * me->totedge, __func__);
/* Create array with all edges. */
- GpEdge *gp_edges = MEM_callocN(sizeof(GpEdge) * me->totedge, __func__);
- GpEdge *gped = NULL;
+ GpEdge *gp_edges = (GpEdge *)MEM_callocN(sizeof(GpEdge) * me->totedge, __func__);
+ GpEdge *gped = nullptr;
for (int i = 0; i < me->totedge; i++) {
MEdge *ed = &me->medge[i];
gped = &gp_edges[i];
@@ -2321,7 +2337,7 @@ static void gpencil_generate_edgeloops(Object *ob,
/* Look backward edges. */
int totbw = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_bw, e, angle, true);
- BLI_ghash_free(v_table, NULL, NULL);
+ BLI_ghash_free(v_table, nullptr, nullptr);
/* Join both arrays. */
int array_len = 0;
@@ -2423,7 +2439,7 @@ static int gpencil_material_find_index_by_name(Object *ob, const char *name)
{
for (int i = 0; i < ob->totcol; i++) {
Material *ma = BKE_object_material_get(ob, i + 1);
- if ((ma != NULL) && (ma->gp_style != NULL) && (STREQ(ma->id.name + 2, name))) {
+ if ((ma != nullptr) && (ma->gp_style != nullptr) && (STREQ(ma->id.name + 2, name))) {
return i;
}
}
@@ -2453,7 +2469,7 @@ static void make_element_name(const char *obname, const char *name, const int ma
* \param scene: Original scene.
* \param ob_gp: Grease pencil object to add strokes.
* \param ob_mesh: Mesh to convert.
- * \param angle: Limit angle to consider a edgeloop ends.
+ * \param angle: Limit angle to consider a edge-loop ends.
* \param thickness: Thickness of the strokes.
* \param offset: Offset along the normals.
* \param matrix: Transformation matrix.
@@ -2474,7 +2490,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
const bool use_seams,
const bool use_faces)
{
- if (ELEM(NULL, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
+ if (ELEM(nullptr, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == nullptr)) {
return false;
}
@@ -2511,7 +2527,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
make_element_name(ob_mesh->id.name + 2, "Fills", 128, element_name);
/* Create Layer and Frame. */
bGPDlayer *gpl_fill = BKE_gpencil_layer_named_get(gpd, element_name);
- if (gpl_fill == NULL) {
+ if (gpl_fill == nullptr) {
gpl_fill = BKE_gpencil_layer_addnew(gpd, element_name, true, false);
}
bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get(
@@ -2524,11 +2540,11 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
int mat_idx = 0;
Material *ma = BKE_object_material_get(ob_mesh, mp->mat_nr + 1);
make_element_name(
- ob_mesh->id.name + 2, (ma != NULL) ? ma->id.name + 2 : "Fill", 64, element_name);
+ ob_mesh->id.name + 2, (ma != nullptr) ? ma->id.name + 2 : "Fill", 64, element_name);
mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob_gp, element_name);
if (mat_idx == -1) {
float color[4];
- if (ma != NULL) {
+ if (ma != nullptr) {
copy_v3_v3(color, &ma->r);
color[3] = 1.0f;
}
@@ -2567,7 +2583,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
/* Create Layer and Frame. */
bGPDlayer *gpl_stroke = BKE_gpencil_layer_named_get(gpd, element_name);
- if (gpl_stroke == NULL) {
+ if (gpl_stroke == nullptr) {
gpl_stroke = BKE_gpencil_layer_addnew(gpd, element_name, true, false);
}
bGPDframe *gpf_stroke = BKE_gpencil_layer_frame_get(
@@ -2589,7 +2605,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
*/
void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4])
{
- if (gpd == NULL) {
+ if (gpd == nullptr) {
return;
}
@@ -2625,7 +2641,7 @@ int BKE_gpencil_stroke_point_count(const bGPdata *gpd)
{
int total_points = 0;
- if (gpd == NULL) {
+ if (gpd == nullptr) {
return 0;
}
@@ -2650,7 +2666,7 @@ int BKE_gpencil_stroke_point_count(const bGPdata *gpd)
/* Used for "move only origins" in object_data_transform.c */
void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_data)
{
- if (gpd == NULL) {
+ if (gpd == nullptr) {
return;
}
@@ -2681,7 +2697,7 @@ void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_da
/* Used for "move only origins" in object_data_transform.c */
void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates *elem_data)
{
- if (gpd == NULL) {
+ if (gpd == nullptr) {
return;
}
@@ -2717,7 +2733,7 @@ void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd,
const GPencilPointCoordinates *elem_data,
const float mat[4][4])
{
- if (gpd == NULL) {
+ if (gpd == nullptr) {
return;
}
@@ -2818,24 +2834,24 @@ void BKE_gpencil_stroke_flip(bGPDstroke *gps)
* that should be kept when splitting up a stroke. Used in:
* gpencil_stroke_delete_tagged_points()
*/
-typedef struct tGPDeleteIsland {
+struct tGPDeleteIsland {
int start_idx;
int end_idx;
-} tGPDeleteIsland;
+};
static void gpencil_stroke_join_islands(bGPdata *gpd,
bGPDframe *gpf,
bGPDstroke *gps_first,
bGPDstroke *gps_last)
{
- bGPDspoint *pt = NULL;
- bGPDspoint *pt_final = NULL;
+ bGPDspoint *pt = nullptr;
+ bGPDspoint *pt_final = nullptr;
const int totpoints = gps_first->totpoints + gps_last->totpoints;
/* create new stroke */
bGPDstroke *join_stroke = BKE_gpencil_stroke_duplicate(gps_first, false, true);
- join_stroke->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
+ join_stroke->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
join_stroke->totpoints = totpoints;
join_stroke->flag &= ~GP_STROKE_CYCLIC;
@@ -2868,17 +2884,17 @@ static void gpencil_stroke_join_islands(bGPdata *gpd,
}
/* Copy over vertex weight data (if available) */
- if ((gps_first->dvert != NULL) || (gps_last->dvert != NULL)) {
- join_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * totpoints, __func__);
- MDeformVert *dvert_src = NULL;
- MDeformVert *dvert_dst = NULL;
+ if ((gps_first->dvert != nullptr) || (gps_last->dvert != nullptr)) {
+ join_stroke->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * totpoints, __func__);
+ MDeformVert *dvert_src = nullptr;
+ MDeformVert *dvert_dst = nullptr;
/* Copy weights (last before). */
e1 = 0;
e2 = 0;
for (int i = 0; i < totpoints; i++) {
dvert_dst = &join_stroke->dvert[i];
- dvert_src = NULL;
+ dvert_src = nullptr;
if (i < gps_last->totpoints) {
if (gps_last->dvert) {
dvert_src = &gps_last->dvert[e1];
@@ -2893,7 +2909,7 @@ static void gpencil_stroke_join_islands(bGPdata *gpd,
}
if ((dvert_src) && (dvert_src->dw)) {
- dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ dvert_dst->dw = (MDeformWeight *)MEM_dupallocN(dvert_src->dw);
}
}
}
@@ -2934,13 +2950,13 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
bool select,
int limit)
{
- tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2,
- "gp_point_islands");
+ tGPDeleteIsland *islands = (tGPDeleteIsland *)MEM_callocN(
+ sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands");
bool in_island = false;
int num_islands = 0;
- bGPDstroke *new_stroke = NULL;
- bGPDstroke *gps_first = NULL;
+ bGPDstroke *new_stroke = nullptr;
+ bGPDstroke *gps_first = nullptr;
const bool is_cyclic = (bool)(gps->flag & GP_STROKE_CYCLIC);
/* First Pass: Identify start/end of islands */
@@ -2982,7 +2998,7 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
new_stroke = BKE_gpencil_stroke_duplicate(gps, false, true);
/* if cyclic and first stroke, save to join later */
- if ((is_cyclic) && (gps_first == NULL)) {
+ if ((is_cyclic) && (gps_first == nullptr)) {
gps_first = new_stroke;
}
@@ -2992,17 +3008,17 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
new_stroke->totpoints = island->end_idx - island->start_idx + 1;
/* Copy over the relevant point data */
- new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints,
- "gp delete stroke fragment");
+ new_stroke->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints,
+ "gp delete stroke fragment");
memcpy(new_stroke->points,
gps->points + island->start_idx,
sizeof(bGPDspoint) * new_stroke->totpoints);
/* Copy over vertex weight data (if available) */
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
/* Copy over the relevant vertex-weight points */
- new_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints,
- "gp delete stroke fragment weight");
+ new_stroke->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints,
+ "gp delete stroke fragment weight");
memcpy(new_stroke->dvert,
gps->dvert + island->start_idx,
sizeof(MDeformVert) * new_stroke->totpoints);
@@ -3013,7 +3029,7 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
MDeformVert *dvert_src = &gps->dvert[e];
MDeformVert *dvert_dst = &new_stroke->dvert[i];
if (dvert_src->dw) {
- dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ dvert_dst->dw = (MDeformWeight *)MEM_dupallocN(dvert_src->dw);
}
e++;
}
@@ -3047,7 +3063,7 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
/* Add new stroke to the frame or delete if below limit */
if ((limit > 0) && (new_stroke->totpoints <= limit)) {
if (gps_first == new_stroke) {
- gps_first = NULL;
+ gps_first = nullptr;
}
BKE_gpencil_free_stroke(new_stroke);
}
@@ -3064,7 +3080,7 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
}
}
/* if cyclic, need to join last stroke with first stroke */
- if ((is_cyclic) && (gps_first != NULL) && (gps_first != new_stroke)) {
+ if ((is_cyclic) && (gps_first != nullptr) && (gps_first != new_stroke)) {
gpencil_stroke_join_islands(gpd, gpf, gps_first, new_stroke);
}
}
@@ -3086,13 +3102,13 @@ void BKE_gpencil_curve_delete_tagged_points(bGPdata *gpd,
bGPDcurve *gpc,
int tag_flags)
{
- if (gpc == NULL) {
+ if (gpc == nullptr) {
return;
}
const bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
const int idx_last = gpc->tot_curve_points - 1;
- bGPDstroke *gps_first = NULL;
- bGPDstroke *gps_last = NULL;
+ bGPDstroke *gps_first = nullptr;
+ bGPDstroke *gps_last = nullptr;
int idx_start = 0;
int idx_end = 0;
@@ -3123,11 +3139,11 @@ void BKE_gpencil_curve_delete_tagged_points(bGPdata *gpd,
}
bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, false, false);
- new_stroke->points = NULL;
+ new_stroke->points = nullptr;
new_stroke->flag &= ~GP_STROKE_CYCLIC;
new_stroke->editcurve = BKE_gpencil_stroke_editcurve_new(island_length);
- if (gps_first == NULL) {
+ if (gps_first == nullptr) {
gps_first = new_stroke;
}
@@ -3155,15 +3171,15 @@ void BKE_gpencil_curve_delete_tagged_points(bGPdata *gpd,
}
/* join first and last stroke if cyclic */
- if (is_cyclic && gps_first != NULL && gps_last != NULL && gps_first != gps_last) {
+ if (is_cyclic && gps_first != nullptr && gps_last != nullptr && gps_first != gps_last) {
bGPDcurve *gpc_first = gps_first->editcurve;
bGPDcurve *gpc_last = gps_last->editcurve;
int first_tot_points = gpc_first->tot_curve_points;
int old_tot_points = gpc_last->tot_curve_points;
gpc_last->tot_curve_points = first_tot_points + old_tot_points;
- gpc_last->curve_points = MEM_recallocN(gpc_last->curve_points,
- sizeof(bGPDcurve_point) * gpc_last->tot_curve_points);
+ gpc_last->curve_points = (bGPDcurve_point *)MEM_recallocN(
+ gpc_last->curve_points, sizeof(bGPDcurve_point) * gpc_last->tot_curve_points);
/* copy data from first to last */
memcpy(gpc_last->curve_points + old_tot_points,
gpc_first->curve_points,
@@ -3196,14 +3212,16 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps,
{
bGPDspoint *newpoint;
- gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
- if (gps->dvert != NULL) {
- gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
+ gps->points = (bGPDspoint *)MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ if (gps->dvert != nullptr) {
+ gps->dvert = (MDeformVert *)MEM_reallocN(gps->dvert,
+ sizeof(MDeformVert) * (gps->totpoints + 1));
}
else {
/* If destination has weight add weight to origin. */
- if (dvert != NULL) {
- gps->dvert = MEM_callocN(sizeof(MDeformVert) * (gps->totpoints + 1), __func__);
+ if (dvert != nullptr) {
+ gps->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * (gps->totpoints + 1),
+ __func__);
}
}
@@ -3219,16 +3237,16 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps,
newpoint->time = point->time + deltatime;
copy_v4_v4(newpoint->vert_color, point->vert_color);
- if (gps->dvert != NULL) {
+ if (gps->dvert != nullptr) {
MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1];
- if (dvert != NULL) {
+ if (dvert != nullptr) {
newdvert->totweight = dvert->totweight;
- newdvert->dw = MEM_dupallocN(dvert->dw);
+ newdvert->dw = (MDeformWeight *)MEM_dupallocN(dvert->dw);
}
else {
newdvert->totweight = 0;
- newdvert->dw = NULL;
+ newdvert->dw = nullptr;
}
}
}
@@ -3246,7 +3264,7 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
float deltatime = 0.0f;
/* sanity checks */
- if (ELEM(NULL, gps_a, gps_b)) {
+ if (ELEM(nullptr, gps_a, gps_b)) {
return;
}
@@ -3308,11 +3326,11 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
point = gps_a->points[gps_a->totpoints - 1];
deltatime = point.time;
- gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, 0.0f);
+ gpencil_stroke_copy_point(gps_a, nullptr, &point, delta, 0.0f, 0.0f, 0.0f);
/* 2nd: add one head point to finish invisible area */
point = gps_b->points[0];
- gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, deltatime);
+ gpencil_stroke_copy_point(gps_a, nullptr, &point, delta, 0.0f, 0.0f, deltatime);
}
const float ratio = (fit_thickness && gps_a->thickness > 0.0f) ?
@@ -3321,7 +3339,7 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
/* 3rd: add all points */
for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
- MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : NULL;
+ MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : nullptr;
gpencil_stroke_copy_point(
gps_a, dvert, pt, delta, pt->pressure * ratio, pt->strength, deltatime);
}
@@ -3340,16 +3358,16 @@ void BKE_gpencil_stroke_copy_to_keyframes(
if (gpf->framenum != cfra) {
bGPDframe *gpf_new = BKE_gpencil_layer_frame_find(gpl, cfra);
- if (gpf_new == NULL) {
+ if (gpf_new == nullptr) {
gpf_new = BKE_gpencil_frame_addnew(gpl, cfra);
}
- if (gpf_new == NULL) {
+ if (gpf_new == nullptr) {
continue;
}
bGPDstroke *gps_new = BKE_gpencil_stroke_duplicate(gps, true, true);
- if (gps_new == NULL) {
+ if (gps_new == nullptr) {
continue;
}
@@ -3363,38 +3381,38 @@ void BKE_gpencil_stroke_copy_to_keyframes(
}
/* Free hash table. */
- BLI_ghash_free(frame_list, NULL, NULL);
+ BLI_ghash_free(frame_list, nullptr, nullptr);
}
/* Stroke Uniform Subdivide ------------------------------------- */
-typedef struct tSamplePoint {
+struct tSamplePoint {
struct tSamplePoint *next, *prev;
float x, y, z;
float pressure, strength, time;
float vertex_color[4];
struct MDeformWeight *dw;
int totweight;
-} tSamplePoint;
+};
-typedef struct tSampleEdge {
+struct tSampleEdge {
float length_sq;
tSamplePoint *from;
tSamplePoint *to;
-} tSampleEdge;
+};
/* Helper: creates a tSamplePoint from a bGPDspoint and (optionally) a MDeformVert. */
static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const MDeformVert *dvert)
{
- tSamplePoint *new_pt = MEM_callocN(sizeof(tSamplePoint), __func__);
+ tSamplePoint *new_pt = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__);
copy_v3_v3(&new_pt->x, &pt->x);
new_pt->pressure = pt->pressure;
new_pt->strength = pt->strength;
new_pt->time = pt->time;
copy_v4_v4((float *)&new_pt->vertex_color, (float *)&pt->vert_color);
- if (dvert != NULL) {
+ if (dvert != nullptr) {
new_pt->totweight = dvert->totweight;
- new_pt->dw = MEM_callocN(sizeof(MDeformWeight) * new_pt->totweight, __func__);
+ new_pt->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * new_pt->totweight, __func__);
for (uint i = 0; i < new_pt->totweight; ++i) {
MDeformWeight *dw = &new_pt->dw[i];
MDeformWeight *dw_from = &dvert->dw[i];
@@ -3409,7 +3427,7 @@ static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const
* the edge. */
static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamplePoint *to)
{
- tSampleEdge *new_edge = MEM_callocN(sizeof(tSampleEdge), __func__);
+ tSampleEdge *new_edge = (tSampleEdge *)MEM_callocN(sizeof(tSampleEdge), __func__);
new_edge->from = from;
new_edge->to = to;
new_edge->length_sq = len_squared_v3v3(&from->x, &to->x);
@@ -3431,27 +3449,27 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
const bool select)
{
/* Stroke needs at least two points and strictly less points than the target number. */
- if (gps == NULL || gps->totpoints < 2 || gps->totpoints >= target_number) {
+ if (gps == nullptr || gps->totpoints < 2 || gps->totpoints >= target_number) {
return;
}
const int totpoints = gps->totpoints;
- const bool has_dverts = (gps->dvert != NULL);
+ const bool has_dverts = (gps->dvert != nullptr);
const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC);
- ListBase points = {NULL, NULL};
+ ListBase points = {nullptr, nullptr};
Heap *edges = BLI_heap_new();
/* Add all points into list. */
for (uint32_t i = 0; i < totpoints; ++i) {
bGPDspoint *pt = &gps->points[i];
- MDeformVert *dvert = has_dverts ? &gps->dvert[i] : NULL;
+ MDeformVert *dvert = has_dverts ? &gps->dvert[i] : nullptr;
tSamplePoint *sp = new_sample_point_from_gp_point(pt, dvert);
BLI_addtail(&points, sp);
}
/* Iterate over edges and insert them into the heap. */
- for (tSamplePoint *pt = ((tSamplePoint *)points.first)->next; pt != NULL; pt = pt->next) {
+ for (tSamplePoint *pt = ((tSamplePoint *)points.first)->next; pt != nullptr; pt = pt->next) {
tSampleEdge *se = new_sample_edge_from_sample_points(pt->prev, pt);
/* BLI_heap is a min-heap, but we need the largest key to be at the top, so we take the
* negative of the squared length. */
@@ -3459,8 +3477,8 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
}
if (is_cyclic) {
- tSamplePoint *sp_first = points.first;
- tSamplePoint *sp_last = points.last;
+ tSamplePoint *sp_first = (tSamplePoint *)points.first;
+ tSamplePoint *sp_last = (tSamplePoint *)points.last;
tSampleEdge *se = new_sample_edge_from_sample_points(sp_last, sp_first);
BLI_heap_insert(edges, -(se->length_sq), se);
}
@@ -3469,12 +3487,12 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
BLI_assert(num_points_needed > 0);
while (num_points_needed > 0) {
- tSampleEdge *se = BLI_heap_pop_min(edges);
+ tSampleEdge *se = (tSampleEdge *)BLI_heap_pop_min(edges);
tSamplePoint *sp = se->from;
tSamplePoint *sp_next = se->to;
/* Subdivide the edge. */
- tSamplePoint *new_sp = MEM_callocN(sizeof(tSamplePoint), __func__);
+ tSamplePoint *new_sp = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__);
interp_v3_v3v3(&new_sp->x, &sp->x, &sp_next->x, 0.5f);
new_sp->pressure = interpf(sp->pressure, sp_next->pressure, 0.5f);
new_sp->strength = interpf(sp->strength, sp_next->strength, 0.5f);
@@ -3485,7 +3503,8 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
0.5f);
if (sp->dw && sp_next->dw) {
new_sp->totweight = MIN2(sp->totweight, sp_next->totweight);
- new_sp->dw = MEM_callocN(sizeof(MDeformWeight) * new_sp->totweight, __func__);
+ new_sp->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * new_sp->totweight,
+ __func__);
for (uint32_t i = 0; i < new_sp->totweight; ++i) {
MDeformWeight *dw = &new_sp->dw[i];
MDeformWeight *dw_from = &sp->dw[i];
@@ -3509,13 +3528,13 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
BLI_heap_free(edges, (HeapFreeFP)MEM_freeN);
gps->totpoints = target_number;
- gps->points = MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints);
+ gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints);
if (has_dverts) {
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints);
+ gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints);
}
/* Convert list back to stroke point array. */
- tSamplePoint *sp = points.first;
+ tSamplePoint *sp = (tSamplePoint *)points.first;
for (uint32_t i = 0; i < gps->totpoints && sp; ++i, sp = sp->next) {
bGPDspoint *pt = &gps->points[i];
MDeformVert *dvert = &gps->dvert[i];
@@ -3528,7 +3547,7 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
if (sp->dw) {
dvert->totweight = sp->totweight;
- dvert->dw = MEM_callocN(sizeof(MDeformWeight) * dvert->totweight, __func__);
+ dvert->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dvert->totweight, __func__);
for (uint32_t j = 0; j < dvert->totweight; ++j) {
MDeformWeight *dw = &dvert->dw[j];
MDeformWeight *dw_from = &sp->dw[j];
@@ -3549,7 +3568,7 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
/* Free the sample points. Important to use the mutable loop here because we are erasing the list
* elements. */
LISTBASE_FOREACH_MUTABLE (tSamplePoint *, temp, &points) {
- if (temp->dw != NULL) {
+ if (temp->dw != nullptr) {
MEM_freeN(temp->dw);
}
MEM_SAFE_FREE(temp);
@@ -3601,14 +3620,14 @@ void BKE_gpencil_stroke_from_view_space(RegionView3D *rv3d,
/* ----------------------------------------------------------------------------- */
/* Stroke to perimeter */
-typedef struct tPerimeterPoint {
+struct tPerimeterPoint {
struct tPerimeterPoint *next, *prev;
float x, y, z;
-} tPerimeterPoint;
+};
static tPerimeterPoint *new_perimeter_point(const float pt[3])
{
- tPerimeterPoint *new_pt = MEM_callocN(sizeof(tPerimeterPoint), __func__);
+ tPerimeterPoint *new_pt = (tPerimeterPoint *)MEM_callocN(sizeof(tPerimeterPoint), __func__);
copy_v3_v3(&new_pt->x, pt);
return new_pt;
}
@@ -3771,14 +3790,14 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
{
/* sanity check */
if (gps->totpoints < 1) {
- return NULL;
+ return nullptr;
}
float defaultpixsize = 1000.0f / gpd->pixfactor;
float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f;
- ListBase *perimeter_right_side = MEM_callocN(sizeof(ListBase), __func__);
- ListBase *perimeter_left_side = MEM_callocN(sizeof(ListBase), __func__);
+ ListBase *perimeter_right_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
+ ListBase *perimeter_left_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
int num_perimeter_points = 0;
bGPDspoint *first = &gps->points[0];
@@ -4018,7 +4037,7 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
const float diff_mat[4][4])
{
if (gps->totpoints == 0) {
- return NULL;
+ return nullptr;
}
bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, true, false);
const bool cyclic = ((gps_temp->flag & GP_STROKE_CYCLIC) != 0);
@@ -4026,8 +4045,8 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
/* If Cyclic, add a new point. */
if (cyclic && (gps_temp->totpoints > 1)) {
gps_temp->totpoints++;
- gps_temp->points = MEM_recallocN(gps_temp->points,
- sizeof(*gps_temp->points) * gps_temp->totpoints);
+ gps_temp->points = (bGPDspoint *)MEM_recallocN(
+ gps_temp->points, sizeof(*gps_temp->points) * gps_temp->totpoints);
bGPDspoint *pt_src = &gps_temp->points[0];
bGPDspoint *pt_dst = &gps_temp->points[gps_temp->totpoints - 1];
copy_v3_v3(&pt_dst->x, &pt_src->x);
@@ -4043,7 +4062,7 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
gpd, gpl, gps_temp, subdivisions, &num_perimeter_points);
if (num_perimeter_points == 0) {
- return NULL;
+ return nullptr;
}
/* Create new stroke. */
diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc
index 7e9f81f9c83..12a0a1e3ae7 100644
--- a/source/blender/blenkernel/intern/icons.cc
+++ b/source/blender/blenkernel/intern/icons.cc
@@ -667,7 +667,7 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
BKE_previewimg_finish(prv, i);
}
else {
- /* Only for old files that didn't write the flag . */
+ /* Only for old files that didn't write the flag. */
prv->flag[i] |= PRV_UNFINISHED;
}
}
diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c
index 9e3d5a162ae..360bad3e786 100644
--- a/source/blender/blenkernel/intern/image_save.c
+++ b/source/blender/blenkernel/intern/image_save.c
@@ -135,8 +135,8 @@ static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
/**
* \return success.
- * \note ``ima->filepath`` and ``ibuf->name`` should end up the same.
- * \note for multiview the first ``ibuf`` is important to get the settings.
+ * \note `ima->filepath` and `ibuf->name` should end up the same.
+ * \note for multi-view the first `ibuf` is important to get the settings.
*/
static bool image_save_single(ReportList *reports,
Image *ima,
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 730c989abc9..28282aaa823 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -1237,7 +1237,7 @@ void BKE_layer_collection_isolate_global(Scene *scene,
bool hide_it = extend && (lc->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER);
if (!extend) {
- /* Hide all collections . */
+ /* Hide all collections. */
LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
layer_collection_flag_set_recursive(lc_iter, LAYER_COLLECTION_HIDE);
}
diff --git a/source/blender/blenkernel/intern/main_idmap.c b/source/blender/blenkernel/intern/main_idmap.c
index 1d362db4432..1421d456883 100644
--- a/source/blender/blenkernel/intern/main_idmap.c
+++ b/source/blender/blenkernel/intern/main_idmap.c
@@ -49,9 +49,9 @@
* \{ */
struct IDNameLib_Key {
- /** ``ID.name + 2``: without the ID type prefix, since each id type gets its own 'map' */
+ /** `ID.name + 2`: without the ID type prefix, since each id type gets its own 'map'. */
const char *name;
- /** ``ID.lib``: */
+ /** `ID.lib`: */
const Library *lib;
};
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 760febaca91..9dd583b4c6b 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -305,7 +305,7 @@ static void build_bvh_spatial(PROCESS *process,
/**
* Computes density from given metaball at given position.
- * Metaball equation is: ``(1 - r^2 / R^2)^3 * s``
+ * Metaball equation is: `(1 - r^2 / R^2)^3 * s`
*
* r = distance from center
* R = metaball radius
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index b463d903303..8d74002ad79 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -1874,6 +1874,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
}
mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
+ mesh->runtime.cd_dirty_loop &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_split(Mesh *mesh)
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index e777eb7ffe9..0e4fe91e577 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -212,54 +212,19 @@ static void make_edges_mdata_extend(
}
/* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
-/* return non-zero on error */
-int BKE_mesh_nurbs_to_mdata(Object *ob,
- MVert **r_allvert,
- int *r_totvert,
- MEdge **r_alledge,
- int *r_totedge,
- MLoop **r_allloop,
- MPoly **r_allpoly,
- int *r_totloop,
- int *r_totpoly)
-{
- ListBase disp = {NULL, NULL};
-
- if (ob->runtime.curve_cache) {
- disp = ob->runtime.curve_cache->disp;
- }
-
- return BKE_mesh_nurbs_displist_to_mdata(ob,
- &disp,
- r_allvert,
- r_totvert,
- r_alledge,
- r_totedge,
- r_allloop,
- r_allpoly,
- NULL,
- r_totloop,
- r_totpoly);
-}
-
-/* BMESH: this doesn't calculate all edges from polygons,
- * only free standing edges are calculated */
-
-/* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
/* use specified dispbase */
-int BKE_mesh_nurbs_displist_to_mdata(const Object *ob,
- const ListBase *dispbase,
- MVert **r_allvert,
- int *r_totvert,
- MEdge **r_alledge,
- int *r_totedge,
- MLoop **r_allloop,
- MPoly **r_allpoly,
- MLoopUV **r_alluv,
- int *r_totloop,
- int *r_totpoly)
+static int mesh_nurbs_displist_to_mdata(const Curve *cu,
+ const ListBase *dispbase,
+ MVert **r_allvert,
+ int *r_totvert,
+ MEdge **r_alledge,
+ int *r_totedge,
+ MLoop **r_allloop,
+ MPoly **r_allpoly,
+ MLoopUV **r_alluv,
+ int *r_totloop,
+ int *r_totpoly)
{
- const Curve *cu = ob->data;
MVert *mvert;
MPoly *mpoly;
MLoop *mloop;
@@ -272,7 +237,7 @@ int BKE_mesh_nurbs_displist_to_mdata(const Object *ob,
/* 2d polys are filled with DL_INDEX3 displists */
(CU_DO_2DFILL(cu) == false) ||
/* surf polys are never filled */
- (ob->type == OB_SURF));
+ BKE_curve_type_get(cu) == OB_SURF);
/* count */
LISTBASE_FOREACH (const DispList *, dl, dispbase) {
@@ -527,17 +492,17 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(const Object *ob, const ListBase *
MLoopUV *alluv = NULL;
int totvert, totedge, totloop, totpoly;
- if (BKE_mesh_nurbs_displist_to_mdata(ob,
- dispbase,
- &allvert,
- &totvert,
- &alledge,
- &totedge,
- &allloop,
- &allpoly,
- &alluv,
- &totloop,
- &totpoly) != 0) {
+ if (mesh_nurbs_displist_to_mdata(ob->data,
+ dispbase,
+ &allvert,
+ &totvert,
+ &alledge,
+ &totedge,
+ &allloop,
+ &allpoly,
+ &alluv,
+ &totloop,
+ &totpoly) != 0) {
/* Error initializing mdata. This often happens when curve is empty */
return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
}
@@ -571,7 +536,7 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(const Object *ob, const ListBase *
return mesh;
}
-Mesh *BKE_mesh_new_nomain_from_curve(Object *ob)
+Mesh *BKE_mesh_new_nomain_from_curve(const Object *ob)
{
ListBase disp = {NULL, NULL};
@@ -589,7 +554,6 @@ void BKE_mesh_from_nurbs_displist(
Object *ob1;
Mesh *me_eval = (Mesh *)ob->runtime.data_eval;
Mesh *me;
- Curve *cu;
MVert *allvert = NULL;
MEdge *alledge = NULL;
MLoop *allloop = NULL;
@@ -597,20 +561,20 @@ void BKE_mesh_from_nurbs_displist(
MPoly *allpoly = NULL;
int totvert, totedge, totloop, totpoly;
- cu = ob->data;
+ Curve *cu = ob->data;
if (me_eval == NULL) {
- if (BKE_mesh_nurbs_displist_to_mdata(ob,
- dispbase,
- &allvert,
- &totvert,
- &alledge,
- &totedge,
- &allloop,
- &allpoly,
- &alluv,
- &totloop,
- &totpoly) != 0) {
+ if (mesh_nurbs_displist_to_mdata(cu,
+ dispbase,
+ &allvert,
+ &totvert,
+ &alledge,
+ &totedge,
+ &allloop,
+ &allpoly,
+ &alluv,
+ &totloop,
+ &totpoly) != 0) {
/* Error initializing */
return;
}
@@ -702,18 +666,6 @@ void BKE_mesh_from_nurbs_displist(
}
}
-void BKE_mesh_from_nurbs(Main *bmain, Object *ob)
-{
- Curve *cu = (Curve *)ob->data;
- ListBase disp = {NULL, NULL};
-
- if (ob->runtime.curve_cache) {
- disp = ob->runtime.curve_cache->disp;
- }
-
- BKE_mesh_from_nurbs_displist(bmain, ob, &disp, cu->id.name, false);
-}
-
typedef struct EdgeLink {
struct EdgeLink *next, *prev;
void *edge;
@@ -1152,8 +1104,8 @@ static Mesh *mesh_new_from_curve_type_object(Object *object)
BKE_mesh_from_nurbs_displist(
NULL, temp_object, &temp_object->runtime.curve_cache->disp, curve->id.name + 2, true);
- /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. If it didn't the curve did
- * not have any segments or otherwise would have generated an empty mesh. */
+ /* BKE_mesh_from_nurbs_displist changes the type to a mesh, check it worked. If it didn't
+ * the curve did not have any segments or otherwise would have generated an empty mesh. */
if (temp_object->type != OB_MESH) {
BKE_id_free(NULL, temp_object->data);
BKE_id_free(NULL, temp_object);
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
index 5ecf5ae316d..7a776b0ecb7 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.c
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -95,9 +95,14 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
}
}
-/* Copied from cdDM_foreachMappedEdge */
+/**
+ * Copied from #cdDM_foreachMappedEdge.
+ * \param tot_edges: Number of original edges. Used to avoid calling the callback with invalid
+ * edge indices.
+ */
void BKE_mesh_foreach_mapped_edge(
Mesh *mesh,
+ const int tot_edges,
void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
void *userData)
{
@@ -138,7 +143,7 @@ void BKE_mesh_foreach_mapped_edge(
func(userData, orig, mv[med->v1].co, mv[med->v2].co);
}
}
- else {
+ else if (mesh->totedge == tot_edges) {
for (int i = 0; i < mesh->totedge; i++, med++) {
func(userData, i, mv[med->v1].co, mv[med->v2].co);
}
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index ca6c60557a6..d28bb9c0744 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -539,8 +539,8 @@ void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
* \param totfinal: The size of \a final_origindex
* \param final_origindex: The size of the final array.
*
- * \note ``totsource`` could be ``totpoly``,
- * ``totfinal`` could be ``tottessface`` and ``final_origindex`` its ORIGINDEX customdata.
+ * \note `totsource` could be `totpoly`,
+ * `totfinal` could be `tottessface` and `final_origindex` its ORIGINDEX custom-data.
* This would allow an MPoly to loop over its tessfaces.
*/
void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index 2fe132fc684..f496d6eada1 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -530,6 +530,36 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
lnors_spacearr->data_type = data_type;
}
+/**
+ * Utility for multi-threaded calculation that ensures
+ * `lnors_spacearr_tls` doesn't share memory with `lnors_spacearr`
+ * that would cause it not to be thread safe.
+ *
+ * \note This works as long as threads never operate on the same loops at once.
+ */
+void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr,
+ MLoopNorSpaceArray *lnors_spacearr_tls)
+{
+ *lnors_spacearr_tls = *lnors_spacearr;
+ lnors_spacearr_tls->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+}
+
+/**
+ * Utility for multi-threaded calculation
+ * that merges `lnors_spacearr_tls` into `lnors_spacearr`.
+ */
+void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr,
+ MLoopNorSpaceArray *lnors_spacearr_tls)
+{
+ BLI_assert(lnors_spacearr->data_type == lnors_spacearr_tls->data_type);
+ BLI_assert(lnors_spacearr->mem != lnors_spacearr_tls->mem);
+ lnors_spacearr->num_spaces += lnors_spacearr_tls->num_spaces;
+ BLI_memarena_merge(lnors_spacearr->mem, lnors_spacearr_tls->mem);
+ BLI_memarena_free(lnors_spacearr_tls->mem);
+ lnors_spacearr_tls->mem = nullptr;
+ BKE_lnor_spacearr_clear(lnors_spacearr_tls);
+}
+
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr)
{
lnors_spacearr->num_spaces = 0;
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 85d30fc8c8b..e9608457896 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -1212,10 +1212,12 @@ static void update_typeinfo(Main *bmain,
FOREACH_NODETREE_END;
}
-/* Try to initialize all typeinfo in a node tree.
- * NB: In general undefined typeinfo is a perfectly valid case,
+/**
+ * Try to initialize all type-info in a node tree.
+ *
+ * \note In general undefined type-info is a perfectly valid case,
* the type may just be registered later.
- * In that case the update_typeinfo function will set typeinfo on registration
+ * In that case the update_typeinfo function will set type-info on registration
* and do necessary updates.
*/
void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree)
@@ -5117,9 +5119,11 @@ static void registerGeometryNodes()
register_node_type_geo_curve_primitive_star();
register_node_type_geo_curve_resample();
register_node_type_geo_curve_reverse();
+ register_node_type_geo_curve_set_handles();
register_node_type_geo_curve_subdivide();
register_node_type_geo_curve_to_mesh();
register_node_type_geo_curve_to_points();
+ register_node_type_geo_curve_trim();
register_node_type_geo_delete_geometry();
register_node_type_geo_edge_split();
register_node_type_geo_input_material();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 941db80b76c..89de37d6e4b 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1653,7 +1653,7 @@ static void object_update_from_subsurf_ccg(Object *object)
*
* All this is defeating all the designs we need to follow to allow safe
* threaded evaluation, but this is as good as we can make it within the
- * current sculpt//evaluated mesh design. This is also how we've survived
+ * current sculpt/evaluated mesh design. This is also how we've survived
* with old DerivedMesh based solutions. So, while this is all wrong and
* needs reconsideration, doesn't seem to be a big stopper for real
* production artists.
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 7cdea14e9bd..7e15ac5de5d 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -388,31 +388,12 @@ void BKE_object_batch_cache_dirty_tag(Object *ob)
BKE_object_data_batch_cache_dirty_tag(ob->data);
}
-void BKE_object_data_eval_batch_cache_dirty_tag(Depsgraph *depsgraph, ID *object_data)
-{
- DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data);
- BKE_object_data_batch_cache_dirty_tag(object_data);
-}
-
-void BKE_object_data_eval_batch_cache_deform_tag(Depsgraph *depsgraph, ID *object_data)
-{
- DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data);
- switch (GS(object_data->name)) {
- case ID_ME:
- BKE_mesh_batch_cache_dirty_tag((Mesh *)object_data, BKE_MESH_BATCH_DIRTY_DEFORM);
- break;
- default:
- /* Only mesh is currently supported. Fallback to dirty all for other datablocks types. */
- BKE_object_data_batch_cache_dirty_tag(object_data);
- break;
- }
-}
-
void BKE_object_eval_uber_data(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type != OB_ARMATURE);
BKE_object_handle_data_update(depsgraph, scene, ob);
+ BKE_object_batch_cache_dirty_tag(ob);
}
void BKE_object_eval_ptcache_reset(Depsgraph *depsgraph, Scene *scene, Object *object)
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 1af66fa090b..a1fa6aae1ce 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -880,7 +880,7 @@ static int palettecolor_compare_luminance(const void *a1, const void *a2)
void BKE_palette_sort_hsv(tPaletteColorHSV *color_array, const int totcol)
{
- /* Sort by Hue , Saturation and Value. */
+ /* Sort by Hue, Saturation and Value. */
qsort(color_array, totcol, sizeof(tPaletteColorHSV), palettecolor_compare_hsv);
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index db1fbb56125..f2f3c5d4ca6 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -4418,12 +4418,12 @@ void psys_get_texture(
if ((event & mtex->mapto) & PAMAP_TIME) {
/* the first time has to set the base value for time regardless of blend mode */
- if ((setvars & MAP_PA_TIME) == 0) {
+ if ((setvars & PAMAP_TIME) == 0) {
int flip = (mtex->timefac < 0.0f);
float timefac = fabsf(mtex->timefac);
ptex->time *= 1.0f - timefac;
ptex->time += timefac * ((flip) ? 1.0f - value : value);
- setvars |= MAP_PA_TIME;
+ setvars |= PAMAP_TIME;
}
else {
ptex->time = texture_value_blend(def, ptex->time, value, mtex->timefac, blend);
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index d3d7f02ecad..93cffcf7164 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1168,12 +1168,12 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
}
/**
- * The 2 new faces created and assigned to ``f_new`` have their
+ * The 2 new faces created and assigned to `f_new` have their
* verts & edges shuffled around.
*
* - faces wind anticlockwise in this example.
- * - original edge is ``(v1, v2)``
- * - original face is ``(v1, v2, v3)``
+ * - original edge is `(v1, v2)`
+ * - original face is `(v1, v2, v3)`
*
* <pre>
* + v3(v_opp)
@@ -1189,8 +1189,8 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
* (first) (second)
* </pre>
*
- * - f_new (first): ``v_tri=(v1, v4, v3), e_tri=(e1, e5, e4)``
- * - f_new (second): ``v_tri=(v4, v2, v3), e_tri=(e2, e3, e5)``
+ * - f_new (first): `v_tri=(v1, v4, v3), e_tri=(e1, e5, e4)`
+ * - f_new (second): `v_tri=(v4, v2, v3), e_tri=(e2, e3, e5)`
*/
/* Create two new faces */
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index cc5a8536a5a..a3a0ce0060b 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -2105,7 +2105,7 @@ Object *BKE_scene_object_find_by_name(const Scene *scene, const char *name)
/**
* Sets the active scene, mainly used when running in background mode
- * (``--scene`` command line argument).
+ * (`--scene` command line argument).
* This is also called to set the scene directly, bypassing windowing code.
* Otherwise #WM_window_set_active_scene is used when changing scenes by the user.
*/
@@ -3242,9 +3242,9 @@ void BKE_scene_multiview_filepath_get(SceneRenderView *srv, const char *filepath
}
/**
- * When multiview is not used the filepath is as usual (e.g., ``Image.jpg``).
+ * When multiview is not used the filepath is as usual (e.g., `Image.jpg`).
* When multiview is on, even if only one view is enabled the view is incorporated
- * into the file name (e.g., ``Image_L.jpg``). That allows for the user to re-render
+ * into the file name (e.g., `Image_L.jpg`). That allows for the user to re-render
* individual views.
*/
void BKE_scene_multiview_view_filepath_get(const RenderData *rd,
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index 6234cdf87e2..a7caae967f6 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -410,7 +410,7 @@ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
const float *offset = std::lower_bound(lengths.begin(), lengths.end(), length);
const int index = offset - lengths.begin();
- const int next_index = (index == this->size() - 1) ? 0 : index + 1;
+ const int next_index = (index == this->evaluated_points_size() - 1) ? 0 : index + 1;
const float previous_length = (index == 0) ? 0.0f : lengths[index - 1];
const float factor = (length - previous_length) / (lengths[index] - previous_length);
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index cff2c5cc562..a1b45c2ac7d 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -423,7 +423,7 @@ static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *
/* get some info from CCGSubSurf */
totface = ccgSubSurf_getNumFaces(uvss);
- /* edgeSize = ccgSubSurf_getEdgeSize(uvss); */ /*UNUSED*/
+ // edgeSize = ccgSubSurf_getEdgeSize(uvss); /* UNUSED */
gridSize = ccgSubSurf_getGridSize(uvss);
gridFaces = gridSize - 1;
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index d9f02ce4c75..4581d410444 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -1303,7 +1303,7 @@ const char *BKE_unit_identifier_get(const void *usys_pt, int index)
{
const bUnitDef *unit = ((const bUnitCollection *)usys_pt)->units + index;
if (unit->identifier == NULL) {
- BLI_assert(false && "identifier for this unit is not specified yet");
+ BLI_assert_msg(0, "identifier for this unit is not specified yet");
}
return unit->identifier;
}
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 5cac149c503..059dc68b1dc 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -58,7 +58,7 @@ static void workspace_init_data(ID *id)
{
WorkSpace *workspace = (WorkSpace *)id;
- BKE_asset_library_reference_init_default(&workspace->active_asset_library);
+ BKE_asset_library_reference_init_default(&workspace->asset_library);
}
static void workspace_free_data(ID *id)
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 560ae30967f..9b3103a638b 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -1747,9 +1747,10 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset)
rd->ffcodecdata.type = FFMPEG_MPEG2;
rd->ffcodecdata.video_bitrate = 6000;
- /* Don't set resolution, see T21351.
- * rd->xsch = 720;
- * rd->ysch = isntsc ? 480 : 576; */
+# if 0 /* Don't set resolution, see T21351. */
+ rd->xsch = 720;
+ rd->ysch = isntsc ? 480 : 576;
+# endif
rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
rd->ffcodecdata.rc_max_rate = 9000;
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index e40a79dad21..6bf29a6168f 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -58,7 +58,7 @@ void _bli_array_grow_func(void **arr_p,
/** \name Public defines
* \{ */
-/** use ``sizeof(*(arr))`` to ensure the array exists and is an array */
+/** use `sizeof(*(arr))` to ensure the array exists and is an array */
#define BLI_array_declare(arr) \
int _##arr##_len = ((void)(sizeof(*(arr))), 0); \
void *_##arr##_static = NULL
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
index 76dfcf0b57d..d93bd7f6f76 100644
--- a/source/blender/blenlib/BLI_color.hh
+++ b/source/blender/blenlib/BLI_color.hh
@@ -34,11 +34,11 @@ namespace blender {
* Usage:
*
* Convert a theme byte color to a linearrgb premultiplied.
- * ```
+ * \code{.cc}
* ColorTheme4b theme_color;
* ColorSceneLinear4f<eAlpha::Premultiplied> linearrgb_color =
* BLI_color_convert_to_scene_linear(theme_color).premultiply_alpha();
- * ```
+ * \endcode
*
* The API is structured to make most use of inlining. Most notable are space
* conversions done via `BLI_color_convert_to*` functions.
diff --git a/source/blender/blenlib/BLI_compiler_typecheck.h b/source/blender/blenlib/BLI_compiler_typecheck.h
index d9c2bfc1d58..18be2190c1b 100644
--- a/source/blender/blenlib/BLI_compiler_typecheck.h
+++ b/source/blender/blenlib/BLI_compiler_typecheck.h
@@ -86,7 +86,7 @@
/**
* CHECK_TYPE_ANY: handy macro, eg:
- * ``CHECK_TYPE_ANY(var, Foo *, Bar *, Baz *)``
+ * `CHECK_TYPE_ANY(var, Foo *, Bar *, Baz *)`
*
* excuse ridiculously long generated args.
* \code{.py}
diff --git a/source/blender/blenlib/BLI_delaunay_2d.h b/source/blender/blenlib/BLI_delaunay_2d.h
index d42bd6af637..658dcadadce 100644
--- a/source/blender/blenlib/BLI_delaunay_2d.h
+++ b/source/blender/blenlib/BLI_delaunay_2d.h
@@ -110,6 +110,10 @@ extern "C" {
* If zero is supplied for epsilon, an internal value of 1e-8 used
* instead, since this code will not work correctly if it is not allowed
* to merge "too near" vertices.
+ *
+ * Normally the output will contain mappings from outputs to inputs.
+ * If this is not needed, set need_ids to false and the execution may be much
+ * faster in some circumstances.
*/
typedef struct CDT_input {
int verts_len;
@@ -121,6 +125,7 @@ typedef struct CDT_input {
int *faces_start_table;
int *faces_len_table;
float epsilon;
+ bool need_ids;
} CDT_input;
/**
@@ -140,6 +145,7 @@ typedef struct CDT_input {
* a run-together array and a "start" and "len" extra array,
* similar triples are used to represent the output to input
* mapping of vertices, edges, and faces.
+ * These are only set if need_ids is true in the input.
*
* Those triples are:
* - verts_orig, verts_orig_start_table, verts_orig_len_table
@@ -236,6 +242,7 @@ template<typename Arith_t> class CDT_input {
Array<std::pair<int, int>> edge;
Array<Vector<int>> face;
Arith_t epsilon{0};
+ bool need_ids{true};
};
template<typename Arith_t> class CDT_result {
@@ -243,6 +250,7 @@ template<typename Arith_t> class CDT_result {
Array<vec2<Arith_t>> vert;
Array<std::pair<int, int>> edge;
Array<Vector<int>> face;
+ /* The orig vectors are only populated if the need_ids input field is true. */
/** For each output vert, which input verts correspond to it? */
Array<Vector<int>> vert_orig;
/**
diff --git a/source/blender/blenlib/BLI_dlrbTree.h b/source/blender/blenlib/BLI_dlrbTree.h
index 8c20e3d3988..03aab8d2895 100644
--- a/source/blender/blenlib/BLI_dlrbTree.h
+++ b/source/blender/blenlib/BLI_dlrbTree.h
@@ -111,20 +111,22 @@ void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree);
/* Searching ------------------------------------ */
/* Find the node which matches or is the closest to the requested node */
-DLRBT_Node *BLI_dlrbTree_search(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data);
+DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
+ DLRBT_Comparator_FP cmp_cb,
+ void *search_data);
/* Find the node which exactly matches the required data */
-DLRBT_Node *BLI_dlrbTree_search_exact(DLRBT_Tree *tree,
+DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
/* Find the node which occurs immediately before the best matching node */
-DLRBT_Node *BLI_dlrbTree_search_prev(DLRBT_Tree *tree,
+DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
/* Find the node which occurs immediately after the best matching node */
-DLRBT_Node *BLI_dlrbTree_search_next(DLRBT_Tree *tree,
+DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
@@ -137,7 +139,8 @@ short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *
*/
/* Add the given data to the tree, and return the node added */
-// NOTE: for duplicates, the update_cb is called (if available), and the existing node is returned
+/* NOTE: for duplicates, the update_cb is called (if available),
+ * and the existing node is returned. */
DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
DLRBT_NAlloc_FP new_cb,
@@ -145,7 +148,7 @@ DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree,
void *data);
/* Remove the given element from the tree and balance again */
-// FIXME: this is not implemented yet...
+/* FIXME: this is not implemented yet... */
// void BLI_dlrbTree_remove(DLRBT_Tree *tree, DLRBT_Node *node);
/* Node Operations (Manual) --------------------- */
diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh
index 396b0b1bd21..8ff4f94f95c 100644
--- a/source/blender/blenlib/BLI_float4x4.hh
+++ b/source/blender/blenlib/BLI_float4x4.hh
@@ -51,8 +51,14 @@ struct float4x4 {
{
BLI_ASSERT_UNIT_V3(forward);
BLI_ASSERT_UNIT_V3(up);
+
+ /* Negate the cross product so that the resulting matrix has determinant 1 (instead of -1).
+ * Without the negation, the result would be a so called improper rotation. That means it
+ * contains a reflection. Such an improper rotation matrix could not be converted to another
+ * representation of a rotation such as euler angles. */
+ const float3 cross = -float3::cross(forward, up);
+
float4x4 matrix;
- const float3 cross = float3::cross(forward, up);
matrix.values[0][0] = forward.x;
matrix.values[1][0] = cross.x;
matrix.values[2][0] = up.x;
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index e708b327bd4..a2c5c6349a5 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -77,7 +77,7 @@ enum {
/* -------------------------------------------------------------------- */
/** \name GHash API
*
- * Defined in ``BLI_ghash.c``
+ * Defined in `BLI_ghash.c`
* \{ */
GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
@@ -333,11 +333,11 @@ double BLI_gset_calc_quality(GSet *gs);
/* -------------------------------------------------------------------- */
/** \name GHash/GSet Utils
*
- * Defined in ``BLI_ghash_utils.c``
+ * Defined in `BLI_ghash_utils.c`
* \{ */
/**
- * Callbacks for GHash (``BLI_ghashutil_``)
+ * Callbacks for GHash (`BLI_ghashutil_`)
*
* \note '_p' suffix denotes void pointer arg,
* so we can have functions that take correctly typed args too.
diff --git a/source/blender/blenlib/BLI_link_utils.h b/source/blender/blenlib/BLI_link_utils.h
index e1e4a8dbd4a..7aa7300da16 100644
--- a/source/blender/blenlib/BLI_link_utils.h
+++ b/source/blender/blenlib/BLI_link_utils.h
@@ -20,7 +20,7 @@
* \ingroup bli
* \brief Single link-list utility macros. (header only api).
*
- * Use this api when the structure defines its own ``next`` pointer
+ * Use this api when the structure defines its own `next` pointer
* and a double linked list such as #ListBase isn't needed.
*/
diff --git a/source/blender/blenlib/BLI_linklist_stack.h b/source/blender/blenlib/BLI_linklist_stack.h
index 8a5e94a7b56..d07bc40c923 100644
--- a/source/blender/blenlib/BLI_linklist_stack.h
+++ b/source/blender/blenlib/BLI_linklist_stack.h
@@ -28,7 +28,7 @@
* \note These macros follow STACK_* macros defined in 'BLI_utildefines.h'
* and should be kept (mostly) interchangeable.
*
- * \note ``_##var##_type`` is a dummy variable only used for typechecks.
+ * \note `_##var##_type` is a dummy variable only used for type-checks.
*/
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/BLI_math.h b/source/blender/blenlib/BLI_math.h
index 3b61c0feb51..5768b098d2f 100644
--- a/source/blender/blenlib/BLI_math.h
+++ b/source/blender/blenlib/BLI_math.h
@@ -26,32 +26,32 @@
*
* \section mathabbrev Abbreviations
*
- * - ``fl`` = float
- * - ``db`` = double
- * - ``v2`` = vec2 = vector 2
- * - ``v3`` = vec3 = vector 3
- * - ``v4`` = vec4 = vector 4
- * - ``vn`` = vec4 = vector N dimensions, *passed as an arg, after the vector*.
- * - ``qt`` = quat = quaternion
- * - ``dq`` = dquat = dual quaternion
- * - ``m2`` = mat2 = matrix 2x2
- * - ``m3`` = mat3 = matrix 3x3
- * - ``m4`` = mat4 = matrix 4x4
- * - ``eul`` = euler rotation
- * - ``eulO`` = euler with order
- * - ``plane`` = plane 4, (vec3, distance)
- * - ``plane3`` = plane 3 (same as a ``plane`` with a zero 4th component)
+ * - `fl` = float
+ * - `db` = double
+ * - `v2` = vec2 = vector 2
+ * - `v3` = vec3 = vector 3
+ * - `v4` = vec4 = vector 4
+ * - `vn` = vec4 = vector N dimensions, *passed as an arg, after the vector*.
+ * - `qt` = quat = quaternion
+ * - `dq` = dquat = dual quaternion
+ * - `m2` = mat2 = matrix 2x2
+ * - `m3` = mat3 = matrix 3x3
+ * - `m4` = mat4 = matrix 4x4
+ * - `eul` = euler rotation
+ * - `eulO` = euler with order
+ * - `plane` = plane 4, (vec3, distance)
+ * - `plane3` = plane 3 (same as a `plane` with a zero 4th component)
*
* \subsection mathabbrev_all Function Type Abbreviations
*
* For non float versions of functions (which typically operate on floats),
* use single suffix abbreviations.
*
- * - ``_d`` = double
- * - ``_i`` = int
- * - ``_u`` = unsigned int
- * - ``_char`` = char
- * - ``_uchar`` = unsigned char
+ * - `_d` = double
+ * - `_i` = int
+ * - `_u` = unsigned int
+ * - `_char` = char
+ * - `_uchar` = unsigned char
*
* \section mathvarnames Variable Names
*
diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c
index 86784557b25..8f7f722c71b 100644
--- a/source/blender/blenlib/intern/BLI_dynstr.c
+++ b/source/blender/blenlib/intern/BLI_dynstr.c
@@ -291,7 +291,7 @@ int BLI_dynstr_get_len(const DynStr *ds)
/**
* Get a DynStr's contents as a c-string.
* The \a rets argument must be allocated to be at
- * least the size of ``BLI_dynstr_get_len(ds) + 1``.
+ * least the size of `BLI_dynstr_get_len(ds) + 1`.
*
* \param ds: The DynStr of interest.
* \param rets: The string to fill.
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 46e599b7cf3..2c9285e418a 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -1270,7 +1270,7 @@ void BLI_gset_flag_clear(GSet *gs, uint flag)
/* -------------------------------------------------------------------- */
/** \name GSet Combined Key/Value Usage
*
- * \note Not typical ``set`` use, only use when the pointer identity matters.
+ * \note Not typical `set` use, only use when the pointer identity matters.
* This can be useful when the key references data stored outside the GSet.
* \{ */
diff --git a/source/blender/blenlib/intern/BLI_ghash_utils.c b/source/blender/blenlib/intern/BLI_ghash_utils.c
index 182c27aed6d..b9144009304 100644
--- a/source/blender/blenlib/intern/BLI_ghash_utils.c
+++ b/source/blender/blenlib/intern/BLI_ghash_utils.c
@@ -138,8 +138,8 @@ size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b)
* This function implements the widely used "djb" hash apparently posted
* by Daniel Bernstein to comp.lang.c some time ago. The 32 bit
* unsigned hash value starts at 5381 and for each byte 'c' in the
- * string, is updated: ``hash = hash * 33 + c``. This
- * function uses the signed value of each byte.
+ * string, is updated: `hash = hash * 33 + c`.
+ * This function uses the signed value of each byte.
*
* NOTE: this is the same hash method that glib 2.34.0 uses.
*/
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 25939323b73..674654c99a8 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -22,7 +22,7 @@
* \brief BVH-tree implementation.
*
* k-DOP BVH (Discrete Oriented Polytope, Bounding Volume Hierarchy).
- * A k-DOP is represented as k/2 pairs of min , max values for k/2 directions (intervals, "slabs").
+ * A k-DOP is represented as k/2 pairs of min, max values for k/2 directions (intervals, "slabs").
*
* See: http://www.gris.uni-tuebingen.de/people/staff/jmezger/papers/bvh.pdf
*
@@ -868,7 +868,7 @@ static void non_recursive_bvh_div_nodes(const BVHTree *tree,
* \{ */
/**
- * \note many callers don't check for ``NULL`` return.
+ * \note many callers don't check for `NULL` return.
*/
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
{
diff --git a/source/blender/blenlib/intern/BLI_memiter.c b/source/blender/blenlib/intern/BLI_memiter.c
index 3f255ce0e16..effbe5da5c4 100644
--- a/source/blender/blenlib/intern/BLI_memiter.c
+++ b/source/blender/blenlib/intern/BLI_memiter.c
@@ -73,7 +73,7 @@ typedef struct BLI_memiter_chunk {
struct BLI_memiter_chunk *next;
/**
* internal format is:
- * ``[next_pointer, size:data, size:data, ..., negative_offset]``
+ * `[next_pointer, size:data, size:data, ..., negative_offset]`
*
* Where negative offset rewinds to the start.
*/
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index 5263af2ae56..f968799326a 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -63,9 +63,9 @@
#endif
/**
- * Important that this value is an is _not_ aligned with ``sizeof(void *)``.
+ * Important that this value is an is _not_ aligned with `sizeof(void *)`.
* So having a pointer to 2/4/8... aligned memory is enough to ensure
- * the freeword will never be used.
+ * the `freeword` will never be used.
* To be safe, use a word that's the same in both directions.
*/
#define FREEWORD \
diff --git a/source/blender/blenlib/intern/BLI_mmap.c b/source/blender/blenlib/intern/BLI_mmap.c
index 71510b62ba1..c25e89df818 100644
--- a/source/blender/blenlib/intern/BLI_mmap.c
+++ b/source/blender/blenlib/intern/BLI_mmap.c
@@ -31,11 +31,11 @@
#ifndef WIN32
# include <signal.h>
# include <stdlib.h>
-# include <sys/mman.h> // for mmap
-# include <unistd.h> // for read close
+# include <sys/mman.h> /* For mmap. */
+# include <unistd.h> /* For read close. */
#else
# include "BLI_winstuff.h"
-# include <io.h> // for open close read
+# include <io.h> /* For open close read. */
#endif
struct BLI_mmap_file {
diff --git a/source/blender/blenlib/intern/DLRB_tree.c b/source/blender/blenlib/intern/DLRB_tree.c
index 09234dcfa26..436b9b8d782 100644
--- a/source/blender/blenlib/intern/DLRB_tree.c
+++ b/source/blender/blenlib/intern/DLRB_tree.c
@@ -128,7 +128,9 @@ void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree)
/* Tree Search Utilities */
/* Find the node which matches or is the closest to the requested node */
-DLRBT_Node *BLI_dlrbTree_search(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data)
+DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
+ DLRBT_Comparator_FP cmp_cb,
+ void *search_data)
{
DLRBT_Node *node = (tree) ? tree->root : NULL;
short found = 0;
@@ -174,7 +176,7 @@ DLRBT_Node *BLI_dlrbTree_search(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, vo
}
/* Find the node which exactly matches the required data */
-DLRBT_Node *BLI_dlrbTree_search_exact(DLRBT_Tree *tree,
+DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
{
@@ -222,7 +224,7 @@ DLRBT_Node *BLI_dlrbTree_search_exact(DLRBT_Tree *tree,
}
/* Find the node which occurs immediately before the best matching node */
-DLRBT_Node *BLI_dlrbTree_search_prev(DLRBT_Tree *tree,
+DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
{
@@ -253,7 +255,7 @@ DLRBT_Node *BLI_dlrbTree_search_prev(DLRBT_Tree *tree,
}
/* Find the node which occurs immediately after the best matching node */
-DLRBT_Node *BLI_dlrbTree_search_next(DLRBT_Tree *tree,
+DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
{
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index e1a7ee98ce5..5ad57a7bec8 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -1403,16 +1403,16 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info,
* Create a new array store, which can store any number of arrays
* as long as their stride matches.
*
- * \param stride: ``sizeof()`` each element,
+ * \param stride: `sizeof()` each element,
*
- * \note while a stride of ``1`` will always work,
+ * \note while a stride of `1` will always work,
* its less efficient since duplicate chunks of memory will be searched
* at positions unaligned with the array data.
*
* \param chunk_count: Number of elements to split each chunk into.
* - A small value increases the ability to de-duplicate chunks,
* but adds overhead by increasing the number of chunks to look up when searching for duplicates,
- * as well as some overhead constructing the original array again, with more calls to ``memcpy``.
+ * as well as some overhead constructing the original array again, with more calls to `memcpy`.
* - Larger values reduce the *book keeping* overhead,
* but increase the chance a small,
* isolated change will cause a larger amount of data to be duplicated.
diff --git a/source/blender/blenlib/intern/convexhull_2d.c b/source/blender/blenlib/intern/convexhull_2d.c
index cb4ef54bfb7..233a1430fe7 100644
--- a/source/blender/blenlib/intern/convexhull_2d.c
+++ b/source/blender/blenlib/intern/convexhull_2d.c
@@ -188,7 +188,7 @@ static int pointref_cmp_yx(const void *a_, const void *b_)
* \param points: An array of 2D points.
* \param n: The number of points in points.
* \param r_points: An array of the convex hull vertex indices (max is n).
- * _must_ be allocated as ``n * 2`` because of how its used internally,
+ * _must_ be allocated as `n * 2` because of how its used internally,
* even though the final result will be no more than \a n in size.
* \returns the number of points in r_points.
*/
diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc
index 24a58103a10..4582ea69d9b 100644
--- a/source/blender/blenlib/intern/delaunay_2d.cc
+++ b/source/blender/blenlib/intern/delaunay_2d.cc
@@ -19,6 +19,7 @@
*/
#include <algorithm>
+#include <atomic>
#include <fstream>
#include <iostream>
#include <sstream>
@@ -29,6 +30,8 @@
#include "BLI_math_boolean.hh"
#include "BLI_math_mpq.hh"
#include "BLI_mpq2.hh"
+#include "BLI_set.hh"
+#include "BLI_task.hh"
#include "BLI_vector.hh"
#include "BLI_delaunay_2d.h"
@@ -77,8 +80,8 @@ template<> double math_to_double<double>(const double v)
* Define a templated 2D arrangement of vertices, edges, and faces.
* The #SymEdge data structure is the basis for a structure that allows
* easy traversal to neighboring (by topology) geometric elements.
- * Each of #CDTVert, #CDTEdge, and #CDTFace have an input_id linked list,
- * whose nodes contain integers that keep track of which input verts, edges,
+ * Each of #CDTVert, #CDTEdge, and #CDTFace have an input_id set,
+ * which contain integers that keep track of which input verts, edges,
* and faces, respectively, that the element was derived from.
*
* While this could be cleaned up some, it is usable by other routines in Blender
@@ -195,8 +198,8 @@ template<typename T> struct CDTVert {
FatCo<T> co;
/** Some edge attached to it. */
SymEdge<T> *symedge{nullptr};
- /** List of corresponding vertex input ids. */
- LinkNode *input_ids{nullptr};
+ /** Set of corresponding vertex input ids. Not used if don't need_ids. */
+ blender::Set<int> input_ids;
/** Index into array that #CDTArrangement keeps. */
int index{-1};
/** Index of a CDTVert that this has merged to. -1 if no merge. */
@@ -209,8 +212,10 @@ template<typename T> struct CDTVert {
};
template<typename Arith_t> struct CDTEdge {
- /** List of input edge ids that this is part of. */
- LinkNode *input_ids{nullptr};
+ /** Set of input edge ids that this is part of.
+ * If don't need_ids, then should contain 0 if it is a constrained edge,
+ * else empty. */
+ blender::Set<int> input_ids;
/** The directed edges for this edge. */
SymEdge<Arith_t> symedges[2]{SymEdge<Arith_t>(), SymEdge<Arith_t>()};
@@ -220,8 +225,10 @@ template<typename Arith_t> struct CDTEdge {
template<typename Arith_t> struct CDTFace {
/** A symedge in face; only used during output, so only valid then. */
SymEdge<Arith_t> *symedge{nullptr};
- /** List of input face ids that this is part of. */
- LinkNode *input_ids{nullptr};
+ /** Set of input face ids that this is part of.
+ * If don't need_ids, then should contain 0 if it is part of a constrained face,
+ * else empty. */
+ blender::Set<int> input_ids;
/** Used by algorithms operating on CDT structures. */
int visit_index{0};
/** Marks this face no longer used. */
@@ -334,27 +341,30 @@ template<typename T> class CDT_state {
int face_edge_offset;
/** How close before coords considered equal. */
T epsilon;
+ /** Do we need to track ids? */
+ bool need_ids;
- explicit CDT_state(int num_input_verts, int num_input_edges, int num_input_faces, T epsilon);
+ explicit CDT_state(
+ int num_input_verts, int num_input_edges, int num_input_faces, T epsilon, bool need_ids);
};
template<typename T> CDTArrangement<T>::~CDTArrangement()
{
for (int i : this->verts.index_range()) {
CDTVert<T> *v = this->verts[i];
- BLI_linklist_free(v->input_ids, nullptr);
+ v->input_ids.clear();
delete v;
this->verts[i] = nullptr;
}
for (int i : this->edges.index_range()) {
CDTEdge<T> *e = this->edges[i];
- BLI_linklist_free(e->input_ids, nullptr);
+ e->input_ids.clear();
delete e;
this->edges[i] = nullptr;
}
for (int i : this->faces.index_range()) {
CDTFace<T> *f = this->faces[i];
- BLI_linklist_free(f->input_ids, nullptr);
+ f->input_ids.clear();
delete f;
this->faces[i] = nullptr;
}
@@ -431,11 +441,11 @@ template<typename T> std::ostream &operator<<(std::ostream &os, const CDT_state<
if (se) {
os << " edges out:\n";
do {
- if (se->next == NULL) {
+ if (se->next == nullptr) {
os << " [NULL] next/rot symedge, se=" << trunc_ptr(se) << "\n";
break;
}
- if (se->next->next == NULL) {
+ if (se->next->next == nullptr) {
os << " [NULL] next-next/rot symedge, se=" << trunc_ptr(se) << "\n";
break;
}
@@ -495,6 +505,7 @@ template<typename T> void cdt_draw(const std::string &label, const CDTArrangemen
constexpr int vert_radius = 3;
constexpr bool draw_vert_labels = true;
constexpr bool draw_edge_labels = false;
+ constexpr bool draw_face_labels = false;
if (cdt.verts.size() == 0) {
return;
@@ -559,7 +570,7 @@ template<typename T> void cdt_draw(const std::string &label, const CDTArrangemen
const CDTVert<T> *v = e->symedges[1].vert;
const vec2<double> &uco = u->co.approx;
const vec2<double> &vco = v->co.approx;
- int strokew = e->input_ids == nullptr ? thin_line : thick_line;
+ int strokew = e->input_ids.size() == 0 ? thin_line : thick_line;
f << R"(<line fill="none" stroke="black" stroke-width=")" << strokew << "\" x1=\""
<< SX(uco[0]) << "\" y1=\"" << SY(uco[1]) << "\" x2=\"" << SX(vco[0]) << "\" y2=\""
<< SY(vco[1]) << "\">\n";
@@ -586,6 +597,54 @@ template<typename T> void cdt_draw(const std::string &label, const CDTArrangemen
++i;
}
+ if (draw_face_labels) {
+ for (const CDTFace<T> *face : cdt.faces) {
+ if (!face->deleted) {
+ /* Since may not have prepared output yet, need a slow find of a SymEdge for this face. */
+ const SymEdge<T> *se_face_start = nullptr;
+ for (const CDTEdge<T> *e : cdt.edges) {
+ if (e->symedges[0].face == face) {
+ se_face_start = &e->symedges[0];
+ break;
+ }
+ if (e->symedges[1].face == face) {
+ se_face_start = &e->symedges[1];
+ }
+ }
+ if (se_face_start != nullptr) {
+ /* Find center of face. */
+ int face_nverts = 0;
+ vec2<double> cen(0.0, 0.0);
+ if (face == cdt.outer_face) {
+ cen.x = minx;
+ cen.y = miny;
+ }
+ else {
+ const SymEdge<T> *se = se_face_start;
+ do {
+ if (se->face == face) {
+ cen = cen + se->vert->co.approx;
+ face_nverts++;
+ }
+ } while ((se = se->next) != se_face_start);
+ if (face_nverts > 0) {
+ cen = cen / double(face_nverts);
+ }
+ }
+ f << "<text x=\"" << SX(cen[0]) << "\" y=\"" << SY(cen[1]) << "\""
+ << " font-size=\"small\">[";
+ f << trunc_ptr(face);
+ if (face->input_ids.size() > 0) {
+ for (int id : face->input_ids) {
+ f << " " << id;
+ }
+ }
+ f << "]</text>\n";
+ }
+ }
+ }
+ }
+
append = true;
# undef SX
# undef SY
@@ -754,7 +813,6 @@ template<> CDTVert<double>::CDTVert(const vec2<double> &pt)
this->co.exact = pt;
this->co.approx = pt;
this->co.abs_approx = pt; /* Not used, so doesn't matter. */
- this->input_ids = nullptr;
this->symedge = nullptr;
this->index = -1;
this->merge_to_index = -1;
@@ -767,7 +825,6 @@ template<> CDTVert<mpq_class>::CDTVert(const vec2<mpq_class> &pt)
this->co.exact = pt;
this->co.approx = double2(pt.x.get_d(), pt.y.get_d());
this->co.abs_approx = double2(fabs(this->co.approx.x), fabs(this->co.approx.y));
- this->input_ids = nullptr;
this->symedge = nullptr;
this->index = -1;
this->merge_to_index = -1;
@@ -824,35 +881,21 @@ template<typename T> void CDTArrangement<T>::reserve(int num_verts, int num_edge
}
template<typename T>
-CDT_state<T>::CDT_state(int num_input_verts, int num_input_edges, int num_input_faces, T epsilon)
+CDT_state<T>::CDT_state(
+ int num_input_verts, int num_input_edges, int num_input_faces, T epsilon, bool need_ids)
{
this->input_vert_tot = num_input_verts;
this->cdt.reserve(num_input_verts, num_input_edges, num_input_faces);
this->cdt.outer_face = this->cdt.add_face();
this->epsilon = epsilon;
+ this->need_ids = need_ids;
this->visit_count = 0;
}
-static bool id_in_list(const LinkNode *id_list, int id)
-{
- const LinkNode *ln;
-
- for (ln = id_list; ln != nullptr; ln = ln->next) {
- if (POINTER_AS_INT(ln->link) == id) {
- return true;
- }
- }
- return false;
-}
-
/* Is any id in (range_start, range_start+1, ... , range_end) in id_list? */
-static bool id_range_in_list(const LinkNode *id_list, int range_start, int range_end)
+static bool id_range_in_list(const blender::Set<int> &id_list, int range_start, int range_end)
{
- const LinkNode *ln;
- int id;
-
- for (ln = id_list; ln != nullptr; ln = ln->next) {
- id = POINTER_AS_INT(ln->link);
+ for (int id : id_list) {
if (id >= range_start && id <= range_end) {
return true;
}
@@ -860,19 +903,15 @@ static bool id_range_in_list(const LinkNode *id_list, int range_start, int range
return false;
}
-static void add_to_input_ids(LinkNode **dst, int input_id)
+static void add_to_input_ids(blender::Set<int> &dst, int input_id)
{
- if (!id_in_list(*dst, input_id)) {
- BLI_linklist_prepend(dst, POINTER_FROM_INT(input_id));
- }
+ dst.add(input_id);
}
-static void add_list_to_input_ids(LinkNode **dst, const LinkNode *src)
+static void add_list_to_input_ids(blender::Set<int> &dst, const blender::Set<int> &src)
{
- const LinkNode *ln;
-
- for (ln = src; ln != nullptr; ln = ln->next) {
- add_to_input_ids(dst, POINTER_AS_INT(ln->link));
+ for (int value : src) {
+ dst.add(value);
}
}
@@ -883,7 +922,7 @@ template<typename T> inline bool is_border_edge(const CDTEdge<T> *e, const CDT_s
template<typename T> inline bool is_constrained_edge(const CDTEdge<T> *e)
{
- return e->input_ids != nullptr;
+ return e->input_ids.size() > 0;
}
template<typename T> inline bool is_deleted_edge(const CDTEdge<T> *e)
@@ -979,7 +1018,7 @@ template<typename T> CDTEdge<T> *CDTArrangement<T>::add_diagonal(SymEdge<T> *s1,
for (SymEdge<T> *se = s2; se != sdiag; se = se->next) {
se->face = fnew;
}
- add_list_to_input_ids(&fnew->input_ids, fold->input_ids);
+ add_list_to_input_ids(fnew->input_ids, fold->input_ids);
return ediag;
}
@@ -1058,7 +1097,7 @@ template<typename T> CDTEdge<T> *CDTArrangement<T>::split_edge(SymEdge<T> *se, T
if (newsesym->vert->symedge == sesym) {
newsesym->vert->symedge = newsesym;
}
- add_list_to_input_ids(&e->input_ids, se->edge->input_ids);
+ add_list_to_input_ids(e->input_ids, se->edge->input_ids);
return e;
}
@@ -1880,7 +1919,7 @@ void add_edge_constraint(
SymEdge<T> *t = find_symedge_between_verts(v1, v2);
if (t != nullptr) {
/* Segment already there. */
- add_to_input_ids(&t->edge->input_ids, input_id);
+ add_to_input_ids(t->edge->input_ids, input_id);
if (r_edges != nullptr) {
BLI_linklist_append(&edge_list, t->edge);
*r_edges = edge_list.list;
@@ -2041,7 +2080,7 @@ void add_edge_constraint(
BLI_assert(cd_prev->lambda == 0.0);
BLI_assert(cd_prev->out->next->vert == cd->vert);
edge = cd_prev->out->edge;
- add_to_input_ids(&edge->input_ids, input_id);
+ add_to_input_ids(edge->input_ids, input_id);
if (r_edges != nullptr) {
BLI_linklist_append(&edge_list, edge);
}
@@ -2054,7 +2093,7 @@ void add_edge_constraint(
else {
edge = cdt_state->cdt.add_diagonal(tstart, t);
}
- add_to_input_ids(&edge->input_ids, input_id);
+ add_to_input_ids(edge->input_ids, input_id);
if (r_edges != nullptr) {
BLI_linklist_append(&edge_list, edge);
}
@@ -2093,7 +2132,8 @@ template<typename T> void add_edge_constraints(CDT_state<T> *cdt_state, const CD
}
CDTVert<T> *v1 = cdt_state->cdt.get_vert_resolve_merge(iv1);
CDTVert<T> *v2 = cdt_state->cdt.get_vert_resolve_merge(iv2);
- add_edge_constraint(cdt_state, v1, v2, i, nullptr);
+ int id = cdt_state->need_ids ? i : 0;
+ add_edge_constraint(cdt_state, v1, v2, id, nullptr);
}
cdt_state->face_edge_offset = ne;
}
@@ -2132,7 +2172,7 @@ void add_face_ids(
continue;
}
face->visit_index = visit;
- add_to_input_ids(&face->input_ids, face_id);
+ add_to_input_ids(face->input_ids, face_id);
SymEdge<T> *se_start = se;
for (se = se->next; se != se_start; se = se->next) {
if (!id_range_in_list(se->edge->input_ids, fedge_start, fedge_end)) {
@@ -2168,7 +2208,10 @@ static int power_of_10_greater_equal_to(int x)
* order around each face in turn. And then the next face starts at
* cdt->face_edge_offset beyond the start for the previous face.
*/
-template<typename T> void add_face_constraints(CDT_state<T> *cdt_state, const CDT_input<T> &input)
+template<typename T>
+void add_face_constraints(CDT_state<T> *cdt_state,
+ const CDT_input<T> &input,
+ CDT_output_type output_type)
{
int nv = input.vert.size();
int nf = input.face.size();
@@ -2206,7 +2249,8 @@ template<typename T> void add_face_constraints(CDT_state<T> *cdt_state, const CD
CDTVert<T> *v1 = cdt->get_vert_resolve_merge(iv1);
CDTVert<T> *v2 = cdt->get_vert_resolve_merge(iv2);
LinkNode *edge_list;
- add_edge_constraint(cdt_state, v1, v2, face_edge_id, &edge_list);
+ int id = cdt_state->need_ids ? face_edge_id : 0;
+ add_edge_constraint(cdt_state, v1, v2, id, &edge_list);
/* Set a new face_symedge0 each time since earlier ones may not
* survive later symedge splits. Really, just want the one when
* i == flen -1, but this code guards against that one somehow
@@ -2224,7 +2268,16 @@ template<typename T> void add_face_constraints(CDT_state<T> *cdt_state, const CD
}
int fedge_end = fedge_start + flen - 1;
if (face_symedge0 != nullptr) {
- add_face_ids(cdt_state, face_symedge0, f, fedge_start, fedge_end);
+ /* We need to propagate face ids to all faces that represent #f, if #need_ids.
+ * Even if `need_ids == false`, we need to propagate at least the fact that
+ * the face ids set would be non-empty if the output type is one of the ones
+ * making valid BMesh faces. */
+ int id = cdt_state->need_ids ? f : 0;
+ add_face_ids(cdt_state, face_symedge0, id, fedge_start, fedge_end);
+ if (cdt_state->need_ids || (output_type == CDT_CONSTRAINTS_VALID_BMESH ||
+ output_type == CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES)) {
+ add_face_ids(cdt_state, face_symedge0, f, fedge_start, fedge_end);
+ }
}
fstart += flen;
}
@@ -2349,7 +2402,7 @@ template<typename T> void remove_non_constraint_edges_leave_valid_bmesh(CDT_stat
CDTFace<T> *fleft = se->face;
CDTFace<T> *fright = sym(se)->face;
if (fleft != cdt->outer_face && fright != cdt->outer_face &&
- (fleft->input_ids != nullptr || fright->input_ids != nullptr)) {
+ (fleft->input_ids.size() > 0 || fright->input_ids.size() > 0)) {
/* Is there another #SymEdge with same left and right faces?
* Or is there a vertex not part of e touching the same left and right faces? */
for (SymEdge<T> *se2 = se->next; dissolve && se2 != se; se2 = se2->next) {
@@ -2507,30 +2560,33 @@ template<typename T> void detect_holes(CDT_state<T> *cdt_state)
mid.exact[1] = (f->symedge->vert->co.exact[1] + f->symedge->next->vert->co.exact[1] +
f->symedge->next->next->vert->co.exact[1]) /
3;
- int hits = 0;
+ std::atomic<int> hits = 0;
/* TODO: Use CDT data structure here to greatly reduce search for intersections! */
- for (const CDTEdge<T> *e : cdt->edges) {
- if (!is_deleted_edge(e) && is_constrained_edge(e)) {
- if (e->symedges[0].face->visit_index == e->symedges[1].face->visit_index) {
- continue; /* Don't count hits on edges between faces in same region. */
- }
- auto isect = vec2<T>::isect_seg_seg(ray_end.exact,
- mid.exact,
- e->symedges[0].vert->co.exact,
- e->symedges[1].vert->co.exact);
- switch (isect.kind) {
- case vec2<T>::isect_result::LINE_LINE_CROSS: {
- hits++;
- break;
+ threading::parallel_for(cdt->edges.index_range(), 256, [&](IndexRange range) {
+ for (const int i : range) {
+ const CDTEdge<T> *e = cdt->edges[i];
+ if (!is_deleted_edge(e) && is_constrained_edge(e)) {
+ if (e->symedges[0].face->visit_index == e->symedges[1].face->visit_index) {
+ continue; /* Don't count hits on edges between faces in same region. */
+ }
+ auto isect = vec2<T>::isect_seg_seg(ray_end.exact,
+ mid.exact,
+ e->symedges[0].vert->co.exact,
+ e->symedges[1].vert->co.exact);
+ switch (isect.kind) {
+ case vec2<T>::isect_result::LINE_LINE_CROSS: {
+ hits++;
+ break;
+ }
+ case vec2<T>::isect_result::LINE_LINE_EXACT:
+ case vec2<T>::isect_result::LINE_LINE_NONE:
+ case vec2<T>::isect_result::LINE_LINE_COLINEAR:
+ break;
}
- case vec2<T>::isect_result::LINE_LINE_EXACT:
- case vec2<T>::isect_result::LINE_LINE_NONE:
- case vec2<T>::isect_result::LINE_LINE_COLINEAR:
- break;
}
}
- }
- f->hole = (hits % 2) == 0;
+ });
+ f->hole = (hits.load() % 2) == 0;
}
/* Finally, propagate hole status to all holes of a region. */
@@ -2631,25 +2687,31 @@ CDT_result<T> get_cdt_output(CDT_state<T> *cdt_state,
for (int i = 0; i < verts_size; ++i) {
CDTVert<T> *v = cdt->verts[i];
if (v->merge_to_index != -1) {
- if (i < cdt_state->input_vert_tot) {
- add_to_input_ids(&cdt->verts[v->merge_to_index]->input_ids, i);
+ if (cdt_state->need_ids) {
+ if (i < cdt_state->input_vert_tot) {
+ add_to_input_ids(cdt->verts[v->merge_to_index]->input_ids, i);
+ }
}
vert_to_output_map[i] = vert_to_output_map[v->merge_to_index];
}
}
}
result.vert = Array<vec2<T>>(nv);
- result.vert_orig = Array<Vector<int>>(nv);
+ if (cdt_state->need_ids) {
+ result.vert_orig = Array<Vector<int>>(nv);
+ }
int i_out = 0;
for (int i = 0; i < verts_size; ++i) {
CDTVert<T> *v = cdt->verts[i];
if (v->merge_to_index == -1) {
result.vert[i_out] = v->co.exact;
- if (i < cdt_state->input_vert_tot) {
- result.vert_orig[i_out].append(i);
- }
- for (LinkNode *ln = v->input_ids; ln; ln = ln->next) {
- result.vert_orig[i_out].append(POINTER_AS_INT(ln->link));
+ if (cdt_state->need_ids) {
+ if (i < cdt_state->input_vert_tot) {
+ result.vert_orig[i_out].append(i);
+ }
+ for (int vert : v->input_ids) {
+ result.vert_orig[i_out].append(vert);
+ }
}
++i_out;
}
@@ -2660,15 +2722,19 @@ CDT_result<T> get_cdt_output(CDT_state<T> *cdt_state,
return !is_deleted_edge(e);
});
result.edge = Array<std::pair<int, int>>(ne);
- result.edge_orig = Array<Vector<int>>(ne);
+ if (cdt_state->need_ids) {
+ result.edge_orig = Array<Vector<int>>(ne);
+ }
int e_out = 0;
for (const CDTEdge<T> *e : cdt->edges) {
if (!is_deleted_edge(e)) {
int vo1 = vert_to_output_map[e->symedges[0].vert->index];
int vo2 = vert_to_output_map[e->symedges[1].vert->index];
result.edge[e_out] = std::pair<int, int>(vo1, vo2);
- for (LinkNode *ln = e->input_ids; ln; ln = ln->next) {
- result.edge_orig[e_out].append(POINTER_AS_INT(ln->link));
+ if (cdt_state->need_ids) {
+ for (int edge : e->input_ids) {
+ result.edge_orig[e_out].append(edge);
+ }
}
++e_out;
}
@@ -2679,7 +2745,9 @@ CDT_result<T> get_cdt_output(CDT_state<T> *cdt_state,
return !f->deleted && f != cdt->outer_face;
});
result.face = Array<Vector<int>>(nf);
- result.face_orig = Array<Vector<int>>(nf);
+ if (cdt_state->need_ids) {
+ result.face_orig = Array<Vector<int>>(nf);
+ }
int f_out = 0;
for (const CDTFace<T> *f : cdt->faces) {
if (!f->deleted && f != cdt->outer_face) {
@@ -2690,8 +2758,10 @@ CDT_result<T> get_cdt_output(CDT_state<T> *cdt_state,
result.face[f_out].append(vert_to_output_map[se->vert->index]);
se = se->next;
} while (se != se_start);
- for (LinkNode *ln = f->input_ids; ln; ln = ln->next) {
- result.face_orig[f_out].append(POINTER_AS_INT(ln->link));
+ if (cdt_state->need_ids) {
+ for (int face : f->input_ids) {
+ result.face_orig[f_out].append(face);
+ }
}
++f_out;
}
@@ -2716,11 +2786,11 @@ CDT_result<T> delaunay_calc(const CDT_input<T> &input, CDT_output_type output_ty
int nv = input.vert.size();
int ne = input.edge.size();
int nf = input.face.size();
- CDT_state<T> cdt_state(nv, ne, nf, input.epsilon);
+ CDT_state<T> cdt_state(nv, ne, nf, input.epsilon, input.need_ids);
add_input_verts(&cdt_state, input);
initial_triangulation(&cdt_state.cdt);
add_edge_constraints(&cdt_state, input);
- add_face_constraints(&cdt_state, input);
+ add_face_constraints(&cdt_state, input, output_type);
return get_cdt_output(&cdt_state, input, output_type);
}
@@ -2772,6 +2842,7 @@ extern "C" ::CDT_result *BLI_delaunay_2d_cdt_calc(const ::CDT_input *input,
}
}
in.epsilon = static_cast<double>(input->epsilon);
+ in.need_ids = input->need_ids;
blender::meshintersect::CDT_result<double> res = blender::meshintersect::delaunay_2d_calc(
in, output_type);
@@ -2784,74 +2855,101 @@ extern "C" ::CDT_result *BLI_delaunay_2d_cdt_calc(const ::CDT_input *input,
int tot_e_orig = 0;
int tot_f_orig = 0;
int tot_f_lens = 0;
- for (int v = 0; v < nv; ++v) {
- tot_v_orig += res.vert_orig[v].size();
- }
- for (int e = 0; e < ne; ++e) {
- tot_e_orig += res.edge_orig[e].size();
+ if (input->need_ids) {
+ for (int v = 0; v < nv; ++v) {
+ tot_v_orig += res.vert_orig[v].size();
+ }
+ for (int e = 0; e < ne; ++e) {
+ tot_e_orig += res.edge_orig[e].size();
+ }
}
for (int f = 0; f < nf; ++f) {
- tot_f_orig += res.face_orig[f].size();
+ if (input->need_ids) {
+ tot_f_orig += res.face_orig[f].size();
+ }
tot_f_lens += res.face[f].size();
}
output->vert_coords = static_cast<decltype(output->vert_coords)>(
MEM_malloc_arrayN(nv, sizeof(output->vert_coords[0]), __func__));
- output->verts_orig = static_cast<int *>(MEM_malloc_arrayN(tot_v_orig, sizeof(int), __func__));
- output->verts_orig_start_table = static_cast<int *>(
- MEM_malloc_arrayN(nv, sizeof(int), __func__));
- output->verts_orig_len_table = static_cast<int *>(MEM_malloc_arrayN(nv, sizeof(int), __func__));
output->edges = static_cast<decltype(output->edges)>(
MEM_malloc_arrayN(ne, sizeof(output->edges[0]), __func__));
- output->edges_orig = static_cast<int *>(MEM_malloc_arrayN(tot_e_orig, sizeof(int), __func__));
- output->edges_orig_start_table = static_cast<int *>(
- MEM_malloc_arrayN(ne, sizeof(int), __func__));
- output->edges_orig_len_table = static_cast<int *>(MEM_malloc_arrayN(ne, sizeof(int), __func__));
output->faces = static_cast<int *>(MEM_malloc_arrayN(tot_f_lens, sizeof(int), __func__));
output->faces_start_table = static_cast<int *>(MEM_malloc_arrayN(nf, sizeof(int), __func__));
output->faces_len_table = static_cast<int *>(MEM_malloc_arrayN(nf, sizeof(int), __func__));
- output->faces_orig = static_cast<int *>(MEM_malloc_arrayN(tot_f_orig, sizeof(int), __func__));
- output->faces_orig_start_table = static_cast<int *>(
- MEM_malloc_arrayN(nf, sizeof(int), __func__));
- output->faces_orig_len_table = static_cast<int *>(MEM_malloc_arrayN(nf, sizeof(int), __func__));
+ if (input->need_ids) {
+ output->verts_orig = static_cast<int *>(MEM_malloc_arrayN(tot_v_orig, sizeof(int), __func__));
+ output->verts_orig_start_table = static_cast<int *>(
+ MEM_malloc_arrayN(nv, sizeof(int), __func__));
+ output->verts_orig_len_table = static_cast<int *>(
+ MEM_malloc_arrayN(nv, sizeof(int), __func__));
+ output->edges_orig = static_cast<int *>(MEM_malloc_arrayN(tot_e_orig, sizeof(int), __func__));
+ output->edges_orig_start_table = static_cast<int *>(
+ MEM_malloc_arrayN(ne, sizeof(int), __func__));
+ output->edges_orig_len_table = static_cast<int *>(
+ MEM_malloc_arrayN(ne, sizeof(int), __func__));
+ output->faces_orig = static_cast<int *>(MEM_malloc_arrayN(tot_f_orig, sizeof(int), __func__));
+ output->faces_orig_start_table = static_cast<int *>(
+ MEM_malloc_arrayN(nf, sizeof(int), __func__));
+ output->faces_orig_len_table = static_cast<int *>(
+ MEM_malloc_arrayN(nf, sizeof(int), __func__));
+ }
+ else {
+ output->verts_orig = nullptr;
+ output->verts_orig_start_table = nullptr;
+ output->verts_orig_len_table = nullptr;
+ output->edges_orig = nullptr;
+ output->edges_orig_start_table = nullptr;
+ output->edges_orig_len_table = nullptr;
+ output->faces_orig = nullptr;
+ output->faces_orig_start_table = nullptr;
+ output->faces_orig_len_table = nullptr;
+ }
int v_orig_index = 0;
for (int v = 0; v < nv; ++v) {
output->vert_coords[v][0] = static_cast<float>(res.vert[v][0]);
output->vert_coords[v][1] = static_cast<float>(res.vert[v][1]);
- int this_start = v_orig_index;
- output->verts_orig_start_table[v] = this_start;
- for (int j : res.vert_orig[v].index_range()) {
- output->verts_orig[v_orig_index++] = res.vert_orig[v][j];
+ if (input->need_ids) {
+ int this_start = v_orig_index;
+ output->verts_orig_start_table[v] = this_start;
+ for (int j : res.vert_orig[v].index_range()) {
+ output->verts_orig[v_orig_index++] = res.vert_orig[v][j];
+ }
+ output->verts_orig_len_table[v] = v_orig_index - this_start;
}
- output->verts_orig_len_table[v] = v_orig_index - this_start;
}
int e_orig_index = 0;
for (int e = 0; e < ne; ++e) {
output->edges[e][0] = res.edge[e].first;
output->edges[e][1] = res.edge[e].second;
- int this_start = e_orig_index;
- output->edges_orig_start_table[e] = this_start;
- for (int j : res.edge_orig[e].index_range()) {
- output->edges_orig[e_orig_index++] = res.edge_orig[e][j];
+ if (input->need_ids) {
+ int this_start = e_orig_index;
+ output->edges_orig_start_table[e] = this_start;
+ for (int j : res.edge_orig[e].index_range()) {
+ output->edges_orig[e_orig_index++] = res.edge_orig[e][j];
+ }
+ output->edges_orig_len_table[e] = e_orig_index - this_start;
}
- output->edges_orig_len_table[e] = e_orig_index - this_start;
}
int f_orig_index = 0;
int f_index = 0;
for (int f = 0; f < nf; ++f) {
+
output->faces_start_table[f] = f_index;
int flen = res.face[f].size();
output->faces_len_table[f] = flen;
for (int j = 0; j < flen; ++j) {
output->faces[f_index++] = res.face[f][j];
}
- int this_start = f_orig_index;
- output->faces_orig_start_table[f] = this_start;
- for (int k : res.face_orig[f].index_range()) {
- output->faces_orig[f_orig_index++] = res.face_orig[f][k];
+ if (input->need_ids) {
+ int this_start = f_orig_index;
+ output->faces_orig_start_table[f] = this_start;
+ for (int k : res.face_orig[f].index_range()) {
+ output->faces_orig[f_orig_index++] = res.face_orig[f][k];
+ }
+ output->faces_orig_len_table[f] = f_orig_index - this_start;
}
- output->faces_orig_len_table[f] = f_orig_index - this_start;
}
return output;
}
@@ -2863,14 +2961,16 @@ extern "C" void BLI_delaunay_2d_cdt_free(::CDT_result *result)
MEM_freeN(result->faces);
MEM_freeN(result->faces_start_table);
MEM_freeN(result->faces_len_table);
- MEM_freeN(result->verts_orig);
- MEM_freeN(result->verts_orig_start_table);
- MEM_freeN(result->verts_orig_len_table);
- MEM_freeN(result->edges_orig);
- MEM_freeN(result->edges_orig_start_table);
- MEM_freeN(result->edges_orig_len_table);
- MEM_freeN(result->faces_orig);
- MEM_freeN(result->faces_orig_start_table);
- MEM_freeN(result->faces_orig_len_table);
+ if (result->verts_orig) {
+ MEM_freeN(result->verts_orig);
+ MEM_freeN(result->verts_orig_start_table);
+ MEM_freeN(result->verts_orig_len_table);
+ MEM_freeN(result->edges_orig);
+ MEM_freeN(result->edges_orig_start_table);
+ MEM_freeN(result->edges_orig_len_table);
+ MEM_freeN(result->faces_orig);
+ MEM_freeN(result->faces_orig_start_table);
+ MEM_freeN(result->faces_orig_len_table);
+ }
MEM_freeN(result);
}
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 58b109eca10..0a213fa8696 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -410,7 +410,7 @@ MINLINE float pingpongf(float value, float scale)
return fabsf(fractf((value - scale) / (scale * 2.0f)) * scale * 2.0f - scale);
}
-// Square.
+/* Square. */
MINLINE int square_s(short a)
{
@@ -442,7 +442,7 @@ MINLINE double square_d(double a)
return a * a;
}
-// Cube.
+/* Cube. */
MINLINE int cube_s(short a)
{
@@ -474,7 +474,7 @@ MINLINE double cube_d(double a)
return a * a * a;
}
-// Min/max
+/* Min/max */
MINLINE float min_ff(float a, float b)
{
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index 4c50c1c7af8..a5a687ef9fe 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -276,14 +276,14 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
* https://en.wikipedia.org/wiki/Relative_luminance
*
* Real values are:
- * ``Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)``
+ * `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`
* according to: "Derivation of Basic Television Color Equations", RP 177-1993
*
* As this sums slightly above 1.0, the document recommends to use:
- * ``0.2126(R) + 0.7152(G) + 0.0722(B)``, as used here.
+ * `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here.
*
* The high precision values are used to calculate the rounded byte weights so they add up to 255:
- * ``54(R) + 182(G) + 19(B)``
+ * `54(R) + 182(G) + 19(B)`
*/
MINLINE float rgb_to_grayscale(const float rgb[3])
{
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 80f0008c7eb..803291e4a3b 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -165,7 +165,7 @@ float area_squared_poly_v3(const float verts[][3], unsigned int nr)
/**
* Scalar cross product of a 2d polygon.
*
- * - equivalent to ``area * 2``
+ * - equivalent to `area * 2`
* - useful for checking polygon winding (a positive value is clockwise).
*/
float cross_poly_v2(const float verts[][2], unsigned int nr)
@@ -518,7 +518,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3])
}
/**
- * Check if \a p is inside the 2x planes defined by ``(v1, v2, v3)``
+ * Check if \a p is inside the 2x planes defined by `(v1, v2, v3)`
* where the 3x points define 2x planes.
*
* \param axis_ref: used when v1,v2,v3 form a line and to check if the corner is concave/convex.
@@ -527,7 +527,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3])
* (it just defines the planes).
*
* \return the lowest squared distance to either of the planes.
- * where ``(return < 0.0)`` is outside.
+ * where `(return < 0.0)` is outside.
*
* <pre>
* v1
@@ -1421,7 +1421,7 @@ int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
* \return r_p1, r_p2: Intersection coordinates.
*
* \note The order of assignment for intersection points (\a r_p1, \a r_p2) is predictable,
- * based on the direction defined by ``l2 - l1``,
+ * based on the direction defined by `l2 - l1`,
* this direction compared with the normal of each point on the sphere:
* \a r_p1 always has a >= 0.0 dot product.
* \a r_p2 always has a <= 0.0 dot product.
@@ -3426,7 +3426,7 @@ float ray_point_factor_v3(const float p[3],
/**
* A simplified version of #closest_to_line_v3
- * we only need to return the ``lambda``
+ * we only need to return the `lambda`
*
* \param epsilon: avoid approaching divide-by-zero.
* Passing a zero will just check for nonzero division.
diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c
index 655d3fcc4c0..1757b0dd525 100644
--- a/source/blender/blenlib/intern/math_geom_inline.c
+++ b/source/blender/blenlib/intern/math_geom_inline.c
@@ -272,7 +272,7 @@ MINLINE float shell_angle_to_dist(const float angle)
return (UNLIKELY(angle < SMALL_NUMBER)) ? 1.0f : fabsf(1.0f / cosf(angle));
}
/**
- * equivalent to ``shell_angle_to_dist(angle_normalized_v3v3(a, b))``
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b))`.
*/
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
{
@@ -282,7 +282,7 @@ MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
}
/**
- * equivalent to ``shell_angle_to_dist(angle_normalized_v2v2(a, b))``
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b))`.
*/
MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2])
{
@@ -293,7 +293,7 @@ MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2])
}
/**
- * equivalent to ``shell_angle_to_dist(angle_normalized_v3v3(a, b) / 2)``
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b) / 2)`.
*/
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3])
{
@@ -307,7 +307,7 @@ MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[
}
/**
- * equivalent to ``shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)``
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)`.
*/
MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2])
{
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index 04fae6a0e68..bd48edf70c0 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -625,7 +625,7 @@ void BLI_ewa_filter(const int width,
* Use a different radius based on interpolation switch,
* just enough to anti-alias when interpolation is off,
* and slightly larger to make result a bit smoother than bilinear interpolation when
- * interpolation is on (minimum values: const float rmin = intpol ? 1.0f : 0.5f;) */
+ * interpolation is on (minimum values: `const float rmin = intpol ? 1.0f : 0.5f;`) */
const float rmin = (intpol ? 1.5625f : 0.765625f) / ff2;
BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
if ((b2 = b * b) < rmin) {
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 5920788821c..b605c3eeead 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -276,7 +276,7 @@ void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4])
{
BLI_assert(!ELEM(R, A, B));
- /* matrix product: R[j][k] = A[j][i] . B[i][k] */
+ /* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */
#ifdef BLI_HAVE_SSE2
__m128 A0 = _mm_loadu_ps(A[0]);
__m128 A1 = _mm_loadu_ps(A[1]);
@@ -321,7 +321,7 @@ void mul_m4_m4m4_db_uniq(double R[4][4], const double A[4][4], const double B[4]
{
BLI_assert(!ELEM(R, A, B));
- /* matrix product: R[j][k] = A[j][i] . B[i][k] */
+ /* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */
R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0] + B[0][3] * A[3][0];
R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1] + B[0][3] * A[3][1];
@@ -349,7 +349,7 @@ void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B
/* Remove second check since types don't match. */
BLI_assert(!ELEM(R, A /*, B */));
- /* matrix product: R[j][k] = A[j][i] . B[i][k] */
+ /* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */
R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0] + B[0][3] * A[3][0];
R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1] + B[0][3] * A[3][1];
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index db9ece81c59..55f7a152b83 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -1312,7 +1312,7 @@ MINLINE bool is_one_v3(const float v[3])
/* -------------------------------------------------------------------- */
/** \name Vector Comparison
*
- * \note use ``value <= limit``, so a limit of zero doesn't fail on an exact match.
+ * \note use `value <= limit`, so a limit of zero doesn't fail on an exact match.
* \{ */
MINLINE bool equals_v2v2(const float v1[2], const float v2[2])
diff --git a/source/blender/blenlib/intern/memory_utils.c b/source/blender/blenlib/intern/memory_utils.c
index 5ca7b96c136..4bb93877401 100644
--- a/source/blender/blenlib/intern/memory_utils.c
+++ b/source/blender/blenlib/intern/memory_utils.c
@@ -19,7 +19,7 @@
* \brief Generic memory manipulation API.
*
* This is to extend on existing functions
- * such as ``memcpy`` & ``memcmp``.
+ * such as `memcpy` & `memcmp`.
*/
#include <string.h>
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index 8b8850c7cdb..90ffebdb422 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -151,7 +151,7 @@ class TriMeshTopology : NonCopyable {
* Else return NO_INDEX. */
int other_tri_if_manifold(Edge e, int t) const
{
- auto p = edge_tri_.lookup_ptr(e);
+ const auto *p = edge_tri_.lookup_ptr(e);
if (p != nullptr && (*p)->size() == 2) {
return ((**p)[0] == t) ? (**p)[1] : (**p)[0];
}
@@ -204,7 +204,7 @@ TriMeshTopology::TriMeshTopology(const IMesh &tm)
}
edges->append_non_duplicates(e);
- auto p = edge_tri_.lookup_ptr(Edge(v, vnext));
+ auto *p = edge_tri_.lookup_ptr(Edge(v, vnext));
if (p == nullptr) {
edge_tri_.add_new(e, new Vector<int>{t});
}
@@ -238,7 +238,7 @@ TriMeshTopology::~TriMeshTopology()
Vector<Vector<int> *> values;
/* Deconstructing is faster in parallel, so it is worth building an array of things to delete. */
- for (auto item : edge_tri_.values()) {
+ for (auto *item : edge_tri_.values()) {
values.append(item);
}
diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc
index f91dd762e70..dcd432a88d5 100644
--- a/source/blender/blenlib/intern/mesh_intersect.cc
+++ b/source/blender/blenlib/intern/mesh_intersect.cc
@@ -1875,6 +1875,16 @@ static void do_cdt(CDT_data &cd)
}
}
+/* Find an original edge index that goes with the edge that the CDT output edge
+ * that goes between verts i0 and i1 (in the CDT output vert indexing scheme).
+ * There may be more than one: if so, prefer one that was originally a face edge.
+ * The input to CDT for a triangle with some intersecting segments from other triangles
+ * will have both edges and a face constraint for the main triangle (this is redundant
+ * but allows us to discover which face edge goes with which output edges).
+ * If there is any face edge, return one of those as the original.
+ * If there is no face edge but there is another edge in the input problem, then that
+ * edge must have come from intersection with another triangle, so set *r_is_intersect
+ * to true in that case. */
static int get_cdt_edge_orig(
int i0, int i1, const CDT_data &cd, const IMesh &in_tm, bool *r_is_intersect)
{
@@ -1900,35 +1910,50 @@ static int get_cdt_edge_orig(
}
/* Pick an arbitrary orig, but not one equal to NO_INDEX, if we can help it. */
- /* TODO: if edge has origs from more than on part of the nary input,
+ /* TODO: if edge has origs from more than one part of the nary input,
* then want to set *r_is_intersect to true. */
+ int face_eorig = NO_INDEX;
+ bool have_non_face_eorig = false;
for (int orig_index : cd.cdt_out.edge_orig[e]) {
/* orig_index encodes the triangle and pos within the triangle of the input edge. */
if (orig_index >= foff) {
- int in_face_index = (orig_index / foff) - 1;
- int pos = orig_index % foff;
- /* We need to retrieve the edge orig field from the Face used to populate the
- * in_face_index'th face of the CDT, at the pos'th position of the face. */
- int in_tm_face_index = cd.input_face[in_face_index];
- BLI_assert(in_tm_face_index < in_tm.face_size());
- const Face *facep = in_tm.face(in_tm_face_index);
- BLI_assert(pos < facep->size());
- bool is_rev = cd.is_reversed[in_face_index];
- int eorig = is_rev ? facep->edge_orig[2 - pos] : facep->edge_orig[pos];
- if (eorig != NO_INDEX) {
- return eorig;
+ if (face_eorig == NO_INDEX) {
+ int in_face_index = (orig_index / foff) - 1;
+ int pos = orig_index % foff;
+ /* We need to retrieve the edge orig field from the Face used to populate the
+ * in_face_index'th face of the CDT, at the pos'th position of the face. */
+ int in_tm_face_index = cd.input_face[in_face_index];
+ BLI_assert(in_tm_face_index < in_tm.face_size());
+ const Face *facep = in_tm.face(in_tm_face_index);
+ BLI_assert(pos < facep->size());
+ bool is_rev = cd.is_reversed[in_face_index];
+ int eorig = is_rev ? facep->edge_orig[2 - pos] : facep->edge_orig[pos];
+ if (eorig != NO_INDEX) {
+ face_eorig = eorig;
+ }
}
}
else {
- /* This edge came from an edge input to the CDT problem,
- * so it is an intersect edge. */
- *r_is_intersect = true;
- /* TODO: maybe there is an orig index:
- * This happens if an input edge was formed by an input face having
- * an edge that is co-planar with the cluster, while the face as a whole is not. */
- return NO_INDEX;
+ if (!have_non_face_eorig) {
+ have_non_face_eorig = true;
+ }
+ if (face_eorig != NO_INDEX && have_non_face_eorig) {
+ /* Only need at most one orig for each type. */
+ break;
+ }
}
}
+ if (face_eorig != NO_INDEX) {
+ return face_eorig;
+ }
+ if (have_non_face_eorig) {
+ /* This must have been an input to the CDT problem that was an intersection edge. */
+ /* TODO: maybe there is an orig index:
+ * This happens if an input edge was formed by an input face having
+ * an edge that is co-planar with the cluster, while the face as a whole is not. */
+ *r_is_intersect = true;
+ return NO_INDEX;
+ }
return NO_INDEX;
}
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index 01aad5b078f..9850de69b5a 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -1294,13 +1294,12 @@ float BLI_noise_generic_turbulence(
* source code in the book "Texturing and Modeling: A procedural approach"
*/
-/*
- * Procedural fBm evaluated at "point"; returns value stored in "value".
+/**
+ * Procedural `fBm` evaluated at "point"; returns value stored in "value".
*
- * Parameters:
- * ``H'' is the fractal increment parameter
- * ``lacunarity'' is the gap between successive frequencies
- * ``octaves'' is the number of frequencies in the fBm
+ * \param H: is the fractal increment parameter.
+ * \param lacunarity: is the gap between successive frequencies.
+ * \param octaves: is the number of frequencies in the `fBm`.
*/
float BLI_noise_mg_fbm(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis)
@@ -1359,15 +1358,16 @@ float BLI_noise_mg_fbm(
} /* fBm() */
-/*
- * Procedural multifractal evaluated at "point";
+/**
+ * Procedural multi-fractal evaluated at "point";
* returns value stored in "value".
*
- * Parameters:
- * ``H'' determines the highest fractal dimension
- * ``lacunarity'' is gap between successive frequencies
- * ``octaves'' is the number of frequencies in the fBm
- * ``offset'' is the zero offset, which determines multifractality (NOT USED??)
+ * \param H: determines the highest fractal dimension.
+ * \param lacunarity: is gap between successive frequencies.
+ * \param octaves: is the number of frequencies in the `fBm`.
+ *
+ * \note There used to be a parameter called `offset`, old docs read:
+ * is the zero offset, which determines multi-fractality.
*/
/* this one is in fact rather confusing,
@@ -1429,15 +1429,14 @@ float BLI_noise_mg_multi_fractal(
} /* multifractal() */
-/*
+/**
* Heterogeneous procedural terrain function: stats by altitude method.
* Evaluated at "point"; returns value stored in "value".
*
- * Parameters:
- * ``H'' determines the fractal dimension of the roughest areas
- * ``lacunarity'' is the gap between successive frequencies
- * ``octaves'' is the number of frequencies in the fBm
- * ``offset'' raises the terrain from `sea level'
+ * \param H: Determines the fractal dimension of the roughest areas.
+ * \param lacunarity: Is the gap between successive frequencies.
+ * \param octaves: Is the number of frequencies in the `fBm`.
+ * \param offset: Raises the terrain from `sea level`.
*/
float BLI_noise_mg_hetero_terrain(float x,
float y,
diff --git a/source/blender/blenlib/intern/polyfill_2d.c b/source/blender/blenlib/intern/polyfill_2d.c
index 817572ba85c..9af98359199 100644
--- a/source/blender/blenlib/intern/polyfill_2d.c
+++ b/source/blender/blenlib/intern/polyfill_2d.c
@@ -77,9 +77,9 @@ typedef signed char eSign;
#ifdef USE_KDTREE
/**
* Spatial optimization for point-in-triangle intersection checks.
- * The simple version of this algorithm is ``O(n^2)`` complexity
+ * The simple version of this algorithm is `O(n^2)` complexity
* (every point needing to check the triangle defined by every other point),
- * Using a binary-tree reduces the complexity to ``O(n log n)``
+ * Using a binary-tree reduces the complexity to `O(n log n)`
* plus some overhead of creating the tree.
*
* This is a single purpose KDTree based on BLI_kdtree with some modifications
@@ -898,7 +898,7 @@ void BLI_polyfill_calc_arena(const float (*coords)[2],
* \param coords_sign: Pass this when we know the sign in advance to avoid extra calculations.
*
* \param r_tris: This array is filled in with triangle indices in clockwise order.
- * The length of the array must be ``coords_tot - 2``.
+ * The length of the array must be `coords_tot - 2`.
* Indices are guaranteed to be assigned to unique triangles, with valid indices,
* even in the case of degenerate input (self intersecting polygons, zero area ears... etc).
*/
diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c
index 6e5a3e961a5..006a3798dcd 100644
--- a/source/blender/blenlib/intern/smallhash.c
+++ b/source/blender/blenlib/intern/smallhash.c
@@ -34,11 +34,11 @@
* Otherwise #GHash should be used instead.
*
* #SmallHashEntry.key
- * - ``SMHASH_KEY_UNUSED`` means the key in the cell has not been initialized.
+ * - `SMHASH_KEY_UNUSED` means the key in the cell has not been initialized.
*
* #SmallHashEntry.val
- * - ``SMHASH_CELL_UNUSED`` means this cell is inside a key series.
- * - ``SMHASH_CELL_FREE`` means this cell terminates a key series.
+ * - `SMHASH_CELL_UNUSED` means this cell is inside a key series.
+ * - `SMHASH_CELL_FREE` means this cell terminates a key series.
*
* Note that the values and keys are often pointers or index values,
* use the maximum values to avoid real pointers colliding with magic numbers.
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 61d095658a3..5541d75bc73 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -232,7 +232,7 @@ size_t BLI_vsnprintf(char *__restrict buffer,
}
/**
- * A version of #BLI_vsnprintf that returns ``strlen(buffer)``
+ * A version of #BLI_vsnprintf that returns `strlen(buffer)`
*/
size_t BLI_vsnprintf_rlen(char *__restrict buffer,
size_t maxncpy,
@@ -278,7 +278,7 @@ size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict
}
/**
- * A version of #BLI_snprintf that returns ``strlen(dst)``
+ * A version of #BLI_snprintf that returns `strlen(dst)`
*/
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
{
diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c
index 6a2ed8fac2c..d2666c6fe63 100644
--- a/source/blender/blenlib/intern/string_utils.c
+++ b/source/blender/blenlib/intern/string_utils.c
@@ -182,8 +182,8 @@ void BLI_string_flip_side_name(char *r_name,
/* We first check the case with a .### extension, let's find the last period */
if (isdigit(r_name[len - 1])) {
- index = strrchr(r_name, '.'); /* last occurrence. */
- if (index && isdigit(index[1])) { /* doesn't handle case bone.1abc2 correct..., whatever! */
+ index = strrchr(r_name, '.'); /* Last occurrence. */
+ if (index && isdigit(index[1])) { /* Doesn't handle case `bone.1abc2` correct..., whatever! */
if (strip_number == false) {
BLI_strncpy(number, index, name_len);
}
@@ -194,7 +194,7 @@ void BLI_string_flip_side_name(char *r_name,
BLI_strncpy(prefix, r_name, name_len);
- /* first case; separator . - _ with extensions r R l L. */
+ /* First case; separator (`.` or `_`) with extensions in `r R l L`. */
if ((len > 1) && is_char_sep(r_name[len - 2])) {
is_set = true;
switch (r_name[len - 1]) {
diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc
index 6250c1b9986..cbb5bf34477 100644
--- a/source/blender/blenlib/intern/task_pool.cc
+++ b/source/blender/blenlib/intern/task_pool.cc
@@ -532,7 +532,7 @@ bool BLI_task_pool_current_canceled(TaskPool *pool)
case TASK_POOL_BACKGROUND_SERIAL:
return background_task_pool_canceled(pool);
}
- BLI_assert("BLI_task_pool_canceled: Control flow should not come here!");
+ BLI_assert_msg(0, "BLI_task_pool_canceled: Control flow should not come here!");
return false;
}
diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c
index 7d7436411ac..a9665c0a9c2 100644
--- a/source/blender/blenlib/intern/timecode.c
+++ b/source/blender/blenlib/intern/timecode.c
@@ -39,7 +39,7 @@
* Generate time-code/frame number string and store in \a str
*
* \param str: destination string
- * \param maxncpy: maximum number of characters to copy ``sizeof(str)``
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
* \param brevity_level: special setting for #View2D grid drawing,
* used to specify how detailed we need to be
* \param time_seconds: time total time in seconds
@@ -199,7 +199,7 @@ size_t BLI_timecode_string_from_time(char *str,
* Generate time string and store in \a str
*
* \param str: destination string
- * \param maxncpy: maximum number of characters to copy ``sizeof(str)``
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
* \param time_seconds: time total time in seconds
* \return length of \a str
*/
@@ -229,7 +229,7 @@ size_t BLI_timecode_string_from_time_simple(char *str,
* Generate time string and store in \a str
*
* \param str: destination string
- * \param maxncpy: maximum number of characters to copy ``sizeof(str)``
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
* \param brevity_level: special setting for #View2D grid drawing,
* used to specify how detailed we need to be
* \param time_seconds: time total time in seconds
diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c
index beeae175869..d5c9c5cd5e6 100644
--- a/source/blender/blenlib/intern/winstuff.c
+++ b/source/blender/blenlib/intern/winstuff.c
@@ -30,7 +30,7 @@
# include "MEM_guardedalloc.h"
-# define WIN32_SKIP_HKEY_PROTECTION // need to use HKEY
+# define WIN32_SKIP_HKEY_PROTECTION /* Need to use HKEY. */
# include "BLI_path_util.h"
# include "BLI_string.h"
# include "BLI_utildefines.h"
diff --git a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
index 08a3818e18f..f221036419e 100644
--- a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
+++ b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
@@ -241,7 +241,7 @@ template<typename T> std::ostream &operator<<(std::ostream &os, const CDT_result
for (int i : r.edge.index_range()) {
os << "e" << i << " = (" << r.edge[i].first << ", " << r.edge[i].second << ")\n";
os << " orig: ";
- for (int j : r.edge_orig[i].size()) {
+ for (int j : r.edge_orig[i].index_range()) {
os << r.edge_orig[i][j] << " ";
}
os << "\n";
@@ -797,6 +797,55 @@ template<typename T> void crosssegs_test()
}
}
+template<typename T> void cutacrosstri_test()
+{
+ /* Right triangle with horizontal segment exactly crossing in the middle. */
+ const char *spec = R"(5 1 1
+ 0.0 0.0
+ 1.0 0.0
+ 0.0 1.0
+ 0.0 0.5
+ 0.5 0.5
+ 3 4
+ 0 1 2
+ )";
+
+ CDT_input<T> in = fill_input_from_string<T>(spec);
+ CDT_result<T> out = delaunay_2d_calc(in, CDT_FULL);
+ EXPECT_EQ(out.vert.size(), 5);
+ EXPECT_EQ(out.edge.size(), 7);
+ EXPECT_EQ(out.face.size(), 3);
+ int v0_out = get_orig_index(out.vert_orig, 0);
+ int v1_out = get_orig_index(out.vert_orig, 1);
+ int v2_out = get_orig_index(out.vert_orig, 2);
+ int v3_out = get_orig_index(out.vert_orig, 3);
+ int v4_out = get_orig_index(out.vert_orig, 4);
+ EXPECT_TRUE(v0_out != -1 && v1_out != -1 && v2_out != -1 && v3_out != -1 && v4_out != -1);
+ if (out.face.size() == 3) {
+ int e0_out = get_orig_index(out.edge_orig, 0);
+ EXPECT_NE(e0_out, -1);
+ int fe0_out = get_output_edge_index(out, v0_out, v1_out);
+ EXPECT_NE(fe0_out, -1);
+ int fe1a_out = get_output_edge_index(out, v1_out, v4_out);
+ EXPECT_NE(fe1a_out, -1);
+ int fe1b_out = get_output_edge_index(out, v4_out, v2_out);
+ EXPECT_NE(fe1b_out, -1);
+ if (fe1a_out != 0 && fe1b_out != 0) {
+ EXPECT_EQ(e0_out, get_orig_index(out.edge_orig, 0));
+ EXPECT_TRUE(out.edge_orig[fe1a_out].size() == 1 && out.edge_orig[fe1a_out][0] == 11);
+ EXPECT_TRUE(out.edge_orig[fe1b_out].size() == 1 && out.edge_orig[fe1b_out][0] == 11);
+ }
+ int e_diag = get_output_edge_index(out, v0_out, v4_out);
+ EXPECT_NE(e_diag, -1);
+ if (e_diag != -1) {
+ EXPECT_EQ(out.edge_orig[e_diag].size(), 0);
+ }
+ }
+ if (DO_DRAW) {
+ graph_draw<T>("CutAcrossTri", out.vert, out.edge, out.face);
+ }
+}
+
template<typename T> void diamondcross_test()
{
/* Diamond with constraint edge from top to bottom. Some dup verts. */
@@ -1470,6 +1519,11 @@ TEST(delaunay_d, CrossSegs)
crosssegs_test<double>();
}
+TEST(delaunay_d, CutAcrossTri)
+{
+ cutacrosstri_test<double>();
+}
+
TEST(delaunay_d, DiamondCross)
{
diamondcross_test<double>();
@@ -1610,6 +1664,11 @@ TEST(delaunay_m, CrossSegs)
crosssegs_test<mpq_class>();
}
+TEST(delaunay_m, CutAcrossTri)
+{
+ cutacrosstri_test<mpq_class>();
+}
+
TEST(delaunay_m, DiamondCross)
{
diamondcross_test<mpq_class>();
@@ -1697,14 +1756,40 @@ TEST(delaunay_d, CintTwoFace)
input.faces_len_table = faces_len;
input.faces_start_table = faces_start;
input.epsilon = 1e-5f;
+ input.need_ids = false;
::CDT_result *output = BLI_delaunay_2d_cdt_calc(&input, CDT_FULL);
BLI_delaunay_2d_cdt_free(output);
}
+
+TEST(delaunay_d, CintTwoFaceNoIds)
+{
+ float vert_coords[][2] = {
+ {0.0, 0.0}, {1.0, 0.0}, {0.5, 1.0}, {1.1, 1.0}, {1.1, 0.0}, {1.6, 1.0}};
+ int faces[] = {0, 1, 2, 3, 4, 5};
+ int faces_len[] = {3, 3};
+ int faces_start[] = {0, 3};
+
+ ::CDT_input input;
+ input.verts_len = 6;
+ input.edges_len = 0;
+ input.faces_len = 2;
+ input.vert_coords = vert_coords;
+ input.edges = nullptr;
+ input.faces = faces;
+ input.faces_len_table = faces_len;
+ input.faces_start_table = faces_start;
+ input.epsilon = 1e-5f;
+ input.need_ids = true;
+ ::CDT_result *output = BLI_delaunay_2d_cdt_calc(&input, CDT_FULL);
+ BLI_delaunay_2d_cdt_free(output);
+}
+
#endif
#if DO_TEXT_TESTS
template<typename T>
-void text_test(int num_arc_points, int num_lets_per_line, int num_lines, CDT_output_type otype)
+void text_test(
+ int num_arc_points, int num_lets_per_line, int num_lines, CDT_output_type otype, bool need_ids)
{
constexpr bool print_timing = true;
/*
@@ -1789,7 +1874,7 @@ void text_test(int num_arc_points, int num_lets_per_line, int num_lines, CDT_out
vec2<T> start_co = b_vert[arc_origin_vert];
vec2<T> end_co = b_vert[arc_terminal_vert];
vec2<T> center_co = 0.5 * (start_co + end_co);
- BLI_assert(start_co[0] == end_co[2]);
+ BLI_assert(start_co[0] == end_co[0]);
double radius = abs(math_to_double<T>(end_co[1] - center_co[1]));
double angle_delta = M_PI / (num_arc_points + 1);
int start_vert = b_before_arcs_in.vert.size() + arc * num_arc_points;
@@ -1843,12 +1928,18 @@ void text_test(int num_arc_points, int num_lets_per_line, int num_lines, CDT_out
}
}
in.epsilon = b_before_arcs_in.epsilon;
+ in.need_ids = need_ids;
double tstart = PIL_check_seconds_timer();
CDT_result<T> out = delaunay_2d_calc(in, otype);
double tend = PIL_check_seconds_timer();
if (print_timing) {
std::cout << "time = " << tend - tstart << "\n";
}
+ if (!need_ids) {
+ EXPECT_EQ(out.vert_orig.size(), 0);
+ EXPECT_EQ(out.edge_orig.size(), 0);
+ EXPECT_EQ(out.face_orig.size(), 0);
+ }
if (DO_DRAW) {
std::string label = "Text arcpts=" + std::to_string(num_arc_points);
if (num_lets_per_line > 1) {
@@ -1857,25 +1948,103 @@ void text_test(int num_arc_points, int num_lets_per_line, int num_lines, CDT_out
if (num_lines > 1) {
label += " lines=" + std::to_string(num_lines);
}
+ if (!need_ids) {
+ label += " no_ids";
+ }
+ if (otype != CDT_INSIDE_WITH_HOLES) {
+ label += " otype=" + std::to_string(otype);
+ }
graph_draw<T>(label, out.vert, out.edge, out.face);
}
}
TEST(delaunay_d, TextB10)
{
- text_test<double>(10, 1, 1, CDT_INSIDE_WITH_HOLES);
+ text_test<double>(10, 1, 1, CDT_INSIDE_WITH_HOLES, true);
+}
+
+TEST(delaunay_d, TextB10_noids)
+{
+ text_test<double>(10, 1, 1, CDT_INSIDE_WITH_HOLES, false);
+}
+
+TEST(delaunay_d, TextB10_inside)
+{
+ text_test<double>(10, 1, 1, CDT_INSIDE, true);
+}
+
+TEST(delaunay_d, TextB10_inside_noids)
+{
+ text_test<double>(10, 1, 1, CDT_INSIDE, false);
+}
+
+TEST(delaunay_d, TextB10_constraints)
+{
+ text_test<double>(10, 1, 1, CDT_CONSTRAINTS, true);
+}
+
+TEST(delaunay_d, TextB10_constraints_noids)
+{
+ text_test<double>(10, 1, 1, CDT_CONSTRAINTS, false);
+}
+
+TEST(delaunay_d, TextB10_constraints_valid_bmesh)
+{
+ text_test<double>(10, 1, 1, CDT_CONSTRAINTS_VALID_BMESH, true);
+}
+
+TEST(delaunay_d, TextB10_constraints_valid_bmesh_noids)
+{
+ text_test<double>(10, 1, 1, CDT_CONSTRAINTS_VALID_BMESH, false);
+}
+
+TEST(delaunay_d, TextB10_constraints_valid_bmesh_with_holes)
+{
+ text_test<double>(10, 1, 1, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES, true);
+}
+
+TEST(delaunay_d, TextB10_constraints_valid_bmesh_with_holes_noids)
+{
+ text_test<double>(10, 1, 1, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES, false);
}
TEST(delaunay_d, TextB200)
{
- text_test<double>(200, 1, 1, CDT_INSIDE_WITH_HOLES);
+ text_test<double>(200, 1, 1, CDT_INSIDE_WITH_HOLES, true);
}
TEST(delaunay_d, TextB10_10_10)
{
- text_test<double>(10, 10, 10, CDT_INSIDE_WITH_HOLES);
+ text_test<double>(10, 10, 10, CDT_INSIDE_WITH_HOLES, true);
+}
+
+TEST(delaunay_d, TextB10_10_10_noids)
+{
+ text_test<double>(10, 10, 10, CDT_INSIDE_WITH_HOLES, false);
}
+# ifdef WITH_GMP
+TEST(delaunay_m, TextB10)
+{
+ text_test<mpq_class>(10, 1, 1, CDT_INSIDE_WITH_HOLES, true);
+}
+
+TEST(delaunay_m, TextB200)
+{
+ text_test<mpq_class>(200, 1, 1, CDT_INSIDE_WITH_HOLES, true);
+}
+
+TEST(delaunay_m, TextB10_10_10)
+{
+ text_test<mpq_class>(10, 10, 10, CDT_INSIDE_WITH_HOLES, true);
+}
+
+TEST(delaunay_m, TextB10_10_10_noids)
+{
+ text_test<mpq_class>(10, 10, 10, CDT_INSIDE_WITH_HOLES, false);
+}
+# endif
+
#endif
#if DO_RANDOM_TESTS
diff --git a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
index 24fa7f1a476..0329fc156c0 100644
--- a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
+++ b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
@@ -866,11 +866,11 @@ static void fill_sphere_data(int nrings,
};
Array<int> eid = {0, 0, 0, 0}; /* Don't care about edge ids. */
/*
- * (x, y , z) is given from inclination theta and azimuth phi,
- * where 0 <= theta <= pi; 0 <= phi <= 2pi.
- * x = radius * sin(theta) cos(phi)
- * y = radius * sin(theta) sin(phi)
- * z = radius * cos(theta)
+ * (x, y, z) is given from inclination theta and azimuth phi,
+ * where: `0 <= theta <= pi; 0 <= phi <= 2pi`.
+ * `x = radius * sin(theta) cos(phi)`
+ * `y = radius * sin(theta) sin(phi)`
+ * `z = radius * cos(theta)`
*/
for (int s = 0; s < nsegs; ++s) {
double phi = s * delta_phi;
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 03fb4149d7b..11986f11fea 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2444,7 +2444,7 @@ static void direct_link_id_common(
BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int tag)
{
if (!BLO_read_data_is_undo(reader)) {
- /* When actually reading a file , we do want to reset/re-generate session uuids.
+ /* When actually reading a file, we do want to reset/re-generate session uuids.
* In undo case, we want to re-use existing ones. */
id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
}
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 8a7bc375ea9..e56c1995363 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -132,7 +132,7 @@ static void sequencer_init_preview_region(ARegion *region)
region->v2d.max[0] = 12000.0f;
region->v2d.max[1] = 12000.0f;
region->v2d.cur = region->v2d.tot;
- region->v2d.align = V2D_ALIGN_FREE; // (V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_NEG_Y);
+ region->v2d.align = V2D_ALIGN_FREE; /* `(V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_NEG_Y)` */
region->v2d.keeptot = V2D_KEEPTOT_FREE;
}
@@ -655,8 +655,10 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
Tex *tx;
ParticleSettings *part;
Object *ob;
- // PTCacheID *pid;
- // ListBase pidlist;
+#if 0
+ PTCacheID *pid;
+ ListBase pidlist;
+#endif
bSound *sound;
Sequence *seq;
@@ -766,12 +768,15 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
/* set old pointcaches to have disk cache flag */
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- // BKE_ptcache_ids_from_object(&pidlist, ob);
+#if 0
+ BKE_ptcache_ids_from_object(&pidlist, ob);
- // for (pid = pidlist.first; pid; pid = pid->next)
- // pid->cache->flag |= PTCACHE_DISK_CACHE;
+ for (pid = pidlist.first; pid; pid = pid->next) {
+ pid->cache->flag |= PTCACHE_DISK_CACHE;
+ }
- // BLI_freelistN(&pidlist);
+ BLI_freelistN(&pidlist);
+#endif
}
/* type was a mixed flag & enum. move the 2d flag elsewhere */
@@ -789,18 +794,23 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
Tex *tex;
Scene *sce;
ToolSettings *ts;
- // PTCacheID *pid;
- // ListBase pidlist;
+#if 0
+ PTCacheID *pid;
+ ListBase pidlist;
+#endif
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- // BKE_ptcache_ids_from_object(&pidlist, ob);
+#if 0
+ BKE_ptcache_ids_from_object(&pidlist, ob);
- // for (pid = pidlist.first; pid; pid = pid->next) {
- // if (BLI_listbase_is_empty(pid->ptcaches))
- // pid->ptcaches->first = pid->ptcaches->last = pid->cache;
- //}
+ for (pid = pidlist.first; pid; pid = pid->next) {
+ if (BLI_listbase_is_empty(pid->ptcaches)) {
+ pid->ptcaches->first = pid->ptcaches->last = pid->cache;
+ }
+ }
- // BLI_freelistN(&pidlist);
+ BLI_freelistN(&pidlist);
+#endif
if (ob->totcol && ob->matbits == NULL) {
int a;
@@ -842,7 +852,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
Object *ob;
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- if (ob->flag & 8192) { // OB_POSEMODE = 8192
+ if (ob->flag & 8192) { /* OB_POSEMODE = 8192. */
ob->mode |= OB_MODE_POSE;
}
}
@@ -1395,7 +1405,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
if ((sce->r.ffcodecdata.flags & FFMPEG_MULTIPLEX_AUDIO) == 0) {
- sce->r.ffcodecdata.audio_codec = 0x0; // CODEC_ID_NONE
+ sce->r.ffcodecdata.audio_codec = 0x0; /* `CODEC_ID_NONE` */
}
SEQ_ALL_BEGIN (sce->ed, seq) {
@@ -1735,7 +1745,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
/* New Settings */
if (!MAIN_VERSION_ATLEAST(bmain, 252, 5)) {
- brush->flag |= BRUSH_SPACE_ATTEN; // explicitly enable adaptive space
+ brush->flag |= BRUSH_SPACE_ATTEN; /* Explicitly enable adaptive space. */
/* spacing was originally in pixels, convert it to percentage for new version
* size should not be zero due to sanity check above
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 5bf4d3b68b5..858f5d85a90 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -2149,7 +2149,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- /* NB: scene->nodetree is a local ID block, has been direct_link'ed */
+ /* NOTE: `scene->nodetree` is a local ID block, has been direct_link'ed. */
if (scene->nodetree) {
scene->nodetree->active_viewer_key = active_viewer_key;
}
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index d36c622c572..4dcb7414bb4 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -29,8 +29,10 @@
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_collection_types.h"
+#include "DNA_curve_types.h"
#include "DNA_genfile.h"
#include "DNA_listBase.h"
+#include "DNA_material_types.h"
#include "DNA_modifier_types.h"
#include "DNA_text_types.h"
#include "DNA_workspace_types.h"
@@ -40,6 +42,7 @@
#include "BKE_asset.h"
#include "BKE_collection.h"
#include "BKE_deform.h"
+#include "BKE_fcurve.h"
#include "BKE_fcurve_driver.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -48,11 +51,10 @@
#include "BLO_readfile.h"
#include "MEM_guardedalloc.h"
#include "readfile.h"
-#include "versioning_common.h"
#include "SEQ_sequencer.h"
-#include "MEM_guardedalloc.h"
+#include "RNA_access.h"
#include "versioning_common.h"
@@ -99,13 +101,87 @@ static void move_vertex_group_names_to_object_data(Main *bmain)
if (ELEM(object->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
ListBase *new_defbase = BKE_object_defgroup_list_mutable(object);
- /* Clear the list in case the it was already assigned from another object. */
- BLI_freelistN(new_defbase);
- *new_defbase = object->defbase;
+ /* Choose the longest vertex group name list among all linked duplicates. */
+ if (BLI_listbase_count(&object->defbase) < BLI_listbase_count(new_defbase)) {
+ BLI_freelistN(&object->defbase);
+ }
+ else {
+ /* Clear the list in case the it was already assigned from another object. */
+ BLI_freelistN(new_defbase);
+ *new_defbase = object->defbase;
+ }
}
}
}
+static void do_versions_sequencer_speed_effect_recursive(Scene *scene, const ListBase *seqbase)
+{
+ /* Old SpeedControlVars->flags. */
+#define SEQ_SPEED_INTEGRATE (1 << 0)
+#define SEQ_SPEED_COMPRESS_IPO_Y (1 << 2)
+
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (seq->type == SEQ_TYPE_SPEED) {
+ SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
+ const char *substr = NULL;
+ float globalSpeed = v->globalSpeed;
+ if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
+ if (globalSpeed == 1.0f) {
+ v->speed_control_type = SEQ_SPEED_STRETCH;
+ }
+ else {
+ v->speed_control_type = SEQ_SPEED_MULTIPLY;
+ v->speed_fader = globalSpeed *
+ ((float)seq->seq1->len /
+ max_ff((float)(seq->seq1->enddisp - seq->seq1->start), 1.0f));
+ }
+ }
+ else if (v->flags & SEQ_SPEED_INTEGRATE) {
+ v->speed_control_type = SEQ_SPEED_MULTIPLY;
+ v->speed_fader = seq->speed_fader * globalSpeed;
+ }
+ else if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) {
+ globalSpeed *= 100.0f;
+ v->speed_control_type = SEQ_SPEED_LENGTH;
+ v->speed_fader_length = seq->speed_fader * globalSpeed;
+ substr = "speed_length";
+ }
+ else {
+ v->speed_control_type = SEQ_SPEED_FRAME_NUMBER;
+ v->speed_fader_frame_number = (int)(seq->speed_fader * globalSpeed);
+ substr = "speed_frame_number";
+ }
+
+ v->flags &= ~(SEQ_SPEED_INTEGRATE | SEQ_SPEED_COMPRESS_IPO_Y);
+
+ if (substr || globalSpeed != 1.0f) {
+ FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
+ if (fcu) {
+ if (globalSpeed != 1.0f) {
+ for (int i = 0; i < fcu->totvert; i++) {
+ BezTriple *bezt = &fcu->bezt[i];
+ bezt->vec[0][1] *= globalSpeed;
+ bezt->vec[1][1] *= globalSpeed;
+ bezt->vec[2][1] *= globalSpeed;
+ }
+ }
+ if (substr) {
+ char *new_path = BLI_str_replaceN(fcu->rna_path, "speed_factor", substr);
+ MEM_freeN(fcu->rna_path);
+ fcu->rna_path = new_path;
+ }
+ }
+ }
+ }
+ else if (seq->type == SEQ_TYPE_META) {
+ do_versions_sequencer_speed_effect_recursive(scene, &seq->seqbase);
+ }
+ }
+
+#undef SEQ_SPEED_INTEGRATE
+#undef SEQ_SPEED_COMPRESS_IPO_Y
+}
+
void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
{
if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
@@ -154,6 +230,14 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
move_vertex_group_names_to_object_data(bmain);
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 13)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->ed != NULL) {
+ do_versions_sequencer_speed_effect_recursive(scene, &scene->ed->seqbase);
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -499,6 +583,11 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
sizeof(scene->master_collection->id.name) - 2);
}
}
+ LISTBASE_FOREACH (Material *, mat, &bmain->materials) {
+ if (!(mat->lineart.flags & LRT_MATERIAL_CUSTOM_OCCLUSION_EFFECTIVENESS)) {
+ mat->lineart.mat_occlusion = 1;
+ }
+ }
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 9)) {
@@ -519,15 +608,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
FOREACH_NODETREE_END;
-
- {
- if (!DNA_struct_elem_find(
- fd->filesdna, "WorkSpace", "AssetLibraryReference", "active_asset_library")) {
- LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
- BKE_asset_library_reference_init_default(&workspace->active_asset_library);
- }
- }
- }
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 10)) {
@@ -540,6 +620,51 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 13)) {
+ /* Convert Surface Deform to sparse-capable bind structure. */
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "SurfaceDeformModifierData", "int", "num_mesh_verts")) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_SurfaceDeform) {
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ if (smd->num_bind_verts && smd->verts) {
+ smd->num_mesh_verts = smd->num_bind_verts;
+
+ for (unsigned int i = 0; i < smd->num_bind_verts; i++) {
+ smd->verts[i].vertex_idx = i;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "WorkSpace", "AssetLibraryReference", "asset_library")) {
+ LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
+ BKE_asset_library_reference_init_default(&workspace->asset_library);
+ }
+ }
+
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "FileAssetSelectParams", "AssetLibraryReference", "asset_library")) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)space;
+ if (sfile->browse_mode != FILE_BROWSE_MODE_ASSETS) {
+ continue;
+ }
+ BKE_asset_library_reference_init_default(&sfile->asset_params->asset_library);
+ }
+ }
+ }
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 30587418f84..152dcbed6a4 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -883,6 +883,10 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->sequencer_proxy_setup = USER_SEQ_PROXY_SETUP_AUTOMATIC;
}
+ if (!USER_VERSION_ATLEAST(293, 13)) {
+ BKE_addon_ensure(&userdef->addons, "pose_library");
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -894,7 +898,6 @@ void blo_do_versions_userdef(UserDef *userdef)
*/
{
/* Keep this block, even when empty. */
- BKE_addon_ensure(&userdef->addons, "pose_library");
}
LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index fc29b1d8915..12839a155e4 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -69,7 +69,7 @@
* - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional).
* - write #GLOB (#FileGlobal struct) (some global vars).
* - write #DNA1 (#SDNA struct)
- * - write #USER (#UserDef struct) if filename is ``~/.config/blender/X.XX/config/startup.blend``.
+ * - write #USER (#UserDef struct) if filename is `~/.config/blender/X.XX/config/startup.blend`.
*/
#include <fcntl.h>
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index a5241f6b36d..40db423ba2f 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -37,7 +37,7 @@
*
* BMHeader flags should **never** be read or written to by bmesh operators (see Operators below).
*
- * Access to header flags is done with ``BM_elem_flag_*()`` functions.
+ * Access to header flags is done with `BM_elem_flag_*()` functions.
* \subsection bm_faces Faces
*
* Faces in BMesh are stored as a circular linked list of loops. Loops store per-face-vertex data
@@ -55,7 +55,7 @@
*
* - BMLoop#v - pointer to the vertex associated with this loop.
* - BMLoop#e - pointer to the edge associated with this loop,
- * between verts ``(loop->v, loop->next->v)``
+ * between verts `(loop->v, loop->next->v)`
* - BMLoop#f - pointer to the face associated with this loop.
* \subsection bm_two_side_face 2-Sided Faces
*
@@ -113,7 +113,7 @@
*
* These slots are identified by name, using strings.
*
- * Access to slots is done with ``BMO_slot_***()`` functions.
+ * Access to slots is done with `BMO_slot_***()` functions.
* \subsection bm_tool_flags Tool Flags
*
* The BMesh API provides a set of flags for faces, edges and vertices,
@@ -126,7 +126,7 @@
* These flags should not be confused with header flags, which are used to store persistent flags
* (e.g. selection, hide status, etc).
*
- * Access to tool flags is done with ``BMO_elem_flag_***()`` functions.
+ * Access to tool flags is done with `BMO_elem_flag_***()` functions.
*
* \warning Operators are **never** allowed to read or write to header flags.
* They act entirely on the data inside their input slots.
@@ -162,14 +162,14 @@
*
* These conventions should be used throughout the bmesh module.
*
- * - ``bmesh_kernel_*()`` - Low level API, for primitive functions that others are built ontop of.
- * - ``bmesh_***()`` - Low level API function.
- * - ``bm_***()`` - 'static' functions, not a part of the API at all,
+ * - `bmesh_kernel_*()` - Low level API, for primitive functions that others are built ontop of.
+ * - `bmesh_***()` - Low level API function.
+ * - `bm_***()` - 'static' functions, not a part of the API at all,
* but use prefix since they operate on BMesh data.
- * - ``BM_***()`` - High level BMesh API function for use anywhere.
- * - ``BMO_***()`` - High level operator API function for use anywhere.
- * - ``bmo_***()`` - Low level / internal operator API functions.
- * - ``_bm_***()`` - Functions which are called via macros only.
+ * - `BM_***()` - High level BMesh API function for use anywhere.
+ * - `BMO_***()` - High level operator API function for use anywhere.
+ * - `bmo_***()` - Low level / internal operator API functions.
+ * - `_bm_***()` - Functions which are called via macros only.
*
* \section bm_todo BMesh TODO's
*
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 423d64ba62c..82c76c8ae4f 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -185,7 +185,7 @@ typedef struct BMLoop {
struct BMFace *f;
/**
- * Other loops connected to this edge,.
+ * Other loops connected to this edge.
*
* This is typically use for accessing an edges faces,
* however this is done by stepping over it's loops.
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c
index dea6561fe9a..6dfaa0ca688 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c
@@ -40,6 +40,16 @@
#include "intern/bmesh_private.h"
+/* Smooth angle to use when tagging edges is disabled entirely. */
+#define EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS -FLT_MAX
+
+static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3],
+ BMEdge *e,
+ const float split_angle_cos);
+static void bm_edge_tag_from_smooth(const float (*fnos)[3],
+ BMEdge *e,
+ const float split_angle_cos);
+
/* -------------------------------------------------------------------- */
/** \name Update Vertex & Face Normals
* \{ */
@@ -394,9 +404,7 @@ void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges)
* Helpers for #BM_mesh_loop_normals_update and #BM_loops_calc_normal_vcos
*/
static void bm_mesh_edges_sharp_tag(BMesh *bm,
- const float (*vnos)[3],
const float (*fnos)[3],
- float (*r_lnos)[3],
const float split_angle,
const bool do_sharp_edges_tag)
{
@@ -407,58 +415,23 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm,
const bool check_angle = (split_angle < (float)M_PI);
const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
- {
- char htype = BM_VERT | BM_LOOP;
- if (fnos) {
- htype |= BM_FACE;
- }
- BM_mesh_elem_index_ensure(bm, htype);
+ if (fnos) {
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
}
- /* This first loop checks which edges are actually smooth,
- * and pre-populate lnos with vnos (as if they were all smooth). */
- BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
- BMLoop *l_a, *l_b;
-
- BM_elem_index_set(e, i); /* set_inline */
- BM_elem_flag_disable(e, BM_ELEM_TAG); /* Clear tag (means edge is sharp). */
-
- /* An edge with only two loops, might be smooth... */
- if (BM_edge_loop_pair(e, &l_a, &l_b)) {
- bool is_angle_smooth = true;
- if (check_angle) {
- const float *no_a = fnos ? fnos[BM_elem_index_get(l_a->f)] : l_a->f->no;
- const float *no_b = fnos ? fnos[BM_elem_index_get(l_b->f)] : l_b->f->no;
- is_angle_smooth = (dot_v3v3(no_a, no_b) >= split_angle_cos);
+ if (do_sharp_edges_tag) {
+ BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
+ BM_elem_index_set(e, i); /* set_inline */
+ if (e->l != NULL) {
+ bm_edge_tag_from_smooth_and_set_sharp(fnos, e, split_angle_cos);
}
-
- /* We only tag edges that are *really* smooth:
- * If the angle between both its polys' normals is below split_angle value,
- * and it is tagged as such,
- * and both its faces are smooth,
- * and both its faces have compatible (non-flipped) normals,
- * i.e. both loops on the same edge do not share the same vertex.
- */
- if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) && BM_elem_flag_test(l_a->f, BM_ELEM_SMOOTH) &&
- BM_elem_flag_test(l_b->f, BM_ELEM_SMOOTH) && l_a->v != l_b->v) {
- if (is_angle_smooth) {
- const float *no;
- BM_elem_flag_enable(e, BM_ELEM_TAG);
-
- /* linked vertices might be fully smooth, copy their normals to loop ones. */
- if (r_lnos) {
- no = vnos ? vnos[BM_elem_index_get(l_a->v)] : l_a->v->no;
- copy_v3_v3(r_lnos[BM_elem_index_get(l_a)], no);
- no = vnos ? vnos[BM_elem_index_get(l_b->v)] : l_b->v->no;
- copy_v3_v3(r_lnos[BM_elem_index_get(l_b)], no);
- }
- }
- else if (do_sharp_edges_tag) {
- /* Note that we do not care about the other sharp-edge cases
- * (sharp poly, non-manifold edge, etc.),
- * only tag edge as sharp when it is due to angle threshold. */
- BM_elem_flag_disable(e, BM_ELEM_SMOOTH);
- }
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
+ BM_elem_index_set(e, i); /* set_inline */
+ if (e->l != NULL) {
+ bm_edge_tag_from_smooth(fnos, e, split_angle_cos);
}
}
}
@@ -479,7 +452,7 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
return;
}
- bm_mesh_edges_sharp_tag(bm, NULL, NULL, NULL, split_angle, true);
+ bm_mesh_edges_sharp_tag(bm, NULL, split_angle, true);
}
/** \} */
@@ -526,6 +499,600 @@ bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
}
/**
+ * Called for all faces loops.
+ *
+ * - All loops must have #BM_ELEM_TAG cleared.
+ * - Loop indices must be valid.
+ *
+ * \note When custom normals are present, the order of loops can be important.
+ * Loops with lower indices must be passed before loops with higher indices (for each vertex).
+ * This is needed since the first loop sets the reference point for the custom normal offsets.
+ *
+ * \return The number of loops that were handled (for early exit when all have been handled).
+ */
+static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
+ const float (*vcos)[3],
+ const float (*fnos)[3],
+ const short (*clnors_data)[2],
+ const int cd_loop_clnors_offset,
+ const bool has_clnors,
+ /* Cache. */
+ BLI_Stack *edge_vectors,
+ /* Iterate. */
+ BMLoop *l_curr,
+ /* Result. */
+ float (*r_lnos)[3],
+ MLoopNorSpaceArray *r_lnors_spacearr)
+{
+ BLI_assert((bm->elem_index_dirty & (BM_FACE | BM_LOOP)) == 0);
+ BLI_assert((vcos == NULL) || ((bm->elem_index_dirty & BM_VERT) == 0));
+ UNUSED_VARS_NDEBUG(bm);
+
+ int handled = 0;
+
+ /* Temp normal stack. */
+ BLI_SMALLSTACK_DECLARE(normal, float *);
+ /* Temp clnors stack. */
+ BLI_SMALLSTACK_DECLARE(clnors, short *);
+ /* Temp edge vectors stack, only used when computing lnor spacearr. */
+
+ /* A smooth edge, we have to check for cyclic smooth fan case.
+ * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge
+ * as 'entry point', otherwise we can skip it. */
+
+ /* NOTE: In theory, we could make bm_mesh_loop_check_cyclic_smooth_fan() store
+ * mlfan_pivot's in a stack, to avoid having to fan again around
+ * the vert during actual computation of clnor & clnorspace. However, this would complicate
+ * the code, add more memory usage, and
+ * BM_vert_step_fan_loop() is quite cheap in term of CPU cycles,
+ * so really think it's not worth it. */
+ if (BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
+ (BM_elem_flag_test(l_curr, BM_ELEM_TAG) || !BM_loop_check_cyclic_smooth_fan(l_curr))) {
+ }
+ else if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
+ !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
+ /* Simple case (both edges around that vertex are sharp in related polygon),
+ * this vertex just takes its poly normal.
+ */
+ const int l_curr_index = BM_elem_index_get(l_curr);
+ const float *no = fnos ? fnos[BM_elem_index_get(l_curr->f)] : l_curr->f->no;
+ copy_v3_v3(r_lnos[l_curr_index], no);
+
+ /* If needed, generate this (simple!) lnor space. */
+ if (r_lnors_spacearr) {
+ float vec_curr[3], vec_prev[3];
+ MLoopNorSpace *lnor_space = BKE_lnor_space_create(r_lnors_spacearr);
+
+ {
+ const BMVert *v_pivot = l_curr->v;
+ const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
+ const BMVert *v_1 = l_curr->next->v;
+ const float *co_1 = vcos ? vcos[BM_elem_index_get(v_1)] : v_1->co;
+ const BMVert *v_2 = l_curr->prev->v;
+ const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
+
+ BLI_assert(v_1 == BM_edge_other_vert(l_curr->e, v_pivot));
+ BLI_assert(v_2 == BM_edge_other_vert(l_curr->prev->e, v_pivot));
+
+ sub_v3_v3v3(vec_curr, co_1, co_pivot);
+ normalize_v3(vec_curr);
+ sub_v3_v3v3(vec_prev, co_2, co_pivot);
+ normalize_v3(vec_prev);
+ }
+
+ BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, NULL);
+ /* We know there is only one loop in this space,
+ * no need to create a linklist in this case... */
+ BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, l_curr, true);
+
+ if (has_clnors) {
+ const short(*clnor)[2] = clnors_data ? &clnors_data[l_curr_index] :
+ (const void *)BM_ELEM_CD_GET_VOID_P(
+ l_curr, cd_loop_clnors_offset);
+ BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor, r_lnos[l_curr_index]);
+ }
+ }
+ handled = 1;
+ }
+ /* We *do not need* to check/tag loops as already computed!
+ * Due to the fact a loop only links to one of its two edges,
+ * a same fan *will never be walked more than once!*
+ * Since we consider edges having neighbor faces with inverted (flipped) normals as sharp,
+ * we are sure that no fan will be skipped, even only considering the case
+ * (sharp curr_edge, smooth prev_edge), and not the alternative
+ * (smooth curr_edge, sharp prev_edge).
+ * All this due/thanks to link between normals and loop ordering.
+ */
+ else {
+ /* We have to fan around current vertex, until we find the other non-smooth edge,
+ * and accumulate face normals into the vertex!
+ * Note in case this vertex has only one sharp edge,
+ * this is a waste because the normal is the same as the vertex normal,
+ * but I do not see any easy way to detect that (would need to count number of sharp edges
+ * per vertex, I doubt the additional memory usage would be worth it, especially as it
+ * should not be a common case in real-life meshes anyway).
+ */
+ BMVert *v_pivot = l_curr->v;
+ BMEdge *e_next;
+ const BMEdge *e_org = l_curr->e;
+ BMLoop *lfan_pivot, *lfan_pivot_next;
+ int lfan_pivot_index;
+ float lnor[3] = {0.0f, 0.0f, 0.0f};
+ float vec_curr[3], vec_next[3], vec_org[3];
+
+ /* We validate clnors data on the fly - cheapest way to do! */
+ int clnors_avg[2] = {0, 0};
+ const short(*clnor_ref)[2] = NULL;
+ int clnors_nbr = 0;
+ bool clnors_invalid = false;
+
+ const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
+
+ MLoopNorSpace *lnor_space = r_lnors_spacearr ? BKE_lnor_space_create(r_lnors_spacearr) : NULL;
+
+ BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors));
+
+ lfan_pivot = l_curr;
+ lfan_pivot_index = BM_elem_index_get(lfan_pivot);
+ e_next = lfan_pivot->e; /* Current edge here, actually! */
+
+ /* Only need to compute previous edge's vector once,
+ * then we can just reuse old current one! */
+ {
+ const BMVert *v_2 = lfan_pivot->next->v;
+ const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
+
+ BLI_assert(v_2 == BM_edge_other_vert(e_next, v_pivot));
+
+ sub_v3_v3v3(vec_org, co_2, co_pivot);
+ normalize_v3(vec_org);
+ copy_v3_v3(vec_curr, vec_org);
+
+ if (r_lnors_spacearr) {
+ BLI_stack_push(edge_vectors, vec_org);
+ }
+ }
+
+ while (true) {
+ /* Much simpler than in sibling code with basic Mesh data! */
+ lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
+ if (lfan_pivot_next) {
+ BLI_assert(lfan_pivot_next->v == v_pivot);
+ }
+ else {
+ /* next edge is non-manifold, we have to find it ourselves! */
+ e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
+ }
+
+ /* Compute edge vector.
+ * NOTE: We could pre-compute those into an array, in the first iteration,
+ * instead of computing them twice (or more) here.
+ * However, time gained is not worth memory and time lost,
+ * given the fact that this code should not be called that much in real-life meshes.
+ */
+ {
+ const BMVert *v_2 = BM_edge_other_vert(e_next, v_pivot);
+ const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
+
+ sub_v3_v3v3(vec_next, co_2, co_pivot);
+ normalize_v3(vec_next);
+ }
+
+ {
+ /* Code similar to accumulate_vertex_normals_poly_v3. */
+ /* Calculate angle between the two poly edges incident on this vertex. */
+ const BMFace *f = lfan_pivot->f;
+ const float fac = saacos(dot_v3v3(vec_next, vec_curr));
+ const float *no = fnos ? fnos[BM_elem_index_get(f)] : f->no;
+ /* Accumulate */
+ madd_v3_v3fl(lnor, no, fac);
+
+ if (has_clnors) {
+ /* Accumulate all clnors, if they are not all equal we have to fix that! */
+ const short(*clnor)[2] = clnors_data ? &clnors_data[lfan_pivot_index] :
+ (const void *)BM_ELEM_CD_GET_VOID_P(
+ lfan_pivot, cd_loop_clnors_offset);
+ if (clnors_nbr) {
+ clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
+ }
+ else {
+ clnor_ref = clnor;
+ }
+ clnors_avg[0] += (*clnor)[0];
+ clnors_avg[1] += (*clnor)[1];
+ clnors_nbr++;
+ /* We store here a pointer to all custom lnors processed. */
+ BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
+ }
+ }
+
+ /* We store here a pointer to all loop-normals processed. */
+ BLI_SMALLSTACK_PUSH(normal, (float *)r_lnos[lfan_pivot_index]);
+
+ if (r_lnors_spacearr) {
+ /* Assign current lnor space to current 'vertex' loop. */
+ BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, lfan_pivot_index, lfan_pivot, false);
+ if (e_next != e_org) {
+ /* We store here all edges-normalized vectors processed. */
+ BLI_stack_push(edge_vectors, vec_next);
+ }
+ }
+
+ handled += 1;
+
+ if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
+ /* Next edge is sharp, we have finished with this fan of faces around this vert! */
+ break;
+ }
+
+ /* Copy next edge vector to current one. */
+ copy_v3_v3(vec_curr, vec_next);
+ /* Next pivot loop to current one. */
+ lfan_pivot = lfan_pivot_next;
+ lfan_pivot_index = BM_elem_index_get(lfan_pivot);
+ }
+
+ {
+ float lnor_len = normalize_v3(lnor);
+
+ /* If we are generating lnor spacearr, we can now define the one for this fan. */
+ if (r_lnors_spacearr) {
+ if (UNLIKELY(lnor_len == 0.0f)) {
+ /* Use vertex normal as fallback! */
+ copy_v3_v3(lnor, r_lnos[lfan_pivot_index]);
+ lnor_len = 1.0f;
+ }
+
+ BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_next, edge_vectors);
+
+ if (has_clnors) {
+ if (clnors_invalid) {
+ short *clnor;
+
+ clnors_avg[0] /= clnors_nbr;
+ clnors_avg[1] /= clnors_nbr;
+ /* Fix/update all clnors of this fan with computed average value. */
+
+ /* Prints continuously when merge custom normals, so commenting. */
+ /* printf("Invalid clnors in this fan!\n"); */
+
+ while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
+ // print_v2("org clnor", clnor);
+ clnor[0] = (short)clnors_avg[0];
+ clnor[1] = (short)clnors_avg[1];
+ }
+ // print_v2("new clnors", clnors_avg);
+ }
+ else {
+ /* We still have to consume the stack! */
+ while (BLI_SMALLSTACK_POP(clnors)) {
+ /* pass */
+ }
+ }
+ BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
+ }
+ }
+
+ /* In case we get a zero normal here, just use vertex normal already set! */
+ if (LIKELY(lnor_len != 0.0f)) {
+ /* Copy back the final computed normal into all related loop-normals. */
+ float *nor;
+
+ while ((nor = BLI_SMALLSTACK_POP(normal))) {
+ copy_v3_v3(nor, lnor);
+ }
+ }
+ else {
+ /* We still have to consume the stack! */
+ while (BLI_SMALLSTACK_POP(normal)) {
+ /* pass */
+ }
+ }
+ }
+
+ /* Tag related vertex as sharp, to avoid fanning around it again
+ * (in case it was a smooth one). */
+ if (r_lnors_spacearr) {
+ BM_elem_flag_enable(l_curr->v, BM_ELEM_TAG);
+ }
+ }
+ return handled;
+}
+
+static int bm_loop_index_cmp(const void *a, const void *b)
+{
+ BLI_assert(BM_elem_index_get((BMLoop *)a) != BM_elem_index_get((BMLoop *)b));
+ if (BM_elem_index_get((BMLoop *)a) < BM_elem_index_get((BMLoop *)b)) {
+ return -1;
+ }
+ return 1;
+}
+
+/**
+ * We only tag edges that are *really* smooth when the following conditions are met:
+ * - The angle between both its polygons normals is below split_angle value.
+ * - The edge is tagged as smooth.
+ * - The faces of the edge are tagged as smooth.
+ * - The faces of the edge have compatible (non-flipped) topological normal (winding),
+ * i.e. both loops on the same edge do not share the same vertex.
+ */
+BLI_INLINE bool bm_edge_is_smooth_no_angle_test(const BMEdge *e,
+ const BMLoop *l_a,
+ const BMLoop *l_b)
+{
+ return (
+ /* The face is manifold. */
+ (l_a->radial_next == l_b) &&
+ /* Faces have winding that faces the same way. */
+ (l_a->v != l_b->v) &&
+ /* The edge is smooth. */
+ BM_elem_flag_test(e, BM_ELEM_SMOOTH) &&
+ /* Both faces are smooth. */
+ BM_elem_flag_test(l_a->f, BM_ELEM_SMOOTH) && BM_elem_flag_test(l_b->f, BM_ELEM_SMOOTH));
+}
+
+static void bm_edge_tag_from_smooth(const float (*fnos)[3], BMEdge *e, const float split_angle_cos)
+{
+ BLI_assert(e->l != NULL);
+ BMLoop *l_a = e->l, *l_b = l_a->radial_next;
+ bool is_smooth = false;
+ if (bm_edge_is_smooth_no_angle_test(e, l_a, l_b)) {
+ if (split_angle_cos != -1.0f) {
+ const float dot = (fnos == NULL) ? dot_v3v3(l_a->f->no, l_b->f->no) :
+ dot_v3v3(fnos[BM_elem_index_get(l_a->f)],
+ fnos[BM_elem_index_get(l_b->f)]);
+ if (dot >= split_angle_cos) {
+ is_smooth = true;
+ }
+ }
+ else {
+ is_smooth = true;
+ }
+ }
+
+ /* Perform `BM_elem_flag_set(e, BM_ELEM_TAG, is_smooth)`
+ * NOTE: This will be set by multiple threads however it will be set to the same value. */
+
+ /* No need for atomics here as this is a single byte. */
+ char *hflag_p = &e->head.hflag;
+ if (is_smooth) {
+ *hflag_p = *hflag_p | BM_ELEM_TAG;
+ }
+ else {
+ *hflag_p = *hflag_p & ~BM_ELEM_TAG;
+ }
+}
+
+/**
+ * A version of #bm_edge_tag_from_smooth that sets sharp edges
+ * when they would be considered smooth but exceed the split angle .
+ *
+ * \note This doesn't have the same atomic requirement as #bm_edge_tag_from_smooth
+ * since it isn't run from multiple threads at once.
+ */
+static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3],
+ BMEdge *e,
+ const float split_angle_cos)
+{
+ BLI_assert(e->l != NULL);
+ BMLoop *l_a = e->l, *l_b = l_a->radial_next;
+ bool is_smooth = false;
+ if (bm_edge_is_smooth_no_angle_test(e, l_a, l_b)) {
+ if (split_angle_cos != -1.0f) {
+ const float dot = (fnos == NULL) ? dot_v3v3(l_a->f->no, l_b->f->no) :
+ dot_v3v3(fnos[BM_elem_index_get(l_a->f)],
+ fnos[BM_elem_index_get(l_b->f)]);
+ if (dot >= split_angle_cos) {
+ is_smooth = true;
+ }
+ else {
+ /* Note that we do not care about the other sharp-edge cases
+ * (sharp poly, non-manifold edge, etc.),
+ * only tag edge as sharp when it is due to angle threshold. */
+ BM_elem_flag_disable(e, BM_ELEM_SMOOTH);
+ }
+ }
+ else {
+ is_smooth = true;
+ }
+ }
+
+ BM_elem_flag_set(e, BM_ELEM_TAG, is_smooth);
+}
+
+/**
+ * Operate on all vertices loops.
+ * operating on vertices this is needed for multi-threading
+ * so there is a guarantee that each thread has isolated loops.
+ */
+static void bm_mesh_loops_calc_normals_for_vert_with_clnors(BMesh *bm,
+ const float (*vcos)[3],
+ const float (*fnos)[3],
+ float (*r_lnos)[3],
+ const short (*clnors_data)[2],
+ const int cd_loop_clnors_offset,
+ const bool do_rebuild,
+ const float split_angle_cos,
+ /* TLS */
+ MLoopNorSpaceArray *r_lnors_spacearr,
+ BLI_Stack *edge_vectors,
+ /* Iterate over. */
+ BMVert *v)
+{
+ /* Respecting face order is necessary so the initial starting loop is consistent
+ * with looping over loops of all faces.
+ *
+ * Logically we could sort the loops by their index & loop over them
+ * however it's faster to use the lowest index of an un-ordered list
+ * since it's common that smooth vertices only ever need to pick one loop
+ * which then handles all the others.
+ *
+ * Sorting is only performed when multiple fans are found. */
+ const bool has_clnors = true;
+ LinkNode *loops_of_vert = NULL;
+ int loops_of_vert_count = 0;
+ const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS);
+
+ /* The loop with the lowest index. */
+ {
+ LinkNode *link_best;
+ uint index_best = UINT_MAX;
+ BMEdge *e_curr_iter = v->e;
+ do { /* Edges of vertex. */
+ BMLoop *l_curr = e_curr_iter->l;
+ if (l_curr == NULL) {
+ continue;
+ }
+
+ if (do_edge_tag) {
+ bm_edge_tag_from_smooth(fnos, e_curr_iter, split_angle_cos);
+ }
+
+ do { /* Radial loops. */
+ if (l_curr->v != v) {
+ continue;
+ }
+ if (do_rebuild && !BM_ELEM_API_FLAG_TEST(l_curr, BM_LNORSPACE_UPDATE) &&
+ !(bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL)) {
+ continue;
+ }
+ BM_elem_flag_disable(l_curr, BM_ELEM_TAG);
+ BLI_linklist_prepend_alloca(&loops_of_vert, l_curr);
+ loops_of_vert_count += 1;
+
+ const uint index_test = (uint)BM_elem_index_get(l_curr);
+ if (index_best > index_test) {
+ index_best = index_test;
+ link_best = loops_of_vert;
+ }
+ } while ((l_curr = l_curr->radial_next) != e_curr_iter->l);
+ } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e);
+
+ if (UNLIKELY(loops_of_vert == NULL)) {
+ return;
+ }
+
+ /* Immediately pop the best element.
+ * The order doesn't matter, so swap the links as it's simpler than tracking
+ * reference to `link_best`. */
+ if (link_best != loops_of_vert) {
+ SWAP(void *, link_best->link, loops_of_vert->link);
+ }
+ }
+
+ bool loops_of_vert_is_sorted = false;
+
+ /* Keep track of the number of loops that have been assigned. */
+ int loops_of_vert_handled = 0;
+
+ while (loops_of_vert != NULL) {
+ BMLoop *l_best = loops_of_vert->link;
+ loops_of_vert = loops_of_vert->next;
+
+ BLI_assert(l_best->v == v);
+ loops_of_vert_handled += bm_mesh_loops_calc_normals_for_loop(bm,
+ vcos,
+ fnos,
+ clnors_data,
+ cd_loop_clnors_offset,
+ has_clnors,
+ edge_vectors,
+ l_best,
+ r_lnos,
+ r_lnors_spacearr);
+
+ /* Check if an early exit is possible without an exhaustive inspection of every loop
+ * where 1 loop's fan extends out to all remaining loops.
+ * This is a common case for smooth vertices. */
+ BLI_assert(loops_of_vert_handled <= loops_of_vert_count);
+ if (loops_of_vert_handled == loops_of_vert_count) {
+ break;
+ }
+
+ /* Note on sorting, in some cases it will be faster to scan for the lowest index each time.
+ * However in the worst case this is `O(N^2)`, so use a single sort call instead. */
+ if (!loops_of_vert_is_sorted) {
+ if (loops_of_vert && loops_of_vert->next) {
+ loops_of_vert = BLI_linklist_sort(loops_of_vert, bm_loop_index_cmp);
+ loops_of_vert_is_sorted = true;
+ }
+ }
+ }
+}
+
+/**
+ * A simplified version of #bm_mesh_loops_calc_normals_for_vert_with_clnors
+ * that can operate on loops in any order.
+ */
+static void bm_mesh_loops_calc_normals_for_vert_without_clnors(
+ BMesh *bm,
+ const float (*vcos)[3],
+ const float (*fnos)[3],
+ float (*r_lnos)[3],
+ const bool do_rebuild,
+ const float split_angle_cos,
+ /* TLS */
+ MLoopNorSpaceArray *r_lnors_spacearr,
+ BLI_Stack *edge_vectors,
+ /* Iterate over. */
+ BMVert *v)
+{
+ const bool has_clnors = false;
+ const short(*clnors_data)[2] = NULL;
+ const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS);
+ const int cd_loop_clnors_offset = -1;
+
+ BMEdge *e_curr_iter;
+
+ /* Unfortunately a loop is needed just to clear loop-tags. */
+ e_curr_iter = v->e;
+ do { /* Edges of vertex. */
+ BMLoop *l_curr = e_curr_iter->l;
+ if (l_curr == NULL) {
+ continue;
+ }
+
+ if (do_edge_tag) {
+ bm_edge_tag_from_smooth(fnos, e_curr_iter, split_angle_cos);
+ }
+
+ do { /* Radial loops. */
+ if (l_curr->v != v) {
+ continue;
+ }
+ BM_elem_flag_disable(l_curr, BM_ELEM_TAG);
+ } while ((l_curr = l_curr->radial_next) != e_curr_iter->l);
+ } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e);
+
+ e_curr_iter = v->e;
+ do { /* Edges of vertex. */
+ BMLoop *l_curr = e_curr_iter->l;
+ if (l_curr == NULL) {
+ continue;
+ }
+ do { /* Radial loops. */
+ if (l_curr->v != v) {
+ continue;
+ }
+ if (do_rebuild && !BM_ELEM_API_FLAG_TEST(l_curr, BM_LNORSPACE_UPDATE) &&
+ !(bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL)) {
+ continue;
+ }
+ bm_mesh_loops_calc_normals_for_loop(bm,
+ vcos,
+ fnos,
+ clnors_data,
+ cd_loop_clnors_offset,
+ has_clnors,
+ edge_vectors,
+ l_curr,
+ r_lnos,
+ r_lnors_spacearr);
+ } while ((l_curr = l_curr->radial_next) != e_curr_iter->l);
+ } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e);
+}
+
+/**
* BMesh version of BKE_mesh_normals_loop_split() in `mesh_evaluate.cc`
* Will use first clnors_data array, and fallback to cd_loop_clnors_offset
* (use NULL and -1 to not use clnors).
@@ -533,26 +1100,24 @@ bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
* \note This sets #BM_ELEM_TAG which is used in tool code (e.g. T84426).
* we could add a low-level API flag for this, see #BM_ELEM_API_FLAG_ENABLE and friends.
*/
-static void bm_mesh_loops_calc_normals(BMesh *bm,
- const float (*vcos)[3],
- const float (*fnos)[3],
- float (*r_lnos)[3],
- MLoopNorSpaceArray *r_lnors_spacearr,
- const short (*clnors_data)[2],
- const int cd_loop_clnors_offset,
- const bool do_rebuild)
+static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
+ const float (*vcos)[3],
+ const float (*fnos)[3],
+ float (*r_lnos)[3],
+ MLoopNorSpaceArray *r_lnors_spacearr,
+ const short (*clnors_data)[2],
+ const int cd_loop_clnors_offset,
+ const bool do_rebuild,
+ const float split_angle)
{
BMIter fiter;
BMFace *f_curr;
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
+ const bool check_angle = (split_angle < (float)M_PI);
+ const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
MLoopNorSpaceArray _lnors_spacearr = {NULL};
- /* Temp normal stack. */
- BLI_SMALLSTACK_DECLARE(normal, float *);
- /* Temp clnors stack. */
- BLI_SMALLSTACK_DECLARE(clnors, short *);
- /* Temp edge vectors stack, only used when computing lnor spacearr. */
BLI_Stack *edge_vectors = NULL;
{
@@ -573,6 +1138,10 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
}
+ if (split_angle_cos != -1.0f) {
+ bm_mesh_edges_sharp_tag(bm, fnos, has_clnors ? (float)M_PI : split_angle, false);
+ }
+
/* Clear all loops' tags (means none are to be skipped for now). */
int index_face, index_loop = 0;
BM_ITER_MESH_INDEX (f_curr, &fiter, bm, BM_FACES_OF_MESH, index_face) {
@@ -601,277 +1170,249 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
!(bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL)) {
continue;
}
- /* A smooth edge, we have to check for cyclic smooth fan case.
- * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge
- * as 'entry point', otherwise we can skip it. */
-
- /* NOTE: In theory, we could make bm_mesh_loop_check_cyclic_smooth_fan() store
- * mlfan_pivot's in a stack, to avoid having to fan again around
- * the vert during actual computation of clnor & clnorspace. However, this would complicate
- * the code, add more memory usage, and
- * BM_vert_step_fan_loop() is quite cheap in term of CPU cycles,
- * so really think it's not worth it. */
- if (BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
- (BM_elem_flag_test(l_curr, BM_ELEM_TAG) || !BM_loop_check_cyclic_smooth_fan(l_curr))) {
- }
- else if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
- !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
- /* Simple case (both edges around that vertex are sharp in related polygon),
- * this vertex just takes its poly normal.
- */
- const int l_curr_index = BM_elem_index_get(l_curr);
- const float *no = fnos ? fnos[BM_elem_index_get(f_curr)] : f_curr->no;
- copy_v3_v3(r_lnos[l_curr_index], no);
-
- /* If needed, generate this (simple!) lnor space. */
- if (r_lnors_spacearr) {
- float vec_curr[3], vec_prev[3];
- MLoopNorSpace *lnor_space = BKE_lnor_space_create(r_lnors_spacearr);
-
- {
- const BMVert *v_pivot = l_curr->v;
- const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
- const BMVert *v_1 = l_curr->next->v;
- const float *co_1 = vcos ? vcos[BM_elem_index_get(v_1)] : v_1->co;
- const BMVert *v_2 = l_curr->prev->v;
- const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
-
- BLI_assert(v_1 == BM_edge_other_vert(l_curr->e, v_pivot));
- BLI_assert(v_2 == BM_edge_other_vert(l_curr->prev->e, v_pivot));
-
- sub_v3_v3v3(vec_curr, co_1, co_pivot);
- normalize_v3(vec_curr);
- sub_v3_v3v3(vec_prev, co_2, co_pivot);
- normalize_v3(vec_prev);
- }
-
- BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, NULL);
- /* We know there is only one loop in this space,
- * no need to create a linklist in this case... */
- BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, l_curr, true);
-
- if (has_clnors) {
- const short(*clnor)[2] = clnors_data ? &clnors_data[l_curr_index] :
- (const void *)BM_ELEM_CD_GET_VOID_P(
- l_curr, cd_loop_clnors_offset);
- BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor, r_lnos[l_curr_index]);
- }
- }
- }
- /* We *do not need* to check/tag loops as already computed!
- * Due to the fact a loop only links to one of its two edges,
- * a same fan *will never be walked more than once!*
- * Since we consider edges having neighbor faces with inverted (flipped) normals as sharp,
- * we are sure that no fan will be skipped, even only considering the case
- * (sharp curr_edge, smooth prev_edge), and not the alternative
- * (smooth curr_edge, sharp prev_edge).
- * All this due/thanks to link between normals and loop ordering.
- */
- else {
- /* We have to fan around current vertex, until we find the other non-smooth edge,
- * and accumulate face normals into the vertex!
- * Note in case this vertex has only one sharp edge,
- * this is a waste because the normal is the same as the vertex normal,
- * but I do not see any easy way to detect that (would need to count number of sharp edges
- * per vertex, I doubt the additional memory usage would be worth it, especially as it
- * should not be a common case in real-life meshes anyway).
- */
- BMVert *v_pivot = l_curr->v;
- BMEdge *e_next;
- const BMEdge *e_org = l_curr->e;
- BMLoop *lfan_pivot, *lfan_pivot_next;
- int lfan_pivot_index;
- float lnor[3] = {0.0f, 0.0f, 0.0f};
- float vec_curr[3], vec_next[3], vec_org[3];
-
- /* We validate clnors data on the fly - cheapest way to do! */
- int clnors_avg[2] = {0, 0};
- const short(*clnor_ref)[2] = NULL;
- int clnors_nbr = 0;
- bool clnors_invalid = false;
-
- const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
-
- MLoopNorSpace *lnor_space = r_lnors_spacearr ? BKE_lnor_space_create(r_lnors_spacearr) :
- NULL;
-
- BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors));
-
- lfan_pivot = l_curr;
- lfan_pivot_index = BM_elem_index_get(lfan_pivot);
- e_next = lfan_pivot->e; /* Current edge here, actually! */
-
- /* Only need to compute previous edge's vector once,
- * then we can just reuse old current one! */
- {
- const BMVert *v_2 = lfan_pivot->next->v;
- const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
-
- BLI_assert(v_2 == BM_edge_other_vert(e_next, v_pivot));
-
- sub_v3_v3v3(vec_org, co_2, co_pivot);
- normalize_v3(vec_org);
- copy_v3_v3(vec_curr, vec_org);
+ bm_mesh_loops_calc_normals_for_loop(bm,
+ vcos,
+ fnos,
+ clnors_data,
+ cd_loop_clnors_offset,
+ has_clnors,
+ edge_vectors,
+ l_curr,
+ r_lnos,
+ r_lnors_spacearr);
+ } while ((l_curr = l_curr->next) != l_first);
+ }
- if (r_lnors_spacearr) {
- BLI_stack_push(edge_vectors, vec_org);
- }
- }
+ if (r_lnors_spacearr) {
+ BLI_stack_free(edge_vectors);
+ if (r_lnors_spacearr == &_lnors_spacearr) {
+ BKE_lnor_spacearr_free(r_lnors_spacearr);
+ }
+ }
+}
- while (true) {
- /* Much simpler than in sibling code with basic Mesh data! */
- lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
- if (lfan_pivot_next) {
- BLI_assert(lfan_pivot_next->v == v_pivot);
- }
- else {
- /* next edge is non-manifold, we have to find it ourselves! */
- e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
- }
+typedef struct BMLoopsCalcNormalsWithCoordsData {
+ /* Read-only data. */
+ const float (*fnos)[3];
+ const float (*vcos)[3];
+ BMesh *bm;
+ const short (*clnors_data)[2];
+ const int cd_loop_clnors_offset;
+ const bool do_rebuild;
+ const float split_angle_cos;
+
+ /* Output. */
+ float (*r_lnos)[3];
+ MLoopNorSpaceArray *r_lnors_spacearr;
+} BMLoopsCalcNormalsWithCoordsData;
+
+typedef struct BMLoopsCalcNormalsWithCoords_TLS {
+ BLI_Stack *edge_vectors;
+
+ /** Copied from #BMLoopsCalcNormalsWithCoordsData.r_lnors_spacearr when it's not NULL. */
+ MLoopNorSpaceArray *lnors_spacearr;
+ MLoopNorSpaceArray lnors_spacearr_buf;
+} BMLoopsCalcNormalsWithCoords_TLS;
+
+static void bm_mesh_loops_calc_normals_for_vert_init_fn(const void *__restrict userdata,
+ void *__restrict chunk)
+{
+ const BMLoopsCalcNormalsWithCoordsData *data = userdata;
+ BMLoopsCalcNormalsWithCoords_TLS *tls_data = chunk;
+ if (data->r_lnors_spacearr) {
+ tls_data->edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
+ BKE_lnor_spacearr_tls_init(data->r_lnors_spacearr, &tls_data->lnors_spacearr_buf);
+ tls_data->lnors_spacearr = &tls_data->lnors_spacearr_buf;
+ }
+ else {
+ tls_data->lnors_spacearr = NULL;
+ }
+}
- /* Compute edge vector.
- * NOTE: We could pre-compute those into an array, in the first iteration,
- * instead of computing them twice (or more) here.
- * However, time gained is not worth memory and time lost,
- * given the fact that this code should not be called that much in real-life meshes.
- */
- {
- const BMVert *v_2 = BM_edge_other_vert(e_next, v_pivot);
- const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
+static void bm_mesh_loops_calc_normals_for_vert_reduce_fn(const void *__restrict userdata,
+ void *__restrict UNUSED(chunk_join),
+ void *__restrict chunk)
+{
+ const BMLoopsCalcNormalsWithCoordsData *data = userdata;
+ BMLoopsCalcNormalsWithCoords_TLS *tls_data = chunk;
- sub_v3_v3v3(vec_next, co_2, co_pivot);
- normalize_v3(vec_next);
- }
+ if (data->r_lnors_spacearr) {
+ BKE_lnor_spacearr_tls_join(data->r_lnors_spacearr, tls_data->lnors_spacearr);
+ }
+}
- {
- /* Code similar to accumulate_vertex_normals_poly_v3. */
- /* Calculate angle between the two poly edges incident on this vertex. */
- const BMFace *f = lfan_pivot->f;
- const float fac = saacos(dot_v3v3(vec_next, vec_curr));
- const float *no = fnos ? fnos[BM_elem_index_get(f)] : f->no;
- /* Accumulate */
- madd_v3_v3fl(lnor, no, fac);
-
- if (has_clnors) {
- /* Accumulate all clnors, if they are not all equal we have to fix that! */
- const short(*clnor)[2] = clnors_data ? &clnors_data[lfan_pivot_index] :
- (const void *)BM_ELEM_CD_GET_VOID_P(
- lfan_pivot, cd_loop_clnors_offset);
- if (clnors_nbr) {
- clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] ||
- (*clnor_ref)[1] != (*clnor)[1]);
- }
- else {
- clnor_ref = clnor;
- }
- clnors_avg[0] += (*clnor)[0];
- clnors_avg[1] += (*clnor)[1];
- clnors_nbr++;
- /* We store here a pointer to all custom lnors processed. */
- BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
- }
- }
+static void bm_mesh_loops_calc_normals_for_vert_free_fn(const void *__restrict userdata,
+ void *__restrict chunk)
+{
+ const BMLoopsCalcNormalsWithCoordsData *data = userdata;
+ BMLoopsCalcNormalsWithCoords_TLS *tls_data = chunk;
- /* We store here a pointer to all loop-normals processed. */
- BLI_SMALLSTACK_PUSH(normal, (float *)r_lnos[lfan_pivot_index]);
+ if (data->r_lnors_spacearr) {
+ BLI_stack_free(tls_data->edge_vectors);
+ }
+}
- if (r_lnors_spacearr) {
- /* Assign current lnor space to current 'vertex' loop. */
- BKE_lnor_space_add_loop(
- r_lnors_spacearr, lnor_space, lfan_pivot_index, lfan_pivot, false);
- if (e_next != e_org) {
- /* We store here all edges-normalized vectors processed. */
- BLI_stack_push(edge_vectors, vec_next);
- }
- }
+static void bm_mesh_loops_calc_normals_for_vert_with_clnors_fn(
+ void *userdata, MempoolIterData *mp_v, const TaskParallelTLS *__restrict tls)
+{
+ BMVert *v = (BMVert *)mp_v;
+ if (v->e == NULL) {
+ return;
+ }
+ BMLoopsCalcNormalsWithCoordsData *data = userdata;
+ BMLoopsCalcNormalsWithCoords_TLS *tls_data = tls->userdata_chunk;
+ bm_mesh_loops_calc_normals_for_vert_with_clnors(data->bm,
+ data->vcos,
+ data->fnos,
+ data->r_lnos,
+
+ data->clnors_data,
+ data->cd_loop_clnors_offset,
+ data->do_rebuild,
+ data->split_angle_cos,
+ /* Thread local. */
+ tls_data->lnors_spacearr,
+ tls_data->edge_vectors,
+ /* Iterate over. */
+ v);
+}
- if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
- /* Next edge is sharp, we have finished with this fan of faces around this vert! */
- break;
- }
+static void bm_mesh_loops_calc_normals_for_vert_without_clnors_fn(
+ void *userdata, MempoolIterData *mp_v, const TaskParallelTLS *__restrict tls)
+{
+ BMVert *v = (BMVert *)mp_v;
+ if (v->e == NULL) {
+ return;
+ }
+ BMLoopsCalcNormalsWithCoordsData *data = userdata;
+ BMLoopsCalcNormalsWithCoords_TLS *tls_data = tls->userdata_chunk;
+ bm_mesh_loops_calc_normals_for_vert_without_clnors(data->bm,
+ data->vcos,
+ data->fnos,
+ data->r_lnos,
+
+ data->do_rebuild,
+ data->split_angle_cos,
+ /* Thread local. */
+ tls_data->lnors_spacearr,
+ tls_data->edge_vectors,
+ /* Iterate over. */
+ v);
+}
- /* Copy next edge vector to current one. */
- copy_v3_v3(vec_curr, vec_next);
- /* Next pivot loop to current one. */
- lfan_pivot = lfan_pivot_next;
- lfan_pivot_index = BM_elem_index_get(lfan_pivot);
- }
+static void bm_mesh_loops_calc_normals__multi_threaded(BMesh *bm,
+ const float (*vcos)[3],
+ const float (*fnos)[3],
+ float (*r_lnos)[3],
+ MLoopNorSpaceArray *r_lnors_spacearr,
+ const short (*clnors_data)[2],
+ const int cd_loop_clnors_offset,
+ const bool do_rebuild,
+ const float split_angle)
+{
+ const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
+ const bool check_angle = (split_angle < (float)M_PI);
+ const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
- {
- float lnor_len = normalize_v3(lnor);
+ MLoopNorSpaceArray _lnors_spacearr = {NULL};
- /* If we are generating lnor spacearr, we can now define the one for this fan. */
- if (r_lnors_spacearr) {
- if (UNLIKELY(lnor_len == 0.0f)) {
- /* Use vertex normal as fallback! */
- copy_v3_v3(lnor, r_lnos[lfan_pivot_index]);
- lnor_len = 1.0f;
- }
+ {
+ char htype = BM_LOOP;
+ if (vcos) {
+ htype |= BM_VERT;
+ }
+ if (fnos) {
+ htype |= BM_FACE;
+ }
+ /* Face/Loop indices are set inline below. */
+ BM_mesh_elem_index_ensure(bm, htype);
+ }
- BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_next, edge_vectors);
-
- if (has_clnors) {
- if (clnors_invalid) {
- short *clnor;
-
- clnors_avg[0] /= clnors_nbr;
- clnors_avg[1] /= clnors_nbr;
- /* Fix/update all clnors of this fan with computed average value. */
-
- /* Prints continuously when merge custom normals, so commenting. */
- /* printf("Invalid clnors in this fan!\n"); */
-
- while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
- // print_v2("org clnor", clnor);
- clnor[0] = (short)clnors_avg[0];
- clnor[1] = (short)clnors_avg[1];
- }
- // print_v2("new clnors", clnors_avg);
- }
- else {
- /* We still have to consume the stack! */
- while (BLI_SMALLSTACK_POP(clnors)) {
- /* pass */
- }
- }
- BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
- }
- }
+ if (!r_lnors_spacearr && has_clnors) {
+ /* We need to compute lnor spacearr if some custom lnor data are given to us! */
+ r_lnors_spacearr = &_lnors_spacearr;
+ }
+ if (r_lnors_spacearr) {
+ BKE_lnor_spacearr_init(r_lnors_spacearr, bm->totloop, MLNOR_SPACEARR_BMLOOP_PTR);
+ }
- /* In case we get a zero normal here, just use vertex normal already set! */
- if (LIKELY(lnor_len != 0.0f)) {
- /* Copy back the final computed normal into all related loop-normals. */
- float *nor;
+ /* We now know edges that can be smoothed (they are tagged),
+ * and edges that will be hard (they aren't).
+ * Now, time to generate the normals.
+ */
- while ((nor = BLI_SMALLSTACK_POP(normal))) {
- copy_v3_v3(nor, lnor);
- }
- }
- else {
- /* We still have to consume the stack! */
- while (BLI_SMALLSTACK_POP(normal)) {
- /* pass */
- }
- }
- }
+ TaskParallelSettings settings;
+ BLI_parallel_mempool_settings_defaults(&settings);
- /* Tag related vertex as sharp, to avoid fanning around it again
- * (in case it was a smooth one). */
- if (r_lnors_spacearr) {
- BM_elem_flag_enable(l_curr->v, BM_ELEM_TAG);
- }
- }
- } while ((l_curr = l_curr->next) != l_first);
- }
+ BMLoopsCalcNormalsWithCoords_TLS tls = {NULL};
+
+ settings.userdata_chunk = &tls;
+ settings.userdata_chunk_size = sizeof(tls);
+
+ settings.func_init = bm_mesh_loops_calc_normals_for_vert_init_fn;
+ settings.func_reduce = bm_mesh_loops_calc_normals_for_vert_reduce_fn;
+ settings.func_free = bm_mesh_loops_calc_normals_for_vert_free_fn;
+
+ BMLoopsCalcNormalsWithCoordsData data = {
+ .bm = bm,
+ .vcos = vcos,
+ .fnos = fnos,
+ .r_lnos = r_lnos,
+ .r_lnors_spacearr = r_lnors_spacearr,
+ .clnors_data = clnors_data,
+ .cd_loop_clnors_offset = cd_loop_clnors_offset,
+ .do_rebuild = do_rebuild,
+ .split_angle_cos = split_angle_cos,
+ };
+
+ BM_iter_parallel(bm,
+ BM_VERTS_OF_MESH,
+ has_clnors ? bm_mesh_loops_calc_normals_for_vert_with_clnors_fn :
+ bm_mesh_loops_calc_normals_for_vert_without_clnors_fn,
+ &data,
+ &settings);
if (r_lnors_spacearr) {
- BLI_stack_free(edge_vectors);
if (r_lnors_spacearr == &_lnors_spacearr) {
BKE_lnor_spacearr_free(r_lnors_spacearr);
}
}
}
+static void bm_mesh_loops_calc_normals(BMesh *bm,
+ const float (*vcos)[3],
+ const float (*fnos)[3],
+ float (*r_lnos)[3],
+ MLoopNorSpaceArray *r_lnors_spacearr,
+ const short (*clnors_data)[2],
+ const int cd_loop_clnors_offset,
+ const bool do_rebuild,
+ const float split_angle)
+{
+ if (bm->totloop < BM_OMP_LIMIT) {
+ bm_mesh_loops_calc_normals__single_threaded(bm,
+ vcos,
+ fnos,
+ r_lnos,
+ r_lnors_spacearr,
+ clnors_data,
+ cd_loop_clnors_offset,
+ do_rebuild,
+ split_angle);
+ }
+ else {
+ bm_mesh_loops_calc_normals__multi_threaded(bm,
+ vcos,
+ fnos,
+ r_lnos,
+ r_lnors_spacearr,
+ clnors_data,
+ cd_loop_clnors_offset,
+ do_rebuild,
+ split_angle);
+ }
+}
+
/* This threshold is a bit touchy (usual float precision issue), this value seems OK. */
#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f)
@@ -1062,7 +1603,6 @@ static void bm_mesh_loops_assign_normal_data(BMesh *bm,
*/
static void bm_mesh_loops_custom_normals_set(BMesh *bm,
const float (*vcos)[3],
- const float (*vnos)[3],
const float (*fnos)[3],
MLoopNorSpaceArray *r_lnors_spacearr,
short (*r_clnors_data)[2],
@@ -1080,12 +1620,19 @@ static void bm_mesh_loops_custom_normals_set(BMesh *bm,
/* Tag smooth edges and set lnos from vnos when they might be completely smooth...
* When using custom loop normals, disable the angle feature! */
- bm_mesh_edges_sharp_tag(bm, vnos, fnos, cur_lnors, (float)M_PI, false);
+ bm_mesh_edges_sharp_tag(bm, fnos, (float)M_PI, false);
/* Finish computing lnos by accumulating face normals
* in each fan of faces defined by sharp edges. */
- bm_mesh_loops_calc_normals(
- bm, vcos, fnos, cur_lnors, r_lnors_spacearr, r_clnors_data, cd_loop_clnors_offset, false);
+ bm_mesh_loops_calc_normals(bm,
+ vcos,
+ fnos,
+ cur_lnors,
+ r_lnors_spacearr,
+ r_clnors_data,
+ cd_loop_clnors_offset,
+ false,
+ EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS);
/* Extract new normals from the data layer if necessary. */
float(*custom_lnors)[3] = new_lnors;
@@ -1118,8 +1665,15 @@ static void bm_mesh_loops_custom_normals_set(BMesh *bm,
* spacearr/smooth fans matching the given custom lnors. */
BKE_lnor_spacearr_clear(r_lnors_spacearr);
- bm_mesh_loops_calc_normals(
- bm, vcos, fnos, cur_lnors, r_lnors_spacearr, r_clnors_data, cd_loop_clnors_offset, false);
+ bm_mesh_loops_calc_normals(bm,
+ vcos,
+ fnos,
+ cur_lnors,
+ r_lnors_spacearr,
+ r_clnors_data,
+ cd_loop_clnors_offset,
+ false,
+ EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS);
}
/* And we just have to convert plain object-space custom normals to our
@@ -1167,40 +1721,6 @@ static void bm_mesh_loops_calc_normals_no_autosmooth(BMesh *bm,
}
}
-#if 0 /* Unused currently */
-/**
- * \brief BMesh Compute Loop Normals
- *
- * Updates the loop normals of a mesh.
- * Assumes vertex and face normals are valid (else call BM_mesh_normals_update() first)!
- */
-void BM_mesh_loop_normals_update(BMesh *bm,
- const bool use_split_normals,
- const float split_angle,
- float (*r_lnos)[3],
- MLoopNorSpaceArray *r_lnors_spacearr,
- const short (*clnors_data)[2],
- const int cd_loop_clnors_offset)
-{
- const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
-
- if (use_split_normals) {
- /* Tag smooth edges and set lnos from vnos when they might be completely smooth...
- * When using custom loop normals, disable the angle feature! */
- bm_mesh_edges_sharp_tag(bm, NULL, NULL, has_clnors ? (float)M_PI : split_angle, r_lnos);
-
- /* Finish computing lnos by accumulating face normals
- * in each fan of faces defined by sharp edges. */
- bm_mesh_loops_calc_normals(
- bm, NULL, NULL, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
- }
- else {
- BLI_assert(!r_lnors_spacearr);
- bm_mesh_loops_calc_normals_no_autosmooth(bm, NULL, NULL, r_lnos);
- }
-}
-#endif
-
/**
* \brief BMesh Compute Loop Normals from/to external data.
*
@@ -1223,14 +1743,15 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
if (use_split_normals) {
- /* Tag smooth edges and set lnos from vnos when they might be completely smooth...
- * When using custom loop normals, disable the angle feature! */
- bm_mesh_edges_sharp_tag(bm, vnos, fnos, r_lnos, has_clnors ? (float)M_PI : split_angle, false);
-
- /* Finish computing lnos by accumulating face normals
- * in each fan of faces defined by sharp edges. */
- bm_mesh_loops_calc_normals(
- bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset, do_rebuild);
+ bm_mesh_loops_calc_normals(bm,
+ vcos,
+ fnos,
+ r_lnos,
+ r_lnors_spacearr,
+ clnors_data,
+ cd_loop_clnors_offset,
+ do_rebuild,
+ has_clnors ? (float)M_PI : split_angle);
}
else {
BLI_assert(!r_lnors_spacearr);
@@ -1788,7 +2309,6 @@ void BM_custom_loop_normals_from_vector_layer(BMesh *bm, bool add_sharp_edges)
bm_mesh_loops_custom_normals_set(bm,
NULL,
NULL,
- NULL,
bm->lnor_spacearr,
NULL,
cd_custom_normal_offset,
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 3978959a425..b63a09a97a6 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -245,7 +245,7 @@ static BMOpDefine bmo_region_extend_def = {
* Edge Rotate.
*
* Rotates edges topologically. Also known as "spin edge" to some people.
- * Simple example: ``[/] becomes [|] then [\]``.
+ * Simple example: `[/] becomes [|] then [\]`.
*/
static BMOpDefine bmo_rotate_edges_def = {
"rotate_edges",
@@ -1942,7 +1942,7 @@ static BMOpDefine bmo_inset_region_def = {
};
/*
- * Edgeloop Offset.
+ * Edge-loop Offset.
*
* Creates edge loops based on simple edge-outset method.
*/
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 0aab10e7b1a..51ae47adacc 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -316,7 +316,7 @@ float BM_face_calc_perimeter_with_mat3(const BMFace *f, const float mat3[3][3])
/**
* Utility function to calculate the edge which is most different from the other two.
*
- * \return The first edge index, where the second vertex is ``(index + 1) % 3``.
+ * \return The first edge index, where the second vertex is `(index + 1) % 3`.
*/
static int bm_vert_tri_find_unique_edge(BMVert *verts[3])
{
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index bc881040e4e..cb5764b1c91 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -766,7 +766,7 @@ bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
}
/**
- * Fast alternative to ``(BM_vert_edge_count(v) == 2)``
+ * Fast alternative to `(BM_vert_edge_count(v) == 2)`.
*/
bool BM_vert_is_edge_pair(const BMVert *v)
{
@@ -779,7 +779,7 @@ bool BM_vert_is_edge_pair(const BMVert *v)
}
/**
- * Fast alternative to ``(BM_vert_edge_count(v) == 2)``
+ * Fast alternative to `(BM_vert_edge_count(v) == 2)`
* that checks both edges connect to the same faces.
*/
bool BM_vert_is_edge_pair_manifold(const BMVert *v)
@@ -896,7 +896,7 @@ int BM_vert_face_count_at_most(const BMVert *v, int count_max)
/**
* Return true if the vertex is connected to _any_ faces.
*
- * same as ``BM_vert_face_count(v) != 0`` or ``BM_vert_find_first_loop(v) == NULL``
+ * same as `BM_vert_face_count(v) != 0` or `BM_vert_find_first_loop(v) == NULL`.
*/
bool BM_vert_face_check(const BMVert *v)
{
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index 5627f3820c2..021358f81ad 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -272,7 +272,7 @@ int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm,
int (**r_groups)[3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3, 4, 5);
-/* not really any good place to put this */
+/* Not really any good place to put this. */
float bmesh_subd_falloff_calc(const int falloff, float val) ATTR_WARN_UNUSED_RESULT;
#include "bmesh_query_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
index cfdce0b749b..d5d72cd4ba3 100644
--- a/source/blender/bmesh/intern/bmesh_structure.c
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -592,7 +592,7 @@ int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const
/**
* \brief RADIAL CHECK FACE VERT
*
- * Quicker check for ``bmesh_radial_facevert_count(...) != 0``
+ * Quicker check for `bmesh_radial_facevert_count(...) != 0`.
*/
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v)
{
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index 4ae5bfb7fb2..924538490ad 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -1336,7 +1336,7 @@ static void bm_vert_fasthash_destroy(UUIDFashMatch *fm)
* Take a face-region and return a list of matching face-regions.
*
* \param faces_region: A single, contiguous face-region.
- * \return A list of matching null-terminated face-region arrays.
+ * \return A list of matching null-terminated face-region arrays.
*/
int BM_mesh_region_match(BMesh *bm,
BMFace **faces_region,
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 20b56ceb55f..830792a2a48 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -49,8 +49,11 @@ set(SRC
COM_compositor.h
COM_defines.h
+ intern/COM_BufferArea.h
intern/COM_BufferOperation.cc
intern/COM_BufferOperation.h
+ intern/COM_BufferRange.h
+ intern/COM_BuffersIterator.h
intern/COM_CPUDevice.cc
intern/COM_CPUDevice.h
intern/COM_ChunkOrder.cc
diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h
index 9f8e6f10215..900f29db44c 100644
--- a/source/blender/compositor/COM_defines.h
+++ b/source/blender/compositor/COM_defines.h
@@ -18,6 +18,9 @@
#pragma once
+#include "BLI_index_range.hh"
+#include "BLI_rect.h"
+
namespace blender::compositor {
enum class eExecutionModel {
@@ -63,6 +66,7 @@ constexpr int COM_DATA_TYPE_VALUE_CHANNELS = COM_data_type_num_channels(DataType
constexpr int COM_DATA_TYPE_VECTOR_CHANNELS = COM_data_type_num_channels(DataType::Vector);
constexpr int COM_DATA_TYPE_COLOR_CHANNELS = COM_data_type_num_channels(DataType::Color);
+constexpr float COM_COLOR_TRANSPARENT[4] = {0.0f, 0.0f, 0.0f, 0.0f};
constexpr float COM_VECTOR_ZERO[3] = {0.0f, 0.0f, 0.0f};
constexpr float COM_VALUE_ZERO[1] = {0.0f};
constexpr float COM_VALUE_ONE[1] = {1.0f};
@@ -109,4 +113,24 @@ constexpr float COM_PREVIEW_SIZE = 140.f;
constexpr float COM_RULE_OF_THIRDS_DIVIDER = 100.0f;
constexpr float COM_BLUR_BOKEH_PIXELS = 512;
+constexpr IndexRange XRange(const rcti &area)
+{
+ return IndexRange(area.xmin, area.xmax - area.xmin);
+}
+
+constexpr IndexRange YRange(const rcti &area)
+{
+ return IndexRange(area.ymin, area.ymax - area.ymin);
+}
+
+constexpr IndexRange XRange(const rcti *area)
+{
+ return XRange(*area);
+}
+
+constexpr IndexRange YRange(const rcti *area)
+{
+ return YRange(*area);
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_BufferArea.h b/source/blender/compositor/intern/COM_BufferArea.h
new file mode 100644
index 00000000000..6f7756ecbfc
--- /dev/null
+++ b/source/blender/compositor/intern/COM_BufferArea.h
@@ -0,0 +1,215 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "BLI_assert.h"
+#include "BLI_rect.h"
+#include <iterator>
+
+namespace blender::compositor {
+
+/* Forward declarations. */
+template<typename T> class BufferAreaIterator;
+
+/**
+ * A rectangle area of buffer elements.
+ */
+template<typename T> class BufferArea : rcti {
+ public:
+ using Iterator = BufferAreaIterator<T>;
+ using ConstIterator = BufferAreaIterator<const T>;
+
+ private:
+ T *buffer_;
+ /* Number of elements in a buffer row. */
+ int buffer_width_;
+ /* Buffer element stride. */
+ int elem_stride_;
+
+ public:
+ constexpr BufferArea() = default;
+
+ /**
+ * Create a buffer area containing given rectangle area.
+ */
+ constexpr BufferArea(T *buffer, int buffer_width, const rcti &area, int elem_stride = 1)
+ : rcti(area), buffer_(buffer), buffer_width_(buffer_width), elem_stride_(elem_stride)
+ {
+ }
+
+ /**
+ * Create a buffer area containing whole buffer with no offsets.
+ */
+ constexpr BufferArea(T *buffer, int buffer_width, int buffer_height, int elem_stride = 1)
+ : buffer_(buffer), buffer_width_(buffer_width), elem_stride_(elem_stride)
+ {
+ BLI_rcti_init(this, 0, buffer_width, 0, buffer_height);
+ }
+
+ constexpr friend bool operator==(const BufferArea &a, const BufferArea &b)
+ {
+ return a.buffer_ == b.buffer_ && BLI_rcti_compare(&a, &b) && a.elem_stride_ == b.elem_stride_;
+ }
+
+ constexpr const rcti &get_rect() const
+ {
+ return *this;
+ }
+
+ /**
+ * Number of elements in a row.
+ */
+ constexpr int width() const
+ {
+ return BLI_rcti_size_x(this);
+ }
+
+ /**
+ * Number of elements in a column.
+ */
+ constexpr int height() const
+ {
+ return BLI_rcti_size_y(this);
+ }
+
+ constexpr Iterator begin()
+ {
+ return begin_iterator<Iterator>();
+ }
+
+ constexpr Iterator end()
+ {
+ return end_iterator<Iterator>();
+ }
+
+ constexpr ConstIterator begin() const
+ {
+ return begin_iterator<ConstIterator>();
+ }
+
+ constexpr ConstIterator end() const
+ {
+ return end_iterator<ConstIterator>();
+ }
+
+ private:
+ template<typename TIterator> constexpr TIterator begin_iterator() const
+ {
+ T *end_ptr = get_end_ptr();
+ if (elem_stride_ == 0) {
+ /* Iterate a single element. */
+ return TIterator(buffer_, end_ptr, 1, 1, 1);
+ }
+
+ T *begin_ptr = buffer_ + (intptr_t)this->ymin * buffer_width_ * elem_stride_ +
+ (intptr_t)this->xmin * elem_stride_;
+ return TIterator(begin_ptr, end_ptr, buffer_width_, BLI_rcti_size_x(this), elem_stride_);
+ }
+
+ template<typename TIterator> constexpr TIterator end_iterator() const
+ {
+ T *end_ptr = get_end_ptr();
+ if (elem_stride_ == 0) {
+ /* Iterate a single element. */
+ return TIterator(end_ptr, end_ptr, 1, 1, 1);
+ }
+
+ return TIterator(end_ptr, end_ptr, buffer_width_, BLI_rcti_size_x(this), elem_stride_);
+ }
+
+ T *get_end_ptr() const
+ {
+ if (elem_stride_ == 0) {
+ return buffer_ + 1;
+ }
+ return buffer_ + (intptr_t)(this->ymax - 1) * buffer_width_ * elem_stride_ +
+ (intptr_t)this->xmax * elem_stride_;
+ }
+};
+
+template<typename T> class BufferAreaIterator {
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = T *;
+ using pointer = T *const *;
+ using reference = T *const &;
+ using difference_type = std::ptrdiff_t;
+
+ private:
+ int elem_stride_;
+ int row_stride_;
+ /* Stride between a row end and the next row start. */
+ int rows_gap_;
+ T *current_;
+ const T *row_end_;
+ const T *end_;
+
+ public:
+ constexpr BufferAreaIterator() = default;
+
+ constexpr BufferAreaIterator(
+ T *current, const T *end, int buffer_width, int area_width, int elem_stride = 1)
+ : elem_stride_(elem_stride),
+ row_stride_(buffer_width * elem_stride),
+ rows_gap_(row_stride_ - area_width * elem_stride),
+ current_(current),
+ row_end_(current + area_width * elem_stride),
+ end_(end)
+ {
+ }
+
+ constexpr BufferAreaIterator &operator++()
+ {
+ current_ += elem_stride_;
+ BLI_assert(current_ <= row_end_);
+ if (current_ == row_end_) {
+ BLI_assert(current_ <= end_);
+ if (current_ == end_) {
+ return *this;
+ }
+ current_ += rows_gap_;
+ row_end_ += row_stride_;
+ }
+ return *this;
+ }
+
+ constexpr BufferAreaIterator operator++(int) const
+ {
+ BufferAreaIterator copied_iterator = *this;
+ ++copied_iterator;
+ return copied_iterator;
+ }
+
+ constexpr friend bool operator!=(const BufferAreaIterator &a, const BufferAreaIterator &b)
+ {
+ return a.current_ != b.current_;
+ }
+
+ constexpr friend bool operator==(const BufferAreaIterator &a, const BufferAreaIterator &b)
+ {
+ return a.current_ == b.current_;
+ }
+
+ constexpr T *operator*() const
+ {
+ return current_;
+ }
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_BufferRange.h b/source/blender/compositor/intern/COM_BufferRange.h
new file mode 100644
index 00000000000..ffdf1f2f1e5
--- /dev/null
+++ b/source/blender/compositor/intern/COM_BufferRange.h
@@ -0,0 +1,171 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "BLI_assert.h"
+#include "BLI_rect.h"
+
+#include <iterator>
+
+namespace blender::compositor {
+
+/* Forward declarations. */
+template<typename T> class BufferRangeIterator;
+
+/**
+ * A range of buffer elements.
+ */
+template<typename T> class BufferRange {
+ public:
+ using Iterator = BufferRangeIterator<T>;
+ using ConstIterator = BufferRangeIterator<const T>;
+
+ private:
+ T *start_;
+ /* Number of elements in the range. */
+ int64_t size_;
+ /* Buffer element stride. */
+ int elem_stride_;
+
+ public:
+ constexpr BufferRange() = default;
+
+ /**
+ * Create a buffer range of elements from a given element index.
+ */
+ constexpr BufferRange(T *buffer, int64_t start_elem_index, int64_t size, int elem_stride = 1)
+ : start_(buffer + start_elem_index * elem_stride), size_(size), elem_stride_(elem_stride)
+ {
+ }
+
+ constexpr friend bool operator==(const BufferRange &a, const BufferRange &b)
+ {
+ return a.start_ == b.start_ && a.size_ == b.size_ && a.elem_stride_ == b.elem_stride_;
+ }
+
+ /**
+ * Access an element in the range. Index is relative to range start.
+ */
+ constexpr T *operator[](int64_t index) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ return start_ + index * elem_stride_;
+ }
+
+ /**
+ * Get the number of elements in the range.
+ */
+ constexpr int64_t size() const
+ {
+ return size_;
+ }
+
+ constexpr Iterator begin()
+ {
+ return begin_iterator<Iterator>();
+ }
+
+ constexpr Iterator end()
+ {
+ return end_iterator<Iterator>();
+ }
+
+ constexpr ConstIterator begin() const
+ {
+ return begin_iterator<ConstIterator>();
+ }
+
+ constexpr ConstIterator end() const
+ {
+ return end_iterator<ConstIterator>();
+ }
+
+ private:
+ template<typename TIterator> constexpr TIterator begin_iterator() const
+ {
+ if (elem_stride_ == 0) {
+ /* Iterate a single element. */
+ return TIterator(start_, 1);
+ }
+
+ return TIterator(start_, elem_stride_);
+ }
+
+ template<typename TIterator> constexpr TIterator end_iterator() const
+ {
+ if (elem_stride_ == 0) {
+ /* Iterate a single element. */
+ return TIterator(start_ + 1, 1);
+ }
+
+ return TIterator(start_ + size_ * elem_stride_, elem_stride_);
+ }
+};
+
+template<typename T> class BufferRangeIterator {
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = T *;
+ using pointer = T *const *;
+ using reference = T *const &;
+ using difference_type = std::ptrdiff_t;
+
+ private:
+ T *current_;
+ int elem_stride_;
+
+ public:
+ constexpr BufferRangeIterator() = default;
+
+ constexpr BufferRangeIterator(T *current, int elem_stride = 1)
+ : current_(current), elem_stride_(elem_stride)
+ {
+ }
+
+ constexpr BufferRangeIterator &operator++()
+ {
+ current_ += elem_stride_;
+ return *this;
+ }
+
+ constexpr BufferRangeIterator operator++(int) const
+ {
+ BufferRangeIterator copied_iterator = *this;
+ ++copied_iterator;
+ return copied_iterator;
+ }
+
+ constexpr friend bool operator!=(const BufferRangeIterator &a, const BufferRangeIterator &b)
+ {
+ return a.current_ != b.current_;
+ }
+
+ constexpr friend bool operator==(const BufferRangeIterator &a, const BufferRangeIterator &b)
+ {
+ return a.current_ == b.current_;
+ }
+
+ constexpr T *operator*() const
+ {
+ return current_;
+ }
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_BuffersIterator.h b/source/blender/compositor/intern/COM_BuffersIterator.h
new file mode 100644
index 00000000000..bfe0b7a3d45
--- /dev/null
+++ b/source/blender/compositor/intern/COM_BuffersIterator.h
@@ -0,0 +1,195 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "BLI_rect.h"
+#include "BLI_vector.hh"
+
+namespace blender::compositor {
+
+/**
+ * Builds an iterator for simultaneously iterating an area of elements in an output buffer and any
+ * number of input buffers. It's not a standard C++ iterator and it does not support neither
+ * deference, equality or postfix increment operators.
+ */
+template<typename T> class BuffersIteratorBuilder {
+ public:
+ class Iterator {
+ int x_start_;
+ int x_end_;
+ const T *out_end_;
+ int out_elem_stride_;
+ /* Stride between an output row end and the next row start. */
+ int out_rows_gap_;
+
+ struct In {
+ int elem_stride;
+ int rows_gap;
+ const T *in;
+ };
+ Vector<In, 6> ins_;
+
+ friend class BuffersIteratorBuilder;
+
+ public:
+ int x;
+ int y;
+ /** Current output element. */
+ T *out;
+
+ public:
+ /**
+ * Get current element from an input.
+ */
+ const T *in(int input_index) const
+ {
+ BLI_assert(input_index < ins_.size());
+ return ins_[input_index].in;
+ }
+
+ int get_num_inputs() const
+ {
+ return ins_.size();
+ }
+
+ /**
+ * Has the end of the area been reached.
+ */
+ bool is_end() const
+ {
+ return out >= out_end_;
+ }
+
+ /**
+ * Go to the next element in the area.
+ */
+ void next()
+ {
+ out += out_elem_stride_;
+ for (In &in : ins_) {
+ in.in += in.elem_stride;
+ }
+ x++;
+ if (x == x_end_) {
+ x = x_start_;
+ y++;
+ out += out_rows_gap_;
+ for (In &in : ins_) {
+ in.in += in.rows_gap;
+ }
+ }
+ }
+
+ Iterator &operator++()
+ {
+ this->next();
+ return *this;
+ }
+ };
+
+ private:
+ Iterator iterator_;
+ rcti area_;
+ bool is_built_;
+
+ public:
+ /**
+ * Create a buffers iterator builder to iterate given output buffer area.
+ * \param output: Output buffer.
+ * \param buffer_area: Whole output buffer area (may have offset position).
+ * \param iterated_area: Area to be iterated in all buffers.
+ * \param elem_stride: Output buffer element stride.
+ */
+ BuffersIteratorBuilder(T *output,
+ const rcti &buffer_area,
+ const rcti &iterated_area,
+ int elem_stride = 1)
+ : area_(iterated_area), is_built_(false)
+ {
+ BLI_assert(BLI_rcti_inside_rcti(&buffer_area, &iterated_area));
+ iterator_.x = iterated_area.xmin;
+ iterator_.y = iterated_area.ymin;
+ iterator_.x_start_ = iterated_area.xmin;
+ iterator_.x_end_ = iterated_area.xmax;
+
+ iterator_.out_elem_stride_ = elem_stride;
+ const int buffer_width = BLI_rcti_size_x(&buffer_area);
+ intptr_t out_row_stride = buffer_width * elem_stride;
+ iterator_.out_rows_gap_ = out_row_stride - BLI_rcti_size_x(&iterated_area) * elem_stride;
+ const int out_start_x = iterated_area.xmin - buffer_area.xmin;
+ const int out_start_y = iterated_area.ymin - buffer_area.ymin;
+ iterator_.out = output + (intptr_t)out_start_y * out_row_stride +
+ (intptr_t)out_start_x * elem_stride;
+ const T *out_row_end_ = iterator_.out +
+ (intptr_t)BLI_rcti_size_x(&iterated_area) * elem_stride;
+ iterator_.out_end_ = out_row_end_ +
+ (intptr_t)out_row_stride * (BLI_rcti_size_y(&iterated_area) - 1);
+ }
+
+ /**
+ * Create a buffers iterator builder to iterate given output buffer with no offsets.
+ */
+ BuffersIteratorBuilder(T *output, int buffer_width, int buffer_height, int elem_stride = 1)
+ : BuffersIteratorBuilder(output,
+ {0, buffer_width, 0, buffer_height},
+ {0, buffer_width, 0, buffer_height},
+ elem_stride)
+ {
+ }
+
+ /**
+ * Add an input buffer to be iterated. It must contain iterated area.
+ */
+ void add_input(const T *input, const rcti &buffer_area, int elem_stride = 1)
+ {
+ BLI_assert(!is_built_);
+ BLI_assert(BLI_rcti_inside_rcti(&buffer_area, &area_));
+ typename Iterator::In in;
+ in.elem_stride = elem_stride;
+ const int buffer_width = BLI_rcti_size_x(&buffer_area);
+ in.rows_gap = buffer_width * elem_stride - BLI_rcti_size_x(&area_) * elem_stride;
+ const int in_start_x = area_.xmin - buffer_area.xmin;
+ const int in_start_y = area_.ymin - buffer_area.ymin;
+ in.in = input + in_start_y * buffer_width * elem_stride + in_start_x * elem_stride;
+ iterator_.ins_.append(std::move(in));
+ }
+
+ /**
+ * Add an input buffer to be iterated with no offsets. It must contain iterated area.
+ */
+ void add_input(const T *input, int buffer_width, int elem_stride = 1)
+ {
+ rcti buffer_area;
+ BLI_rcti_init(&buffer_area, 0, buffer_width, 0, area_.ymax);
+ add_input(input, buffer_area, elem_stride);
+ }
+
+ /**
+ * Build the iterator.
+ */
+ BuffersIteratorBuilder::Iterator build()
+ {
+ is_built_ = true;
+ return iterator_;
+ }
+};
+
+template<typename T> using BuffersIterator = typename BuffersIteratorBuilder<T>::Iterator;
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_ConstantFolder.cc b/source/blender/compositor/intern/COM_ConstantFolder.cc
index f20324de342..15450572958 100644
--- a/source/blender/compositor/intern/COM_ConstantFolder.cc
+++ b/source/blender/compositor/intern/COM_ConstantFolder.cc
@@ -53,12 +53,12 @@ static bool is_constant_foldable(NodeOperation *operation)
return false;
}
-static Vector<NodeOperation *> find_constant_foldable_operations(Span<NodeOperation *> operations)
+static Set<NodeOperation *> find_constant_foldable_operations(Span<NodeOperation *> operations)
{
- Vector<NodeOperation *> foldable_ops;
+ Set<NodeOperation *> foldable_ops;
for (NodeOperation *op : operations) {
if (is_constant_foldable(op)) {
- foldable_ops.append(op);
+ foldable_ops.add(op);
}
}
return foldable_ops;
@@ -132,7 +132,7 @@ Vector<MemoryBuffer *> ConstantFolder::get_constant_input_buffers(NodeOperation
/** Returns constant operations resulted from folded operations. */
Vector<ConstantOperation *> ConstantFolder::try_fold_operations(Span<NodeOperation *> operations)
{
- Vector<NodeOperation *> foldable_ops = find_constant_foldable_operations(operations);
+ Set<NodeOperation *> foldable_ops = find_constant_foldable_operations(operations);
if (foldable_ops.size() == 0) {
return Vector<ConstantOperation *>();
}
diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc
index abef4517b3e..c0460aed4a4 100644
--- a/source/blender/compositor/intern/COM_Debug.cc
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -31,6 +31,8 @@ extern "C" {
#include "BKE_appdir.h"
#include "BKE_node.h"
#include "DNA_node_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
}
#include "COM_ExecutionSystem.h"
@@ -50,7 +52,7 @@ std::string DebugInfo::m_current_node_name;
std::string DebugInfo::m_current_op_name;
DebugInfo::GroupStateMap DebugInfo::m_group_states;
-static std::string operation_class_name(NodeOperation *op)
+static std::string operation_class_name(const NodeOperation *op)
{
std::string full_name = typeid(*op).name();
/* Remove name-spaces. */
@@ -452,4 +454,45 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name)
}
}
+static std::string get_operations_export_dir()
+{
+ return std::string(BKE_tempdir_session()) + "COM_operations" + SEP_STR;
+}
+
+void DebugInfo::export_operation(const NodeOperation *op, MemoryBuffer *render)
+{
+ ImBuf *ibuf = IMB_allocFromBuffer(nullptr,
+ render->getBuffer(),
+ render->getWidth(),
+ render->getHeight(),
+ render->get_num_channels());
+
+ const std::string file_name = operation_class_name(op) + "_" + std::to_string(op->get_id()) +
+ ".png";
+ const std::string path = get_operations_export_dir() + file_name;
+ BLI_make_existing_file(path.c_str());
+ IMB_saveiff(ibuf, path.c_str(), ibuf->flags);
+ IMB_freeImBuf(ibuf);
+}
+
+void DebugInfo::delete_operation_exports()
+{
+ const std::string dir = get_operations_export_dir();
+ if (BLI_exists(dir.c_str())) {
+ struct direntry *file_list;
+ int num_files = BLI_filelist_dir_contents(dir.c_str(), &file_list);
+ for (int i = 0; i < num_files; i++) {
+ direntry *file = &file_list[i];
+ const eFileAttributes file_attrs = BLI_file_attributes(file->path);
+ if (file_attrs & FILE_ATTR_ANY_LINK) {
+ continue;
+ }
+
+ if (BLI_is_file(file->path) && BLI_path_extension_check(file->path, ".png")) {
+ BLI_delete(file->path, false, false);
+ }
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_Debug.h b/source/blender/compositor/intern/COM_Debug.h
index 53461e13f48..23d99c7e529 100644
--- a/source/blender/compositor/intern/COM_Debug.h
+++ b/source/blender/compositor/intern/COM_Debug.h
@@ -30,6 +30,9 @@ namespace blender::compositor {
static constexpr bool COM_EXPORT_GRAPHVIZ = false;
static constexpr bool COM_GRAPHVIZ_SHOW_NODE_NAME = false;
+/* Saves operations results to image files. */
+static constexpr bool COM_EXPORT_OPERATION_BUFFERS = false;
+
class Node;
class ExecutionSystem;
class ExecutionGroup;
@@ -75,6 +78,9 @@ class DebugInfo {
m_group_states[execution_group] = EG_WAIT;
}
}
+ if (COM_EXPORT_OPERATION_BUFFERS) {
+ delete_operation_exports();
+ }
};
static void node_added(const Node *node)
@@ -118,6 +124,14 @@ class DebugInfo {
}
};
+ static void operation_rendered(const NodeOperation *op, MemoryBuffer *render)
+ {
+ /* Don't export constant operations as there are too many and it's rarely useful. */
+ if (COM_EXPORT_OPERATION_BUFFERS && render && !render->is_a_single_elem()) {
+ export_operation(op, render);
+ }
+ }
+
static void graphviz(const ExecutionSystem *system, StringRefNull name = "");
protected:
@@ -133,6 +147,9 @@ class DebugInfo {
const char *name, const char *color, const char *style, char *str, int maxlen);
static int graphviz_legend(char *str, int maxlen, bool has_execution_groups);
static bool graphviz_system(const ExecutionSystem *system, char *str, int maxlen);
+
+ static void export_operation(const NodeOperation *op, MemoryBuffer *render);
+ static void delete_operation_exports();
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
index 3b0a9172871..bd3a481d691 100644
--- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
@@ -20,6 +20,7 @@
#include "COM_Debug.h"
#include "COM_ExecutionGroup.h"
#include "COM_ReadBufferOperation.h"
+#include "COM_ViewerOperation.h"
#include "COM_WorkScheduler.h"
#include "BLT_translation.h"
@@ -100,8 +101,13 @@ void FullFrameExecutionModel::render_operation(NodeOperation *op)
const bool has_outputs = op->getNumberOfOutputSockets() > 0;
MemoryBuffer *op_buf = has_outputs ? create_operation_buffer(op) : nullptr;
- Span<rcti> areas = active_buffers_.get_areas_to_render(op);
- op->render(op_buf, areas, input_bufs);
+ if (op->getWidth() > 0 && op->getHeight() > 0) {
+ Span<rcti> areas = active_buffers_.get_areas_to_render(op);
+ op->render(op_buf, areas, input_bufs);
+ DebugInfo::operation_rendered(op, op_buf);
+ }
+ /* Even if operation has no resolution set the empty buffer. It will be clipped with a
+ * TranslateOperation from convert resolutions if linked to an operation with resolution. */
active_buffers_.set_rendered_buffer(op, std::unique_ptr<MemoryBuffer>(op_buf));
operation_finished(op);
@@ -117,10 +123,16 @@ void FullFrameExecutionModel::render_operations()
WorkScheduler::start(this->context_);
for (eCompositorPriority priority : priorities_) {
for (NodeOperation *op : operations_) {
- if (op->isOutputOperation(is_rendering) && op->getRenderPriority() == priority) {
+ const bool has_size = op->getWidth() > 0 && op->getHeight() > 0;
+ const bool is_priority_output = op->isOutputOperation(is_rendering) &&
+ op->getRenderPriority() == priority;
+ if (is_priority_output && has_size) {
render_output_dependencies(op);
render_operation(op);
}
+ else if (is_priority_output && !has_size && op->isActiveViewerOutput()) {
+ static_cast<ViewerOperation *>(op)->clear_display_buffer();
+ }
}
}
WorkScheduler::stop();
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc
index c7bddddd0e6..6b954072a9a 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cc
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc
@@ -129,6 +129,20 @@ void MemoryBuffer::clear()
memset(m_buffer, 0, buffer_len() * m_num_channels * sizeof(float));
}
+BuffersIterator<float> MemoryBuffer::iterate_with(Span<MemoryBuffer *> inputs)
+{
+ return iterate_with(inputs, m_rect);
+}
+
+BuffersIterator<float> MemoryBuffer::iterate_with(Span<MemoryBuffer *> inputs, const rcti &area)
+{
+ BuffersIteratorBuilder<float> builder(m_buffer, m_rect, area, elem_stride);
+ for (MemoryBuffer *input : inputs) {
+ builder.add_input(input->getBuffer(), input->get_rect(), input->elem_stride);
+ }
+ return builder.build();
+}
+
/**
* Converts a single elem buffer to a full size buffer (allocates memory for all
* elements in resolution).
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index 4ad0872b0b7..048ed4c5d6e 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -18,6 +18,9 @@
#pragma once
+#include "COM_BufferArea.h"
+#include "COM_BufferRange.h"
+#include "COM_BuffersIterator.h"
#include "COM_ExecutionGroup.h"
#include "COM_MemoryProxy.h"
@@ -239,6 +242,32 @@ class MemoryBuffer {
}
/**
+ * Get all buffer elements as a range with no offsets.
+ */
+ BufferRange<float> as_range()
+ {
+ return BufferRange<float>(m_buffer, 0, buffer_len(), elem_stride);
+ }
+
+ BufferRange<const float> as_range() const
+ {
+ return BufferRange<const float>(m_buffer, 0, buffer_len(), elem_stride);
+ }
+
+ BufferArea<float> get_buffer_area(const rcti &area)
+ {
+ return BufferArea<float>(m_buffer, getWidth(), area, elem_stride);
+ }
+
+ BufferArea<const float> get_buffer_area(const rcti &area) const
+ {
+ return BufferArea<const float>(m_buffer, getWidth(), area, elem_stride);
+ }
+
+ BuffersIterator<float> iterate_with(Span<MemoryBuffer *> inputs);
+ BuffersIterator<float> iterate_with(Span<MemoryBuffer *> inputs, const rcti &area);
+
+ /**
* \brief get the data of this MemoryBuffer
* \note buffer should already be available in memory
*/
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cc b/source/blender/compositor/nodes/COM_RenderLayersNode.cc
index 253ca542c04..6744e98ecdb 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.cc
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cc
@@ -143,7 +143,7 @@ void RenderLayersNode::missingSocketLink(NodeConverter &converter, NodeOutput *o
break;
}
default: {
- BLI_assert("!Unexpected data type");
+ BLI_assert_msg(0, "Unexpected data type");
return;
}
}
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cc b/source/blender/compositor/operations/COM_BrightnessOperation.cc
index 92cab47318a..7878eca2bbd 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.cc
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.cc
@@ -28,6 +28,7 @@ BrightnessOperation::BrightnessOperation()
this->addOutputSocket(DataType::Color);
this->m_inputProgram = nullptr;
this->m_use_premultiply = false;
+ flags.can_be_constant = true;
}
void BrightnessOperation::setUsePremultiply(bool use_premultiply)
@@ -85,6 +86,50 @@ void BrightnessOperation::executePixelSampled(float output[4],
}
}
+void BrightnessOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ float tmp_color[4];
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ const float *in_color = it.in(0);
+ const float brightness = *it.in(1) / 100.0f;
+ const float contrast = *it.in(2);
+ float delta = contrast / 200.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ float a, b;
+ if (contrast > 0) {
+ a = 1.0f - delta * 2.0f;
+ a = 1.0f / max_ff(a, FLT_EPSILON);
+ b = a * (brightness - delta);
+ }
+ else {
+ delta *= -1;
+ a = max_ff(1.0f - delta * 2.0f, 0.0f);
+ b = a * brightness + delta;
+ }
+ const float *color;
+ if (this->m_use_premultiply) {
+ premul_to_straight_v4_v4(tmp_color, in_color);
+ color = tmp_color;
+ }
+ else {
+ color = in_color;
+ }
+ it.out[0] = a * color[0] + b;
+ it.out[1] = a * color[1] + b;
+ it.out[2] = a * color[2] + b;
+ it.out[3] = color[3];
+ if (this->m_use_premultiply) {
+ straight_to_premul_v4(it.out);
+ }
+ }
+}
+
void BrightnessOperation::deinitExecution()
{
this->m_inputProgram = nullptr;
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.h b/source/blender/compositor/operations/COM_BrightnessOperation.h
index 7c33e0b35ec..64b4fa0dbe2 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.h
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class BrightnessOperation : public NodeOperation {
+class BrightnessOperation : public MultiThreadedOperation {
private:
/**
* Cached reference to the inputProgram
@@ -52,6 +52,10 @@ class BrightnessOperation : public NodeOperation {
void deinitExecution() override;
void setUsePremultiply(bool use_premultiply);
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
index c4099a6d33d..55ae19ad194 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
@@ -25,7 +25,7 @@
namespace blender::compositor {
-// this part has been copied from the double edge mask
+/* This part has been copied from the double edge mask. */
static void do_adjacentKeepBorders(unsigned int t,
unsigned int rw,
const unsigned int *limask,
@@ -35,163 +35,163 @@ static void do_adjacentKeepBorders(unsigned int t,
unsigned int *rsize)
{
int x;
- unsigned int isz = 0; // inner edge size
- unsigned int osz = 0; // outer edge size
- unsigned int gsz = 0; // gradient fill area size
+ unsigned int isz = 0; /* Inner edge size. */
+ unsigned int osz = 0; /* Outer edge size. */
+ unsigned int gsz = 0; /* Gradient fill area size. */
/* Test the four corners */
- /* upper left corner */
+ /* Upper left corner. */
x = t - rw + 1;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel underneath, or to the right, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel underneath, or to the right, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + 1] && lomask[x + 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
- /* upper right corner */
+ /* Upper right corner. */
x = t;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel underneath, or to the left, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel underneath, or to the left, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x - 1] && lomask[x - 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
- /* lower left corner */
+ /* Lower left corner. */
x = 0;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel above, or to the right, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel above, or to the right, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x + 1] && lomask[x + 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
- /* lower right corner */
+ /* Lower right corner. */
x = rw - 1;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel above, or to the left, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel above, or to the left, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x - 1] && lomask[x - 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
/* Test the TOP row of pixels in buffer, except corners */
for (x = t - 1; x >= (t - rw) + 2; x--) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel to the right, or to the left, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel to the right, or to the left, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
}
/* Test the BOTTOM row of pixels in buffer, except corners */
for (x = rw - 2; x; x--) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel to the right, or to the left, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel to the right, or to the left, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
}
/* Test the LEFT edge of pixels in buffer, except corners */
for (x = t - (rw << 1) + 1; x >= rw; x -= rw) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel underneath, or above, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel underneath, or above, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
}
/* Test the RIGHT edge of pixels in buffer, except corners */
for (x = t - rw; x > rw; x -= rw) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel underneath, or above, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel underneath, or above, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
}
- rsize[0] = isz; // fill in our return sizes for edges + fill
+ rsize[0] = isz; /* Fill in our return sizes for edges + fill. */
rsize[1] = osz;
rsize[2] = gsz;
}
@@ -205,214 +205,218 @@ static void do_adjacentBleedBorders(unsigned int t,
unsigned int *rsize)
{
int x;
- unsigned int isz = 0; // inner edge size
- unsigned int osz = 0; // outer edge size
- unsigned int gsz = 0; // gradient fill area size
+ unsigned int isz = 0; /* Inner edge size. */
+ unsigned int osz = 0; /* Outer edge size. */
+ unsigned int gsz = 0; /* Gradient fill area size. */
/* Test the four corners */
- /* upper left corner */
+ /* Upper left corner. */
x = t - rw + 1;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel underneath, or to the right, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel underneath, or to the right, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + 1] && lomask[x + 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
if (!lomask[x - rw] ||
- !lomask[x + 1]) { // test if outer mask is empty underneath or to the right
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ !lomask[x + 1]) { /* Test if outer mask is empty underneath or to the right. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
- /* upper right corner */
+ /* Upper right corner. */
x = t;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel underneath, or to the left, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel underneath, or to the left, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x - 1] && lomask[x - 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
if (!lomask[x - rw] ||
- !lomask[x - 1]) { // test if outer mask is empty underneath or to the left
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ !lomask[x - 1]) { /* Test if outer mask is empty underneath or to the left. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
- /* lower left corner */
+ /* Lower left corner. */
x = 0;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel above, or to the right, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel above, or to the right, are empty in the inner mask,
+ * But filled in the outer mask. */
if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x + 1] && lomask[x + 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- if (!lomask[x + rw] || !lomask[x + 1]) { // test if outer mask is empty above or to the right
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ if (!lomask[x + rw] ||
+ !lomask[x + 1]) { /* Test if outer mask is empty above or to the right. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
- /* lower right corner */
+ /* Lower right corner. */
x = rw - 1;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel above, or to the left, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel above, or to the left, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x - 1] && lomask[x - 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- if (!lomask[x + rw] || !lomask[x - 1]) { // test if outer mask is empty above or to the left
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ if (!lomask[x + rw] ||
+ !lomask[x - 1]) { /* Test if outer mask is empty above or to the left. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
/* Test the TOP row of pixels in buffer, except corners */
for (x = t - 1; x >= (t - rw) + 2; x--) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel to the left, or to the right, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel to the left, or to the right, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
if (!lomask[x - 1] ||
- !lomask[x + 1]) { // test if outer mask is empty to the left or to the right
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ !lomask[x + 1]) { /* Test if outer mask is empty to the left or to the right. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
}
/* Test the BOTTOM row of pixels in buffer, except corners */
for (x = rw - 2; x; x--) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel to the left, or to the right, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel to the left, or to the right, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
if (!lomask[x - 1] ||
- !lomask[x + 1]) { // test if outer mask is empty to the left or to the right
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ !lomask[x + 1]) { /* Test if outer mask is empty to the left or to the right. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
}
/* Test the LEFT edge of pixels in buffer, except corners */
for (x = t - (rw << 1) + 1; x >= rw; x -= rw) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel underneath, or above, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel underneath, or above, are empty in the inner mask,
+ * but filled in the outer mask. */
if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ if (!lomask[x - rw] ||
+ !lomask[x + rw]) { /* Test if outer mask is empty underneath or above. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
}
/* Test the RIGHT edge of pixels in buffer, except corners */
for (x = t - rw; x > rw; x -= rw) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if pixel underneath, or above, are empty in the inner mask,
- // but filled in the outer mask
+ /* Test if pixel underneath, or above, are empty in the inner mask,
+ * But filled in the outer mask. */
if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ if (!lomask[x - rw] ||
+ !lomask[x + rw]) { /* Test if outer mask is empty underneath or above. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
}
- rsize[0] = isz; // fill in our return sizes for edges + fill
+ rsize[0] = isz; /* Fill in our return sizes for edges + fill. */
rsize[1] = osz;
rsize[2] = gsz;
}
@@ -426,155 +430,155 @@ static void do_allKeepBorders(unsigned int t,
unsigned int *rsize)
{
int x;
- unsigned int isz = 0; // inner edge size
- unsigned int osz = 0; // outer edge size
- unsigned int gsz = 0; // gradient fill area size
- /* Test the four corners */
- /* upper left corner */
+ unsigned int isz = 0; /* Inner edge size. */
+ unsigned int osz = 0; /* Outer edge size. */
+ unsigned int gsz = 0; /* Gradient fill area size. */
+ /* Test the four corners. */
+ /* Upper left corner. */
x = t - rw + 1;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if the inner mask is empty underneath or to the right
+ /* Test if the inner mask is empty underneath or to the right. */
if (!limask[x - rw] || !limask[x + 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
- /* upper right corner */
+ /* Upper right corner. */
x = t;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if the inner mask is empty underneath or to the left
+ /* Test if the inner mask is empty underneath or to the left. */
if (!limask[x - rw] || !limask[x - 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
- /* lower left corner */
+ /* Lower left corner. */
x = 0;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty above or to the right
+ /* Test if inner mask is empty above or to the right. */
if (!limask[x + rw] || !limask[x + 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
- /* lower right corner */
+ /* Lower right corner. */
x = rw - 1;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty above or to the left
+ /* Test if inner mask is empty above or to the left. */
if (!limask[x + rw] || !limask[x - 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
/* Test the TOP row of pixels in buffer, except corners */
for (x = t - 1; x >= (t - rw) + 2; x--) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty to the left or to the right
+ /* Test if inner mask is empty to the left or to the right. */
if (!limask[x - 1] || !limask[x + 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
}
/* Test the BOTTOM row of pixels in buffer, except corners */
for (x = rw - 2; x; x--) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty to the left or to the right
+ /* Test if inner mask is empty to the left or to the right. */
if (!limask[x - 1] || !limask[x + 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
}
/* Test the LEFT edge of pixels in buffer, except corners */
for (x = t - (rw << 1) + 1; x >= rw; x -= rw) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty underneath or above
+ /* Test if inner mask is empty underneath or above. */
if (!limask[x - rw] || !limask[x + rw]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
}
/* Test the RIGHT edge of pixels in buffer, except corners */
for (x = t - rw; x > rw; x -= rw) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty underneath or above
+ /* Test if inner mask is empty underneath or above. */
if (!limask[x - rw] || !limask[x + rw]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
}
- rsize[0] = isz; // fill in our return sizes for edges + fill
+ rsize[0] = isz; /* Fill in our return sizes for edges + fill. */
rsize[1] = osz;
rsize[2] = gsz;
}
@@ -588,207 +592,210 @@ static void do_allBleedBorders(unsigned int t,
unsigned int *rsize)
{
int x;
- unsigned int isz = 0; // inner edge size
- unsigned int osz = 0; // outer edge size
- unsigned int gsz = 0; // gradient fill area size
+ unsigned int isz = 0; /* Inner edge size. */
+ unsigned int osz = 0; /* Outer edge size. */
+ unsigned int gsz = 0; /* Gradient fill area size. */
/* Test the four corners */
- /* upper left corner */
+ /* Upper left corner. */
x = t - rw + 1;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if the inner mask is empty underneath or to the right
+ /* Test if the inner mask is empty underneath or to the right. */
if (!limask[x - rw] || !limask[x + 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
if (!lomask[x - rw] ||
- !lomask[x + 1]) { // test if outer mask is empty underneath or to the right
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ !lomask[x + 1]) { /* Test if outer mask is empty underneath or to the right. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
- /* upper right corner */
+ /* Upper right corner. */
x = t;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if the inner mask is empty underneath or to the left
+ /* Test if the inner mask is empty underneath or to the left. */
if (!limask[x - rw] || !limask[x - 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- if (!lomask[x - rw] || !lomask[x - 1]) { // test if outer mask is empty above or to the left
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ if (!lomask[x - rw] ||
+ !lomask[x - 1]) { /* Test if outer mask is empty above or to the left. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
- /* lower left corner */
+ /* Lower left corner. */
x = 0;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty above or to the right
+ /* Test if inner mask is empty above or to the right. */
if (!limask[x + rw] || !limask[x + 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
if (!lomask[x + rw] ||
- !lomask[x + 1]) { // test if outer mask is empty underneath or to the right
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ !lomask[x + 1]) { /* Test if outer mask is empty underneath or to the right. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
- /* lower right corner */
+ /* Lower right corner. */
x = rw - 1;
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty above or to the left
+ /* Test if inner mask is empty above or to the left. */
if (!limask[x + rw] || !limask[x - 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
if (!lomask[x + rw] ||
- !lomask[x - 1]) { // test if outer mask is empty underneath or to the left
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ !lomask[x - 1]) { /* Test if outer mask is empty underneath or to the left. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
/* Test the TOP row of pixels in buffer, except corners */
for (x = t - 1; x >= (t - rw) + 2; x--) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty to the left or to the right
+ /* Test if inner mask is empty to the left or to the right. */
if (!limask[x - 1] || !limask[x + 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
if (!lomask[x - 1] ||
- !lomask[x + 1]) { // test if outer mask is empty to the left or to the right
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ !lomask[x + 1]) { /* Test if outer mask is empty to the left or to the right. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
}
/* Test the BOTTOM row of pixels in buffer, except corners */
for (x = rw - 2; x; x--) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty to the left or to the right
+ /* Test if inner mask is empty to the left or to the right. */
if (!limask[x - 1] || !limask[x + 1]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
if (!lomask[x - 1] ||
- !lomask[x + 1]) { // test if outer mask is empty to the left or to the right
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ !lomask[x + 1]) { /* Test if outer mask is empty to the left or to the right. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
}
/* Test the LEFT edge of pixels in buffer, except corners */
for (x = t - (rw << 1) + 1; x >= rw; x -= rw) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty underneath or above
+ /* Test if inner mask is empty underneath or above. */
if (!limask[x - rw] || !limask[x + rw]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ if (!lomask[x - rw] ||
+ !lomask[x + rw]) { /* Test if outer mask is empty underneath or above. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
}
/* Test the RIGHT edge of pixels in buffer, except corners */
for (x = t - rw; x > rw; x -= rw) {
- // test if inner mask is filled
+ /* Test if inner mask is filled. */
if (limask[x]) {
- // test if inner mask is empty underneath or above
+ /* Test if inner mask is empty underneath or above. */
if (!limask[x - rw] || !limask[x + rw]) {
- isz++; // increment inner edge size
- lres[x] = 4; // flag pixel as inner edge
+ isz++; /* Increment inner edge size. */
+ lres[x] = 4; /* Flag pixel as inner edge. */
}
else {
- res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge
+ res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */
}
}
- else if (lomask[x]) { // inner mask was empty, test if outer mask is filled
- if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above
- osz++; // increment outer edge size
- lres[x] = 3; // flag pixel as outer edge
+ else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */
+ if (!lomask[x - rw] ||
+ !lomask[x + rw]) { /* Test if outer mask is empty underneath or above. */
+ osz++; /* Increment outer edge size. */
+ lres[x] = 3; /* Flag pixel as outer edge. */
}
else {
- gsz++; // increment the gradient pixel count
- lres[x] = 2; // flag pixel as gradient
+ gsz++; /* Increment the gradient pixel count. */
+ lres[x] = 2; /* Flag pixel as gradient. */
}
}
}
- rsize[0] = isz; // fill in our return sizes for edges + fill
+ rsize[0] = isz; /* Fill in our return sizes for edges + fill. */
rsize[1] = osz;
rsize[2] = gsz;
}
@@ -804,13 +811,14 @@ static void do_allEdgeDetection(unsigned int t,
unsigned int in_osz,
unsigned int in_gsz)
{
- int x; // x = pixel loop counter
- int a; // a = pixel loop counter
- int dx; // dx = delta x
- int pix_prevRow; // pix_prevRow = pixel one row behind the one we are testing in a loop
- int pix_nextRow; // pix_nextRow = pixel one row in front of the one we are testing in a loop
- int pix_prevCol; // pix_prevCol = pixel one column behind the one we are testing in a loop
- int pix_nextCol; // pix_nextCol = pixel one column in front of the one we are testing in a loop
+ int x; /* Pixel loop counter. */
+ int a; /* Pixel loop counter. */
+ int dx; /* Delta x. */
+ int pix_prevRow; /* Pixel one row behind the one we are testing in a loop. */
+ int pix_nextRow; /* Pixel one row in front of the one we are testing in a loop. */
+ int pix_prevCol; /* Pixel one column behind the one we are testing in a loop. */
+ int pix_nextCol; /* Pixel one column in front of the one we are testing in a loop. */
+
/* Test all rows between the FIRST and LAST rows, excluding left and right edges */
for (x = (t - rw) + 1, dx = x - (rw - 2); dx > rw; x -= rw, dx -= rw) {
a = x - 2;
@@ -819,8 +827,8 @@ static void do_allEdgeDetection(unsigned int t,
pix_prevCol = a + 1;
pix_nextCol = a - 1;
while (a > dx - 2) {
- if (!limask[a]) { // if the inner mask is empty
- if (lomask[a]) { // if the outer mask is full
+ if (!limask[a]) { /* If the inner mask is empty. */
+ if (lomask[a]) { /* If the outer mask is full. */
/*
* Next we test all 4 directions around the current pixel: next/prev/up/down
* The test ensures that the outer mask is empty and that the inner mask
@@ -831,23 +839,23 @@ static void do_allEdgeDetection(unsigned int t,
(!lomask[pix_prevCol] && !limask[pix_prevCol]) ||
(!lomask[pix_nextRow] && !limask[pix_nextRow]) ||
(!lomask[pix_prevRow] && !limask[pix_prevRow])) {
- in_osz++; // increment the outer boundary pixel count
- lres[a] = 3; // flag pixel as part of outer edge
+ in_osz++; /* Increment the outer boundary pixel count. */
+ lres[a] = 3; /* Flag pixel as part of outer edge. */
}
- else { // it's not a boundary pixel, but it is a gradient pixel
- in_gsz++; // increment the gradient pixel count
- lres[a] = 2; // flag pixel as gradient
+ else { /* It's not a boundary pixel, but it is a gradient pixel. */
+ in_gsz++; /* Increment the gradient pixel count. */
+ lres[a] = 2; /* Flag pixel as gradient. */
}
}
}
else {
if (!limask[pix_nextCol] || !limask[pix_prevCol] || !limask[pix_nextRow] ||
!limask[pix_prevRow]) {
- in_isz++; // increment the inner boundary pixel count
- lres[a] = 4; // flag pixel as part of inner edge
+ in_isz++; /* Increment the inner boundary pixel count. */
+ lres[a] = 4; /* Flag pixel as part of inner edge. */
}
else {
- res[a] = 1.0f; // pixel is part of inner mask, but not at an edge
+ res[a] = 1.0f; /* Pixel is part of inner mask, but not at an edge. */
}
}
a--;
@@ -858,7 +866,7 @@ static void do_allEdgeDetection(unsigned int t,
}
}
- rsize[0] = in_isz; // fill in our return sizes for edges + fill
+ rsize[0] = in_isz; /* Fill in our return sizes for edges + fill. */
rsize[1] = in_osz;
rsize[2] = in_gsz;
}
@@ -874,13 +882,13 @@ static void do_adjacentEdgeDetection(unsigned int t,
unsigned int in_osz,
unsigned int in_gsz)
{
- int x; // x = pixel loop counter
- int a; // a = pixel loop counter
- int dx; // dx = delta x
- int pix_prevRow; // pix_prevRow = pixel one row behind the one we are testing in a loop
- int pix_nextRow; // pix_nextRow = pixel one row in front of the one we are testing in a loop
- int pix_prevCol; // pix_prevCol = pixel one column behind the one we are testing in a loop
- int pix_nextCol; // pix_nextCol = pixel one column in front of the one we are testing in a loop
+ int x; /* Pixel loop counter. */
+ int a; /* Pixel loop counter. */
+ int dx; /* Delta x. */
+ int pix_prevRow; /* Pixel one row behind the one we are testing in a loop. */
+ int pix_nextRow; /* Pixel one row in front of the one we are testing in a loop. */
+ int pix_prevCol; /* Pixel one column behind the one we are testing in a loop. */
+ int pix_nextCol; /* Pixel one column in front of the one we are testing in a loop. */
/* Test all rows between the FIRST and LAST rows, excluding left and right edges */
for (x = (t - rw) + 1, dx = x - (rw - 2); dx > rw; x -= rw, dx -= rw) {
a = x - 2;
@@ -889,8 +897,8 @@ static void do_adjacentEdgeDetection(unsigned int t,
pix_prevCol = a + 1;
pix_nextCol = a - 1;
while (a > dx - 2) {
- if (!limask[a]) { // if the inner mask is empty
- if (lomask[a]) { // if the outer mask is full
+ if (!limask[a]) { /* If the inner mask is empty. */
+ if (lomask[a]) { /* If the outer mask is full. */
/*
* Next we test all 4 directions around the current pixel: next/prev/up/down
* The test ensures that the outer mask is empty and that the inner mask
@@ -901,12 +909,12 @@ static void do_adjacentEdgeDetection(unsigned int t,
(!lomask[pix_prevCol] && !limask[pix_prevCol]) ||
(!lomask[pix_nextRow] && !limask[pix_nextRow]) ||
(!lomask[pix_prevRow] && !limask[pix_prevRow])) {
- in_osz++; // increment the outer boundary pixel count
- lres[a] = 3; // flag pixel as part of outer edge
+ in_osz++; /* Increment the outer boundary pixel count. */
+ lres[a] = 3; /* Flag pixel as part of outer edge. */
}
- else { // it's not a boundary pixel, but it is a gradient pixel
- in_gsz++; // increment the gradient pixel count
- lres[a] = 2; // flag pixel as gradient
+ else { /* It's not a boundary pixel, but it is a gradient pixel. */
+ in_gsz++; /* Increment the gradient pixel count. */
+ lres[a] = 2; /* Flag pixel as gradient. */
}
}
}
@@ -915,22 +923,22 @@ static void do_adjacentEdgeDetection(unsigned int t,
(!limask[pix_prevCol] && lomask[pix_prevCol]) ||
(!limask[pix_nextRow] && lomask[pix_nextRow]) ||
(!limask[pix_prevRow] && lomask[pix_prevRow])) {
- in_isz++; // increment the inner boundary pixel count
- lres[a] = 4; // flag pixel as part of inner edge
+ in_isz++; /* Increment the inner boundary pixel count. */
+ lres[a] = 4; /* Flag pixel as part of inner edge. */
}
else {
- res[a] = 1.0f; // pixel is part of inner mask, but not at an edge
+ res[a] = 1.0f; /* Pixel is part of inner mask, but not at an edge. */
}
}
a--;
- pix_prevRow--; // advance all four "surrounding" pixel pointers
+ pix_prevRow--; /* Advance all four "surrounding" pixel pointers. */
pix_nextRow--;
pix_prevCol--;
pix_nextCol--;
}
}
- rsize[0] = in_isz; // fill in our return sizes for edges + fill
+ rsize[0] = in_isz; /* Fill in our return sizes for edges + fill. */
rsize[1] = in_osz;
rsize[2] = in_gsz;
}
@@ -945,12 +953,12 @@ static void do_createEdgeLocationBuffer(unsigned int t,
unsigned int isz,
unsigned int gsz)
{
- int x; // x = pixel loop counter
- int a; // a = temporary pixel index buffer loop counter
- unsigned int ud; // ud = unscaled edge distance
- unsigned int dmin; // dmin = minimum edge distance
+ int x; /* Pixel loop counter. */
+ int a; /* Temporary pixel index buffer loop counter. */
+ unsigned int ud; /* Unscaled edge distance. */
+ unsigned int dmin; /* Minimum edge distance. */
- unsigned int rsl; // long used for finding fast 1.0/sqrt
+ unsigned int rsl; /* Long used for finding fast `1.0/sqrt`. */
unsigned int gradientFillOffset;
/* For looping inner edge pixel indexes, represents current position from offset. */
@@ -980,11 +988,11 @@ static void do_createEdgeLocationBuffer(unsigned int t,
*
* Example: 9 by 9 pixel block
*
- * . = pixel non-white in both outer and inner mask
- * o = pixel white in outer, but not inner mask, adjacent to "." pixel
- * g = pixel white in outer, but not inner mask, not adjacent to "." pixel
- * i = pixel white in inner mask, adjacent to "g" or "." pixel
- * F = pixel white in inner mask, only adjacent to other pixels white in the inner mask
+ * `.` = Pixel non-white in both outer and inner mask.
+ * `o` = Pixel white in outer, but not inner mask, adjacent to "." pixel.
+ * `g` = Pixel white in outer, but not inner mask, not adjacent to "." pixel.
+ * `i` = Pixel white in inner mask, adjacent to "g" or "." pixel.
+ * `F` = Pixel white in inner mask, only adjacent to other pixels white in the inner mask.
*
*
* ......... <----- pixel #80
@@ -1025,36 +1033,37 @@ static void do_createEdgeLocationBuffer(unsigned int t,
*/
/* clang-format on */
- gradientFillOffset = 0; // since there are likely "more" of these, put it first. :)
- *innerEdgeOffset = gradientFillOffset + gsz; // set start of inner edge indexes
- *outerEdgeOffset = (*innerEdgeOffset) + isz; // set start of outer edge indexes
- /* set the accumulators to correct positions */ // set up some accumulator variables for loops
- gradientAccum = gradientFillOffset; // each accumulator variable starts at its respective
- innerAccum = *innerEdgeOffset; // section's offset so when we start filling, each
- outerAccum = *outerEdgeOffset; // section fills up its allocated space in gbuf
- // uses dmin=row, rsl=col
+ gradientFillOffset = 0; /* Since there are likely "more" of these, put it first. :). */
+ *innerEdgeOffset = gradientFillOffset + gsz; /* Set start of inner edge indexes. */
+ *outerEdgeOffset = (*innerEdgeOffset) + isz; /* Set start of outer edge indexes. */
+ /* Set the accumulators to correct positions */ /* Set up some accumulator variables for loops.
+ */
+ gradientAccum = gradientFillOffset; /* Each accumulator variable starts at its respective. */
+ innerAccum = *innerEdgeOffset; /* Section's offset so when we start filling, each. */
+ outerAccum = *outerEdgeOffset; /* Section fills up its allocated space in gbuf. */
+ /* Uses `dmin=row`, `rsl=col`. */
for (x = 0, dmin = 0; x < t; x += rw, dmin++) {
for (rsl = 0; rsl < rw; rsl++) {
a = x + rsl;
- if (lres[a] == 2) { // it is a gradient pixel flagged by 2
- ud = gradientAccum << 1; // double the index to reach correct unsigned short location
- gbuf[ud] = dmin; // insert pixel's row into gradient pixel location buffer
- gbuf[ud + 1] = rsl; // insert pixel's column into gradient pixel location buffer
- gradientAccum++; // increment gradient index buffer pointer
+ if (lres[a] == 2) { /* It is a gradient pixel flagged by 2. */
+ ud = gradientAccum << 1; /* Double the index to reach correct unsigned short location. */
+ gbuf[ud] = dmin; /* Insert pixel's row into gradient pixel location buffer. */
+ gbuf[ud + 1] = rsl; /* Insert pixel's column into gradient pixel location buffer. */
+ gradientAccum++; /* Increment gradient index buffer pointer. */
}
- else if (lres[a] == 3) { // it is an outer edge pixel flagged by 3
- ud = outerAccum << 1; // double the index to reach correct unsigned short location
- gbuf[ud] = dmin; // insert pixel's row into outer edge pixel location buffer
- gbuf[ud + 1] = rsl; // insert pixel's column into outer edge pixel location buffer
- outerAccum++; // increment outer edge index buffer pointer
- res[a] = 0.0f; // set output pixel intensity now since it won't change later
+ else if (lres[a] == 3) { /* It is an outer edge pixel flagged by 3. */
+ ud = outerAccum << 1; /* Double the index to reach correct unsigned short location. */
+ gbuf[ud] = dmin; /* Insert pixel's row into outer edge pixel location buffer. */
+ gbuf[ud + 1] = rsl; /* Insert pixel's column into outer edge pixel location buffer. */
+ outerAccum++; /* Increment outer edge index buffer pointer. */
+ res[a] = 0.0f; /* Set output pixel intensity now since it won't change later. */
}
- else if (lres[a] == 4) { // it is an inner edge pixel flagged by 4
- ud = innerAccum << 1; // double int index to reach correct unsigned short location
- gbuf[ud] = dmin; // insert pixel's row into inner edge pixel location buffer
- gbuf[ud + 1] = rsl; // insert pixel's column into inner edge pixel location buffer
- innerAccum++; // increment inner edge index buffer pointer
- res[a] = 1.0f; // set output pixel intensity now since it won't change later
+ else if (lres[a] == 4) { /* It is an inner edge pixel flagged by 4. */
+ ud = innerAccum << 1; /* Double int index to reach correct unsigned short location. */
+ gbuf[ud] = dmin; /* Insert pixel's row into inner edge pixel location buffer. */
+ gbuf[ud + 1] = rsl; /* Insert pixel's column into inner edge pixel location buffer. */
+ innerAccum++; /* Increment inner edge index buffer pointer. */
+ res[a] = 1.0f; /* Set output pixel intensity now since it won't change later. */
}
}
}
@@ -1069,21 +1078,21 @@ static void do_fillGradientBuffer(unsigned int rw,
unsigned int innerEdgeOffset,
unsigned int outerEdgeOffset)
{
- int x; // x = pixel loop counter
- int a; // a = temporary pixel index buffer loop counter
- int fsz; // size of the frame
- unsigned int rsl; // long used for finding fast 1.0/sqrt
- float rsf; // float used for finding fast 1.0/sqrt
- const float rsopf = 1.5f; // constant float used for finding fast 1.0/sqrt
+ int x; /* Pixel loop counter. */
+ int a; /* Temporary pixel index buffer loop counter. */
+ int fsz; /* Size of the frame. */
+ unsigned int rsl; /* Long used for finding fast `1.0/sqrt`. */
+ float rsf; /* Float used for finding fast `1.0/sqrt`. */
+ const float rsopf = 1.5f; /* Constant float used for finding fast `1.0/sqrt`. */
unsigned int gradientFillOffset;
unsigned int t;
- unsigned int ud; // ud = unscaled edge distance
- unsigned int dmin; // dmin = minimum edge distance
- float odist; // odist = current outer edge distance
- float idist; // idist = current inner edge distance
- int dx; // dx = X-delta (used for distance proportion calculation)
- int dy; // dy = Y-delta (used for distance proportion calculation)
+ unsigned int ud; /* Unscaled edge distance. */
+ unsigned int dmin; /* Minimum edge distance. */
+ float odist; /* Current outer edge distance. */
+ float idist; /* Current inner edge distance. */
+ int dx; /* X-delta (used for distance proportion calculation) */
+ int dy; /* Y-delta (used for distance proportion calculation) */
/*
* The general algorithm used to color each gradient pixel is:
@@ -1099,9 +1108,9 @@ static void do_fillGradientBuffer(unsigned int rw,
* outside edge.
*
* In an image where:
- * . = blank (black) pixels, not covered by inner mask or outer mask
- * + = desired gradient pixels, covered only by outer mask
- * * = white full mask pixels, covered by at least inner mask
+ * `.` = Blank (black) pixels, not covered by inner mask or outer mask.
+ * `+` = Desired gradient pixels, covered only by outer mask.
+ * `*` = White full mask pixels, covered by at least inner mask.
*
* ...............................
* ...............+++++++++++.....
@@ -1146,92 +1155,95 @@ static void do_fillGradientBuffer(unsigned int rw,
for (x = gsz - 1; x >= 0; x--) {
gradientFillOffset = x << 1;
- t = gbuf[gradientFillOffset]; // calculate column of pixel indexed by gbuf[x]
- fsz = gbuf[gradientFillOffset + 1]; // calculate row of pixel indexed by gbuf[x]
- dmin = 0xffffffff; // reset min distance to edge pixel
+ t = gbuf[gradientFillOffset]; /* Calculate column of pixel indexed by `gbuf[x]`. */
+ fsz = gbuf[gradientFillOffset + 1]; /* Calculate row of pixel indexed by `gbuf[x]`. */
+ dmin = 0xffffffff; /* Reset min distance to edge pixel. */
for (a = outerEdgeOffset + osz - 1; a >= outerEdgeOffset;
- a--) { // loop through all outer edge buffer pixels
+ a--) { /* Loop through all outer edge buffer pixels. */
ud = a << 1;
- dy = t - gbuf[ud]; // set dx to gradient pixel column - outer edge pixel row
- dx = fsz - gbuf[ud + 1]; // set dy to gradient pixel row - outer edge pixel column
- ud = dx * dx + dy * dy; // compute sum of squares
- if (ud < dmin) { // if our new sum of squares is less than the current minimum
- dmin = ud; // set a new minimum equal to the new lower value
+ dy = t - gbuf[ud]; /* Set dx to gradient pixel column - outer edge pixel row. */
+ dx = fsz - gbuf[ud + 1]; /* Set dy to gradient pixel row - outer edge pixel column. */
+ ud = dx * dx + dy * dy; /* Compute sum of squares. */
+ if (ud < dmin) { /* If our new sum of squares is less than the current minimum. */
+ dmin = ud; /* Set a new minimum equal to the new lower value. */
}
}
- odist = (float)(dmin); // cast outer min to a float
- rsf = odist * 0.5f; //
- rsl = *(unsigned int *)&odist; // use some peculiar properties of the way bits are stored
- rsl = 0x5f3759df - (rsl >> 1); // in floats vs. unsigned ints to compute an approximate
- odist = *(float *)&rsl; // reciprocal square root
+ odist = (float)(dmin); /* Cast outer min to a float. */
+ rsf = odist * 0.5f;
+ rsl = *(unsigned int *)&odist; /* Use some peculiar properties of the way bits are stored. */
+ rsl = 0x5f3759df - (rsl >> 1); /* In floats vs. unsigned ints to compute an approximate. */
+ odist = *(float *)&rsl; /* Reciprocal square root. */
odist = odist * (rsopf - (rsf * odist *
- odist)); // -- ** this line can be iterated for more accuracy ** --
- dmin = 0xffffffff; // reset min distance to edge pixel
+ odist)); /* -- This line can be iterated for more accuracy. -- */
+ dmin = 0xffffffff; /* Reset min distance to edge pixel. */
for (a = innerEdgeOffset + isz - 1; a >= innerEdgeOffset;
- a--) { // loop through all inside edge pixels
+ a--) { /* Loop through all inside edge pixels. */
ud = a << 1;
- dy = t - gbuf[ud]; // compute delta in Y from gradient pixel to inside edge pixel
- dx = fsz - gbuf[ud + 1]; // compute delta in X from gradient pixel to inside edge pixel
- ud = dx * dx + dy * dy; // compute sum of squares
- if (ud < dmin) { // if our new sum of squares is less than the current minimum we've found
- dmin = ud; // set a new minimum equal to the new lower value
+ dy = t - gbuf[ud]; /* Compute delta in Y from gradient pixel to inside edge pixel. */
+ dx = fsz - gbuf[ud + 1]; /* Compute delta in X from gradient pixel to inside edge pixel. */
+ ud = dx * dx + dy * dy; /* Compute sum of squares. */
+ if (ud <
+ dmin) { /* If our new sum of squares is less than the current minimum we've found. */
+ dmin = ud; /* Set a new minimum equal to the new lower value. */
}
}
- idist = (float)(dmin); // cast inner min to a float
- rsf = idist * 0.5f; //
- rsl = *(unsigned int *)&idist; //
- rsl = 0x5f3759df - (rsl >> 1); // see notes above
- idist = *(float *)&rsl; //
- idist = idist * (rsopf - (rsf * idist * idist)); //
- /*
- * Note once again that since we are using reciprocals of distance values our
+
+ /* Cast inner min to a float. */
+ idist = (float)(dmin);
+ rsf = idist * 0.5f;
+ rsl = *(unsigned int *)&idist;
+
+ /* See notes above. */
+ rsl = 0x5f3759df - (rsl >> 1);
+ idist = *(float *)&rsl;
+ idist = idist * (rsopf - (rsf * idist * idist));
+
+ /* NOTE: once again that since we are using reciprocals of distance values our
* proportion is already the correct intensity, and does not need to be
- * subtracted from 1.0 like it would have if we used real distances.
- */
+ * subtracted from 1.0 like it would have if we used real distances. */
- /*
- * Here we reconstruct the pixel's memory location in the CompBuf by
- * Pixel Index = Pixel Column + ( Pixel Row * Row Width )
- */
+ /* Here we reconstruct the pixel's memory location in the CompBuf by
+ * `Pixel Index = Pixel Column + ( Pixel Row * Row Width )`. */
res[gbuf[gradientFillOffset + 1] + (gbuf[gradientFillOffset] * rw)] =
- (idist / (idist + odist)); // set intensity
+ (idist / (idist + odist)); /* Set intensity. */
}
}
-// end of copy
+/* End of copy. */
void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float *res)
{
- unsigned int *lres; // lres = unsigned int pointer to output pixel buffer (for bit operations)
- unsigned int *limask; // limask = unsigned int pointer to inner mask (for bit operations)
- unsigned int *lomask; // lomask = unsigned int pointer to outer mask (for bit operations)
-
- int rw; // rw = pixel row width
- int t; // t = total number of pixels in buffer - 1 (used for loop starts)
- int fsz; // size of the frame
-
- unsigned int isz = 0; // size (in pixels) of inside edge pixel index buffer
- unsigned int osz = 0; // size (in pixels) of outside edge pixel index buffer
- unsigned int gsz = 0; // size (in pixels) of gradient pixel index buffer
- unsigned int rsize[3]; // size storage to pass to helper functions
+ unsigned int *lres; /* Pointer to output pixel buffer (for bit operations). */
+ unsigned int *limask; /* Pointer to inner mask (for bit operations). */
+ unsigned int *lomask; /* Pointer to outer mask (for bit operations). */
+
+ int rw; /* Pixel row width. */
+ int t; /* Total number of pixels in buffer - 1 (used for loop starts). */
+ int fsz; /* Size of the frame. */
+
+ unsigned int isz = 0; /* Size (in pixels) of inside edge pixel index buffer. */
+ unsigned int osz = 0; /* Size (in pixels) of outside edge pixel index buffer. */
+ unsigned int gsz = 0; /* Size (in pixels) of gradient pixel index buffer. */
+ unsigned int rsize[3]; /* Size storage to pass to helper functions. */
unsigned int innerEdgeOffset =
- 0; // offset into final buffer where inner edge pixel indexes start
+ 0; /* Offset into final buffer where inner edge pixel indexes start. */
unsigned int outerEdgeOffset =
- 0; // offset into final buffer where outer edge pixel indexes start
+ 0; /* Offset into final buffer where outer edge pixel indexes start. */
- unsigned short *gbuf; // gradient/inner/outer pixel location index buffer
+ unsigned short *gbuf; /* Gradient/inner/outer pixel location index buffer. */
- if (true) { // if both input sockets have some data coming in...
+ if (true) { /* If both input sockets have some data coming in... */
- rw = this->getWidth(); // width of a row of pixels
- t = (rw * this->getHeight()) - 1; // determine size of the frame
+ rw = this->getWidth(); /* Width of a row of pixels. */
+ t = (rw * this->getHeight()) - 1; /* Determine size of the frame. */
memset(res,
0,
- sizeof(float) * (t + 1)); // clear output buffer (not all pixels will be written later)
+ sizeof(float) *
+ (t + 1)); /* Clear output buffer (not all pixels will be written later). */
- lres = (unsigned int *)res; // unsigned int pointer to output buffer (for bit level ops)
- limask = (unsigned int *)imask; // unsigned int pointer to input mask (for bit level ops)
- lomask = (unsigned int *)omask; // unsigned int pointer to output mask (for bit level ops)
+ lres = (unsigned int *)res; /* Pointer to output buffer (for bit level ops).. */
+ limask = (unsigned int *)imask; /* Pointer to input mask (for bit level ops).. */
+ lomask = (unsigned int *)omask; /* Pointer to output mask (for bit level ops).. */
/*
* The whole buffer is broken up into 4 parts. The four CORNERS, the FIRST and LAST rows, the
@@ -1258,52 +1270,52 @@ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float
*
* Each version has slightly different criteria for detecting an edge pixel.
*/
- if (this->m_adjacentOnly) { // if "adjacent only" inner edge mode is turned on
- if (this->m_keepInside) { // if "keep inside" buffer edge mode is turned on
+ if (this->m_adjacentOnly) { /* If "adjacent only" inner edge mode is turned on. */
+ if (this->m_keepInside) { /* If "keep inside" buffer edge mode is turned on. */
do_adjacentKeepBorders(t, rw, limask, lomask, lres, res, rsize);
}
- else { // "bleed out" buffer edge mode is turned on
+ else { /* "bleed out" buffer edge mode is turned on. */
do_adjacentBleedBorders(t, rw, limask, lomask, lres, res, rsize);
}
- // set up inner edge, outer edge, and gradient buffer sizes after border pass
+ /* Set up inner edge, outer edge, and gradient buffer sizes after border pass. */
isz = rsize[0];
osz = rsize[1];
gsz = rsize[2];
- // detect edges in all non-border pixels in the buffer
+ /* Detect edges in all non-border pixels in the buffer. */
do_adjacentEdgeDetection(t, rw, limask, lomask, lres, res, rsize, isz, osz, gsz);
}
- else { // "all" inner edge mode is turned on
- if (this->m_keepInside) { // if "keep inside" buffer edge mode is turned on
+ else { /* "all" inner edge mode is turned on. */
+ if (this->m_keepInside) { /* If "keep inside" buffer edge mode is turned on. */
do_allKeepBorders(t, rw, limask, lomask, lres, res, rsize);
}
- else { // "bleed out" buffer edge mode is turned on
+ else { /* "bleed out" buffer edge mode is turned on. */
do_allBleedBorders(t, rw, limask, lomask, lres, res, rsize);
}
- // set up inner edge, outer edge, and gradient buffer sizes after border pass
+ /* Set up inner edge, outer edge, and gradient buffer sizes after border pass. */
isz = rsize[0];
osz = rsize[1];
gsz = rsize[2];
- // detect edges in all non-border pixels in the buffer
+ /* Detect edges in all non-border pixels in the buffer. */
do_allEdgeDetection(t, rw, limask, lomask, lres, res, rsize, isz, osz, gsz);
}
- // set edge and gradient buffer sizes once again...
- // the sizes in rsize[] may have been modified
- // by the do_*EdgeDetection() function.
+ /* Set edge and gradient buffer sizes once again...
+ * the sizes in rsize[] may have been modified
+ * by the `do_*EdgeDetection()` function. */
isz = rsize[0];
osz = rsize[1];
gsz = rsize[2];
- // calculate size of pixel index buffer needed
+ /* Calculate size of pixel index buffer needed. */
fsz = gsz + isz + osz;
- // allocate edge/gradient pixel index buffer
+ /* Allocate edge/gradient pixel index buffer. */
gbuf = (unsigned short *)MEM_callocN(sizeof(unsigned short) * fsz * 2, "DEM");
do_createEdgeLocationBuffer(
t, rw, lres, res, gbuf, &innerEdgeOffset, &outerEdgeOffset, isz, gsz);
do_fillGradientBuffer(rw, res, gbuf, isz, osz, gsz, innerEdgeOffset, outerEdgeOffset);
- // free the gradient index buffer
+ /* Free the gradient index buffer. */
MEM_freeN(gbuf);
}
}
@@ -1318,6 +1330,7 @@ DoubleEdgeMaskOperation::DoubleEdgeMaskOperation()
this->m_adjacentOnly = false;
this->m_keepInside = false;
this->flags.complex = true;
+ is_output_rendered_ = false;
}
bool DoubleEdgeMaskOperation::determineDependingAreaOfInterest(rcti * /*input*/,
@@ -1382,4 +1395,43 @@ void DoubleEdgeMaskOperation::deinitExecution()
}
}
+void DoubleEdgeMaskOperation::get_area_of_interest(int UNUSED(input_idx),
+ const rcti &UNUSED(output_area),
+ rcti &r_input_area)
+{
+ r_input_area.xmax = this->getWidth();
+ r_input_area.xmin = 0;
+ r_input_area.ymax = this->getHeight();
+ r_input_area.ymin = 0;
+}
+
+void DoubleEdgeMaskOperation::update_memory_buffer(MemoryBuffer *output,
+ const rcti &UNUSED(area),
+ Span<MemoryBuffer *> inputs)
+{
+ if (!is_output_rendered_) {
+ /* Ensure full buffers to work with no strides. */
+ MemoryBuffer *input_inner_mask = inputs[0];
+ MemoryBuffer *inner_mask = input_inner_mask->is_a_single_elem() ? input_inner_mask->inflate() :
+ input_inner_mask;
+ MemoryBuffer *input_outer_mask = inputs[1];
+ MemoryBuffer *outer_mask = input_outer_mask->is_a_single_elem() ? input_outer_mask->inflate() :
+ input_outer_mask;
+
+ BLI_assert(output->getWidth() == this->getWidth());
+ BLI_assert(output->getHeight() == this->getHeight());
+ /* TODO(manzanilla): Once tiled implementation is removed, use execution system to run
+ * multi-threaded where possible. */
+ doDoubleEdgeMask(inner_mask->getBuffer(), outer_mask->getBuffer(), output->getBuffer());
+ is_output_rendered_ = true;
+
+ if (inner_mask != input_inner_mask) {
+ delete inner_mask;
+ }
+ if (outer_mask != input_outer_mask) {
+ delete outer_mask;
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h
index e956e8edc3e..45a80bbbbf0 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
@@ -31,8 +31,12 @@ class DoubleEdgeMaskOperation : public NodeOperation {
SocketReader *m_inputInnerMask;
bool m_adjacentOnly;
bool m_keepInside;
+
+ /* TODO(manzanilla): To be removed with tiled implementation. */
float *m_cachedInstance;
+ bool is_output_rendered_;
+
public:
DoubleEdgeMaskOperation();
@@ -66,6 +70,12 @@ class DoubleEdgeMaskOperation : public NodeOperation {
{
this->m_keepInside = keepInside;
}
+
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
+
+ void update_memory_buffer(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
index 5a4503fecec..eb1fd98a590 100644
--- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
+++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
@@ -20,6 +20,8 @@
#include "BLI_math.h"
#include "DNA_node_types.h"
+#include <functional>
+
namespace blender::compositor {
EllipseMaskOperation::EllipseMaskOperation()
@@ -114,6 +116,77 @@ void EllipseMaskOperation::executePixelSampled(float output[4],
}
}
+void EllipseMaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ MaskFunc mask_func;
+ switch (m_maskType) {
+ case CMP_NODE_MASKTYPE_ADD:
+ mask_func = [](const bool is_inside, const float *mask, const float *value) {
+ return is_inside ? MAX2(mask[0], value[0]) : mask[0];
+ };
+ break;
+ case CMP_NODE_MASKTYPE_SUBTRACT:
+ mask_func = [](const bool is_inside, const float *mask, const float *value) {
+ return is_inside ? CLAMPIS(mask[0] - value[0], 0, 1) : mask[0];
+ };
+ break;
+ case CMP_NODE_MASKTYPE_MULTIPLY:
+ mask_func = [](const bool is_inside, const float *mask, const float *value) {
+ return is_inside ? mask[0] * value[0] : 0;
+ };
+ break;
+ case CMP_NODE_MASKTYPE_NOT:
+ mask_func = [](const bool is_inside, const float *mask, const float *value) {
+ if (is_inside) {
+ return mask[0] > 0.0f ? 0.0f : value[0];
+ }
+ return mask[0];
+ };
+ break;
+ }
+ apply_mask(output, area, inputs, mask_func);
+}
+
+void EllipseMaskOperation::apply_mask(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs,
+ MaskFunc mask_func)
+{
+ const MemoryBuffer *input_mask = inputs[0];
+ const MemoryBuffer *input_value = inputs[1];
+ const float op_w = this->getWidth();
+ const float op_h = this->getHeight();
+ const float half_w = this->m_data->width / 2.0f;
+ const float half_h = this->m_data->height / 2.0f;
+ const float tx = half_w * half_w;
+ const float ty = half_h * half_h;
+ for (const int y : YRange(area)) {
+ const float op_ry = y / op_h;
+ const float dy = (op_ry - this->m_data->y) / m_aspectRatio;
+ float *out = output->get_elem(area.xmin, y);
+ const float *mask = input_mask->get_elem(area.xmin, y);
+ const float *value = input_value->get_elem(area.xmin, y);
+ for (const int x : XRange(area)) {
+ const float op_rx = x / op_w;
+ const float dx = op_rx - this->m_data->x;
+ const float rx = this->m_data->x + (m_cosine * dx + m_sine * dy);
+ const float ry = this->m_data->y + (-m_sine * dx + m_cosine * dy);
+ float sx = rx - this->m_data->x;
+ sx *= sx;
+ float sy = ry - this->m_data->y;
+ sy *= sy;
+ const bool inside = ((sx / tx) + (sy / ty)) < 1.0f;
+ out[0] = mask_func(inside, mask, value);
+
+ mask += input_mask->elem_stride;
+ value += input_value->elem_stride;
+ out += output->elem_stride;
+ }
+ }
+}
+
void EllipseMaskOperation::deinitExecution()
{
this->m_inputMask = nullptr;
diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.h b/source/blender/compositor/operations/COM_EllipseMaskOperation.h
index 64afe0145cf..fba3f979d26 100644
--- a/source/blender/compositor/operations/COM_EllipseMaskOperation.h
+++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.h
@@ -18,12 +18,14 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class EllipseMaskOperation : public NodeOperation {
+class EllipseMaskOperation : public MultiThreadedOperation {
private:
+ using MaskFunc = std::function<float(bool is_inside, const float *mask, const float *value)>;
+
/**
* Cached reference to the inputProgram
*/
@@ -64,6 +66,16 @@ class EllipseMaskOperation : public NodeOperation {
{
this->m_maskType = maskType;
}
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+
+ private:
+ void apply_mask(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs,
+ MaskFunc mask_func);
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
index 2be6e4d1be7..3804e6ec646 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
@@ -126,7 +126,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
float *buffer = src->getBuffer();
const uint8_t num_channels = src->get_num_channels();
- // <0.5 not valid, though can have a possibly useful sort of sharpening effect
+ /* <0.5 not valid, though can have a possibly useful sort of sharpening effect. */
if (sigma < 0.5f) {
return;
}
@@ -135,8 +135,8 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
xy = 3;
}
- // XXX The YVV macro defined below explicitly expects sources of at least 3x3 pixels,
- // so just skipping blur along faulty direction if src's def is below that limit!
+ /* XXX The YVV macro defined below explicitly expects sources of at least 3x3 pixels,
+ * so just skipping blur along faulty direction if src's def is below that limit! */
if (src_width < 3) {
xy &= ~1;
}
@@ -147,32 +147,32 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
return;
}
- // see "Recursive Gabor Filtering" by Young/VanVliet
- // all factors here in double.prec.
- // Required, because for single.prec it seems to blow up if sigma > ~200
+ /* See "Recursive Gabor Filtering" by Young/VanVliet
+ * all factors here in double-precision.
+ * Required, because for single-precision floating point seems to blow up if `sigma > ~200`. */
if (sigma >= 3.556f) {
q = 0.9804f * (sigma - 3.556f) + 2.5091f;
}
- else { // sigma >= 0.5
+ else { /* `sigma >= 0.5`. */
q = (0.0561f * sigma + 0.5784f) * sigma - 0.2568f;
}
q2 = q * q;
sc = (1.1668 + q) * (3.203729649 + (2.21566 + q) * q);
- // no gabor filtering here, so no complex multiplies, just the regular coefs.
- // all negated here, so as not to have to recalc Triggs/Sdika matrix
+ /* No gabor filtering here, so no complex multiplies, just the regular coefficients.
+ * all negated here, so as not to have to recalc Triggs/Sdika matrix. */
cf[1] = q * (5.788961737 + (6.76492 + 3.0 * q) * q) / sc;
cf[2] = -q2 * (3.38246 + 3.0 * q) / sc;
- // 0 & 3 unchanged
+ /* 0 & 3 unchanged. */
cf[3] = q2 * q / sc;
cf[0] = 1.0 - cf[1] - cf[2] - cf[3];
- // Triggs/Sdika border corrections,
- // it seems to work, not entirely sure if it is actually totally correct,
- // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark),
- // found one other implementation by Cristoph Lampert,
- // but neither seem to be quite the same, result seems to be ok so far anyway.
- // Extra scale factor here to not have to do it in filter,
- // though maybe this had something to with the precision errors
+ /* Triggs/Sdika border corrections,
+ * it seems to work, not entirely sure if it is actually totally correct,
+ * Besides J.M.Geusebroek's `anigauss.c` (see http://www.science.uva.nl/~mark),
+ * found one other implementation by Cristoph Lampert,
+ * but neither seem to be quite the same, result seems to be ok so far anyway.
+ * Extra scale factor here to not have to do it in filter,
+ * though maybe this had something to with the precision errors */
sc = cf[0] / ((1.0 + cf[1] - cf[2] + cf[3]) * (1.0 - cf[1] - cf[2] - cf[3]) *
(1.0 + cf[2] + (cf[1] - cf[3]) * cf[3]));
tsM[0] = sc * (-cf[3] * cf[1] + 1.0 - cf[3] * cf[3] - cf[2]);
@@ -210,12 +210,12 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
} \
(void)0
- // intermediate buffers
+ /* Intermediate buffers. */
sz = MAX2(src_width, src_height);
X = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss X buf");
Y = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss Y buf");
W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf");
- if (xy & 1) { // H
+ if (xy & 1) { /* H. */
int offset;
for (y = 0; y < src_height; y++) {
const int yx = y * src_width;
@@ -232,7 +232,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
}
}
}
- if (xy & 2) { // V
+ if (xy & 2) { /* V. */
int offset;
const int add = src_width * num_channels;
@@ -257,7 +257,6 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
#undef YVV
}
-///
FastGaussianBlurValueOperation::FastGaussianBlurValueOperation()
{
this->addInputSocket(DataType::Value);
@@ -336,8 +335,6 @@ void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect)
}
}
- // newBuf->
-
this->m_iirgaus = copy;
}
unlockMutex();
diff --git a/source/blender/compositor/operations/COM_MixOperation.cc b/source/blender/compositor/operations/COM_MixOperation.cc
index 58fa09fa2a8..77ecbf60356 100644
--- a/source/blender/compositor/operations/COM_MixOperation.cc
+++ b/source/blender/compositor/operations/COM_MixOperation.cc
@@ -35,6 +35,7 @@ MixBaseOperation::MixBaseOperation()
this->m_inputColor2Operation = nullptr;
this->setUseValueAlphaMultiply(false);
this->setUseClamp(false);
+ flags.can_be_constant = true;
}
void MixBaseOperation::initExecution()
@@ -97,6 +98,45 @@ void MixBaseOperation::deinitExecution()
this->m_inputColor2Operation = nullptr;
}
+void MixBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input_value = inputs[0];
+ const MemoryBuffer *input_color1 = inputs[1];
+ const MemoryBuffer *input_color2 = inputs[2];
+ const int width = BLI_rcti_size_x(&area);
+ PixelCursor p;
+ p.out_stride = output->elem_stride;
+ p.value_stride = input_value->elem_stride;
+ p.color1_stride = input_color1->elem_stride;
+ p.color2_stride = input_color2->elem_stride;
+ for (const int y : YRange(area)) {
+ p.out = output->get_elem(area.xmin, y);
+ p.row_end = p.out + width * output->elem_stride;
+ p.value = input_value->get_elem(area.xmin, y);
+ p.color1 = input_color1->get_elem(area.xmin, y);
+ p.color2 = input_color2->get_elem(area.xmin, y);
+ update_memory_buffer_row(p);
+ }
+}
+
+void MixBaseOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+ p.out[0] = value_m * p.color1[0] + value * p.color2[0];
+ p.out[1] = value_m * p.color1[1] + value * p.color2[1];
+ p.out[2] = value_m * p.color1[2] + value * p.color2[2];
+ p.out[3] = p.color1[3];
+ p.next();
+ }
+}
+
/* ******** Mix Add Operation ******** */
void MixAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
@@ -121,6 +161,23 @@ void MixAddOperation::executePixelSampled(float output[4], float x, float y, Pix
clampIfNeeded(output);
}
+void MixAddOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ p.out[0] = p.color1[0] + value * p.color2[0];
+ p.out[1] = p.color1[1] + value * p.color2[1];
+ p.out[2] = p.color1[2] + value * p.color2[2];
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Blend Operation ******** */
void MixBlendOperation::executePixelSampled(float output[4],
@@ -150,6 +207,24 @@ void MixBlendOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixBlendOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ float value_m = 1.0f - value;
+ p.out[0] = value_m * p.color1[0] + value * p.color2[0];
+ p.out[1] = value_m * p.color1[1] + value * p.color2[1];
+ p.out[2] = value_m * p.color1[2] + value * p.color2[2];
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Burn Operation ******** */
void MixColorBurnOperation::executePixelSampled(float output[4],
@@ -228,6 +303,48 @@ void MixColorBurnOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixColorBurnOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ float tmp = value_m + value * p.color2[0];
+ if (tmp <= 0.0f) {
+ p.out[0] = 0.0f;
+ }
+ else {
+ tmp = 1.0f - (1.0f - p.color1[0]) / tmp;
+ p.out[0] = CLAMPIS(tmp, 0.0f, 1.0f);
+ }
+
+ tmp = value_m + value * p.color2[1];
+ if (tmp <= 0.0f) {
+ p.out[1] = 0.0f;
+ }
+ else {
+ tmp = 1.0f - (1.0f - p.color1[1]) / tmp;
+ p.out[1] = CLAMPIS(tmp, 0.0f, 1.0f);
+ }
+
+ tmp = value_m + value * p.color2[2];
+ if (tmp <= 0.0f) {
+ p.out[2] = 0.0f;
+ }
+ else {
+ tmp = 1.0f - (1.0f - p.color1[2]) / tmp;
+ p.out[2] = CLAMPIS(tmp, 0.0f, 1.0f);
+ }
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Color Operation ******** */
void MixColorOperation::executePixelSampled(float output[4],
@@ -268,6 +385,36 @@ void MixColorOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixColorOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ float colH, colS, colV;
+ rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV);
+ if (colS != 0.0f) {
+ float rH, rS, rV;
+ float tmpr, tmpg, tmpb;
+ rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV);
+ hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb);
+ p.out[0] = (value_m * p.color1[0]) + (value * tmpr);
+ p.out[1] = (value_m * p.color1[1]) + (value * tmpg);
+ p.out[2] = (value_m * p.color1[2]) + (value * tmpb);
+ }
+ else {
+ copy_v3_v3(p.out, p.color1);
+ }
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Darken Operation ******** */
void MixDarkenOperation::executePixelSampled(float output[4],
@@ -296,6 +443,24 @@ void MixDarkenOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixDarkenOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ float value_m = 1.0f - value;
+ p.out[0] = min_ff(p.color1[0], p.color2[0]) * value + p.color1[0] * value_m;
+ p.out[1] = min_ff(p.color1[1], p.color2[1]) * value + p.color1[1] * value_m;
+ p.out[2] = min_ff(p.color1[2], p.color2[2]) * value + p.color1[2] * value_m;
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Difference Operation ******** */
void MixDifferenceOperation::executePixelSampled(float output[4],
@@ -324,6 +489,24 @@ void MixDifferenceOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixDifferenceOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+ p.out[0] = value_m * p.color1[0] + value * fabsf(p.color1[0] - p.color2[0]);
+ p.out[1] = value_m * p.color1[1] + value * fabsf(p.color1[1] - p.color2[1]);
+ p.out[2] = value_m * p.color1[2] + value * fabsf(p.color1[2] - p.color2[2]);
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Difference Operation ******** */
void MixDivideOperation::executePixelSampled(float output[4],
@@ -369,6 +552,41 @@ void MixDivideOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixDivideOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ if (p.color2[0] != 0.0f) {
+ p.out[0] = value_m * (p.color1[0]) + value * (p.color1[0]) / p.color2[0];
+ }
+ else {
+ p.out[0] = 0.0f;
+ }
+ if (p.color2[1] != 0.0f) {
+ p.out[1] = value_m * (p.color1[1]) + value * (p.color1[1]) / p.color2[1];
+ }
+ else {
+ p.out[1] = 0.0f;
+ }
+ if (p.color2[2] != 0.0f) {
+ p.out[2] = value_m * (p.color1[2]) + value * (p.color1[2]) / p.color2[2];
+ }
+ else {
+ p.out[2] = 0.0f;
+ }
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Dodge Operation ******** */
void MixDodgeOperation::executePixelSampled(float output[4],
@@ -452,6 +670,64 @@ void MixDodgeOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixDodgeOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+
+ float tmp;
+ if (p.color1[0] != 0.0f) {
+ tmp = 1.0f - value * p.color2[0];
+ if (tmp <= 0.0f) {
+ p.out[0] = 1.0f;
+ }
+ else {
+ p.out[0] = p.color1[0] / tmp;
+ CLAMP_MAX(p.out[0], 1.0f);
+ }
+ }
+ else {
+ p.out[0] = 0.0f;
+ }
+
+ if (p.color1[1] != 0.0f) {
+ tmp = 1.0f - value * p.color2[1];
+ if (tmp <= 0.0f) {
+ p.out[1] = 1.0f;
+ }
+ else {
+ p.out[1] = p.color1[1] / tmp;
+ CLAMP_MAX(p.out[1], 1.0f);
+ }
+ }
+ else {
+ p.out[1] = 0.0f;
+ }
+
+ if (p.color1[2] != 0.0f) {
+ tmp = 1.0f - value * p.color2[2];
+ if (tmp <= 0.0f) {
+ p.out[2] = 1.0f;
+ }
+ else {
+ p.out[2] = p.color1[2] / tmp;
+ CLAMP_MAX(p.out[2], 1.0f);
+ }
+ }
+ else {
+ p.out[2] = 0.0f;
+ }
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Glare Operation ******** */
void MixGlareOperation::executePixelSampled(float output[4],
@@ -487,6 +763,33 @@ void MixGlareOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixGlareOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ const float value = p.value[0];
+ /* Linear interpolation between 3 cases:
+ * value=-1:output=input value=0:output=input+glare value=1:output=glare
+ */
+ float input_weight;
+ float glare_weight;
+ if (value < 0.0f) {
+ input_weight = 1.0f;
+ glare_weight = 1.0f + value;
+ }
+ else {
+ input_weight = 1.0f - value;
+ glare_weight = 1.0f;
+ }
+ p.out[0] = input_weight * MAX2(p.color1[0], 0.0f) + glare_weight * p.color2[0];
+ p.out[1] = input_weight * MAX2(p.color1[1], 0.0f) + glare_weight * p.color2[1];
+ p.out[2] = input_weight * MAX2(p.color1[2], 0.0f) + glare_weight * p.color2[2];
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Hue Operation ******** */
void MixHueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
@@ -524,6 +827,36 @@ void MixHueOperation::executePixelSampled(float output[4], float x, float y, Pix
clampIfNeeded(output);
}
+void MixHueOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ float colH, colS, colV;
+ rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV);
+ if (colS != 0.0f) {
+ float rH, rS, rV;
+ float tmpr, tmpg, tmpb;
+ rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV);
+ hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb);
+ p.out[0] = value_m * p.color1[0] + value * tmpr;
+ p.out[1] = value_m * p.color1[1] + value * tmpg;
+ p.out[2] = value_m * p.color1[2] + value * tmpb;
+ }
+ else {
+ copy_v3_v3(p.out, p.color1);
+ }
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Lighten Operation ******** */
void MixLightenOperation::executePixelSampled(float output[4],
@@ -570,6 +903,30 @@ void MixLightenOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixLightenOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+
+ float tmp = value * p.color2[0];
+ p.out[0] = MAX2(tmp, p.color1[0]);
+
+ tmp = value * p.color2[1];
+ p.out[1] = MAX2(tmp, p.color1[1]);
+
+ tmp = value * p.color2[2];
+ p.out[2] = MAX2(tmp, p.color1[2]);
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Linear Light Operation ******** */
void MixLinearLightOperation::executePixelSampled(float output[4],
@@ -613,6 +970,39 @@ void MixLinearLightOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixLinearLightOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ if (p.color2[0] > 0.5f) {
+ p.out[0] = p.color1[0] + value * (2.0f * (p.color2[0] - 0.5f));
+ }
+ else {
+ p.out[0] = p.color1[0] + value * (2.0f * (p.color2[0]) - 1.0f);
+ }
+ if (p.color2[1] > 0.5f) {
+ p.out[1] = p.color1[1] + value * (2.0f * (p.color2[1] - 0.5f));
+ }
+ else {
+ p.out[1] = p.color1[1] + value * (2.0f * (p.color2[1]) - 1.0f);
+ }
+ if (p.color2[2] > 0.5f) {
+ p.out[2] = p.color1[2] + value * (2.0f * (p.color2[2] - 0.5f));
+ }
+ else {
+ p.out[2] = p.color1[2] + value * (2.0f * (p.color2[2]) - 1.0f);
+ }
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Multiply Operation ******** */
void MixMultiplyOperation::executePixelSampled(float output[4],
@@ -641,6 +1031,25 @@ void MixMultiplyOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixMultiplyOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+ p.out[0] = p.color1[0] * (value_m + value * p.color2[0]);
+ p.out[1] = p.color1[1] * (value_m + value * p.color2[1]);
+ p.out[2] = p.color1[2] * (value_m + value * p.color2[2]);
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Overlay Operation ******** */
void MixOverlayOperation::executePixelSampled(float output[4],
@@ -686,6 +1095,40 @@ void MixOverlayOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixOverlayOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+ if (p.color1[0] < 0.5f) {
+ p.out[0] = p.color1[0] * (value_m + 2.0f * value * p.color2[0]);
+ }
+ else {
+ p.out[0] = 1.0f - (value_m + 2.0f * value * (1.0f - p.color2[0])) * (1.0f - p.color1[0]);
+ }
+ if (p.color1[1] < 0.5f) {
+ p.out[1] = p.color1[1] * (value_m + 2.0f * value * p.color2[1]);
+ }
+ else {
+ p.out[1] = 1.0f - (value_m + 2.0f * value * (1.0f - p.color2[1])) * (1.0f - p.color1[1]);
+ }
+ if (p.color1[2] < 0.5f) {
+ p.out[2] = p.color1[2] * (value_m + 2.0f * value * p.color2[2]);
+ }
+ else {
+ p.out[2] = 1.0f - (value_m + 2.0f * value * (1.0f - p.color2[2])) * (1.0f - p.color1[2]);
+ }
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Saturation Operation ******** */
void MixSaturationOperation::executePixelSampled(float output[4],
@@ -723,6 +1166,33 @@ void MixSaturationOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixSaturationOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ float rH, rS, rV;
+ rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV);
+ if (rS != 0.0f) {
+ float colH, colS, colV;
+ rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV);
+ hsv_to_rgb(rH, (value_m * rS + value * colS), rV, &p.out[0], &p.out[1], &p.out[2]);
+ }
+ else {
+ copy_v3_v3(p.out, p.color1);
+ }
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Screen Operation ******** */
void MixScreenOperation::executePixelSampled(float output[4],
@@ -752,6 +1222,25 @@ void MixScreenOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixScreenOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ p.out[0] = 1.0f - (value_m + value * (1.0f - p.color2[0])) * (1.0f - p.color1[0]);
+ p.out[1] = 1.0f - (value_m + value * (1.0f - p.color2[1])) * (1.0f - p.color1[1]);
+ p.out[2] = 1.0f - (value_m + value * (1.0f - p.color2[2])) * (1.0f - p.color1[2]);
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Soft Light Operation ******** */
void MixSoftLightOperation::executePixelSampled(float output[4],
@@ -793,6 +1282,34 @@ void MixSoftLightOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixSoftLightOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+ float scr, scg, scb;
+
+ /* First calculate non-fac based Screen mix. */
+ scr = 1.0f - (1.0f - p.color2[0]) * (1.0f - p.color1[0]);
+ scg = 1.0f - (1.0f - p.color2[1]) * (1.0f - p.color1[1]);
+ scb = 1.0f - (1.0f - p.color2[2]) * (1.0f - p.color1[2]);
+
+ p.out[0] = value_m * p.color1[0] +
+ value * ((1.0f - p.color1[0]) * p.color2[0] * p.color1[0] + p.color1[0] * scr);
+ p.out[1] = value_m * p.color1[1] +
+ value * ((1.0f - p.color1[1]) * p.color2[1] * p.color1[1] + p.color1[1] * scg);
+ p.out[2] = value_m * p.color1[2] +
+ value * ((1.0f - p.color1[2]) * p.color2[2] * p.color1[2] + p.color1[2] * scb);
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Subtract Operation ******** */
void MixSubtractOperation::executePixelSampled(float output[4],
@@ -820,6 +1337,23 @@ void MixSubtractOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixSubtractOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ p.out[0] = p.color1[0] - value * p.color2[0];
+ p.out[1] = p.color1[1] - value * p.color2[1];
+ p.out[2] = p.color1[2] - value * p.color2[2];
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Value Operation ******** */
void MixValueOperation::executePixelSampled(float output[4],
@@ -851,4 +1385,25 @@ void MixValueOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixValueOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ float value_m = 1.0f - value;
+
+ float rH, rS, rV;
+ float colH, colS, colV;
+ rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV);
+ rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV);
+ hsv_to_rgb(rH, rS, (value_m * rV + value * colV), &p.out[0], &p.out[1], &p.out[2]);
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MixOperation.h b/source/blender/compositor/operations/COM_MixOperation.h
index 6c241bc5762..7ef9d78d58f 100644
--- a/source/blender/compositor/operations/COM_MixOperation.h
+++ b/source/blender/compositor/operations/COM_MixOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
@@ -27,8 +27,29 @@ namespace blender::compositor {
* it assumes we are in sRGB color space.
*/
-class MixBaseOperation : public NodeOperation {
+class MixBaseOperation : public MultiThreadedOperation {
protected:
+ struct PixelCursor {
+ float *out;
+ const float *row_end;
+ const float *value;
+ const float *color1;
+ const float *color2;
+ int out_stride;
+ int value_stride;
+ int color1_stride;
+ int color2_stride;
+
+ void next()
+ {
+ BLI_assert(out < row_end);
+ out += out_stride;
+ value += value_stride;
+ color1 += color1_stride;
+ color2 += color2_stride;
+ }
+ };
+
/**
* Prefetched reference to the inputProgram
*/
@@ -81,101 +102,165 @@ class MixBaseOperation : public NodeOperation {
{
this->m_useClamp = value;
}
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) final;
+
+ protected:
+ virtual void update_memory_buffer_row(PixelCursor &p);
};
class MixAddOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixBlendOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixColorBurnOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixColorOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixDarkenOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixDifferenceOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixDivideOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixDodgeOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixGlareOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixHueOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixLightenOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixLinearLightOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixMultiplyOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixOverlayOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixSaturationOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixScreenOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixSoftLightOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixSubtractOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixValueOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cc b/source/blender/compositor/operations/COM_MovieClipOperation.cc
index d93a75407c4..e520b928edf 100644
--- a/source/blender/compositor/operations/COM_MovieClipOperation.cc
+++ b/source/blender/compositor/operations/COM_MovieClipOperation.cc
@@ -116,6 +116,18 @@ void MovieClipBaseOperation::executePixelSampled(float output[4],
}
}
+void MovieClipBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ if (m_movieClipBuffer) {
+ output->copy_from(m_movieClipBuffer, area);
+ }
+ else {
+ output->fill(area, COM_COLOR_TRANSPARENT);
+ }
+}
+
MovieClipOperation::MovieClipOperation() : MovieClipBaseOperation()
{
this->addOutputSocket(DataType::Color);
@@ -136,4 +148,16 @@ void MovieClipAlphaOperation::executePixelSampled(float output[4],
output[0] = result[3];
}
+void MovieClipAlphaOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ if (m_movieClipBuffer) {
+ output->copy_from(m_movieClipBuffer, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0);
+ }
+ else {
+ output->fill(area, COM_VALUE_ZERO);
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.h b/source/blender/compositor/operations/COM_MovieClipOperation.h
index c853ea43762..0a0c4c00f81 100644
--- a/source/blender/compositor/operations/COM_MovieClipOperation.h
+++ b/source/blender/compositor/operations/COM_MovieClipOperation.h
@@ -19,7 +19,7 @@
#pragma once
#include "BLI_listbase.h"
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_movieclip_types.h"
#include "IMB_imbuf_types.h"
@@ -28,7 +28,7 @@ namespace blender::compositor {
/**
* Base class for movie clip
*/
-class MovieClipBaseOperation : public NodeOperation {
+class MovieClipBaseOperation : public MultiThreadedOperation {
protected:
MovieClip *m_movieClip;
MovieClipUser *m_movieClipUser;
@@ -67,6 +67,10 @@ class MovieClipBaseOperation : public NodeOperation {
this->m_framenumber = framenumber;
}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
class MovieClipOperation : public MovieClipBaseOperation {
@@ -78,6 +82,10 @@ class MovieClipAlphaOperation : public MovieClipBaseOperation {
public:
MovieClipAlphaOperation();
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc
index 3c753591ced..b078d85372d 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.cc
+++ b/source/blender/compositor/operations/COM_SMAAOperation.cc
@@ -19,9 +19,9 @@
*/
#include "COM_SMAAOperation.h"
+#include "BKE_node.h"
#include "BLI_math.h"
#include "COM_SMAAAreaTexture.h"
-#include "BKE_node.h"
extern "C" {
#include "IMB_colormanagement.h"
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cc b/source/blender/compositor/operations/COM_SunBeamsOperation.cc
index ff117841e8e..bd82b6397ad 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.cc
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cc
@@ -46,14 +46,14 @@ void SunBeamsOperation::initExecution()
* (u,v) is used to designate sector space coordinates
*
* For a target point (x,y) the sector should be chosen such that
- * ``u >= v >= 0``
+ * `u >= v >= 0`
* This removes the need to handle all sorts of special cases.
*
* Template parameters:
- * fxu : buffer increment in x for sector u+1
- * fxv : buffer increment in x for sector v+1
- * fyu : buffer increment in y for sector u+1
- * fyv : buffer increment in y for sector v+1
+ * \param fxu: buffer increment in x for sector `u + 1`.
+ * \param fxv: buffer increment in x for sector `v + 1`.
+ * \param fyu: buffer increment in y for sector `u + 1`.
+ * \param fyv: buffer increment in y for sector `v + 1`.
*/
template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator {
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc
index 059a289ae4d..c8e0844d35f 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cc
+++ b/source/blender/compositor/operations/COM_TextureOperation.cc
@@ -157,14 +157,8 @@ void TextureBaseOperation::executePixelSampled(float output[4],
m_sceneColorManage,
false);
- if (texres.talpha) {
- output[3] = texres.ta;
- }
- else {
- output[3] = texres.tin;
- }
-
- if ((retval & TEX_RGB)) {
+ output[3] = texres.talpha ? texres.ta : texres.tin;
+ if (retval & TEX_RGB) {
output[0] = texres.tr;
output[1] = texres.tg;
output[2] = texres.tb;
@@ -174,4 +168,67 @@ void TextureBaseOperation::executePixelSampled(float output[4],
}
}
+void TextureBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const int op_width = this->getWidth();
+ const int op_height = this->getHeight();
+ const float center_x = op_width / 2;
+ const float center_y = op_height / 2;
+ TexResult tex_result = {0};
+ float vec[3];
+ const int thread_id = WorkScheduler::current_thread_id();
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ const float *tex_offset = it.in(0);
+ const float *tex_size = it.in(1);
+ float u = (it.x - center_x) / op_width * 2;
+ float v = (it.y - center_y) / op_height * 2;
+
+ /* When no interpolation/filtering happens in multitex() force nearest interpolation.
+ * We do it here because (a) we can't easily say multitex() that we want nearest
+ * interpolation and (b) in such configuration multitex() simply floor's the value
+ * which often produces artifacts.
+ */
+ if (m_texture != nullptr && (m_texture->imaflag & TEX_INTERPOL) == 0) {
+ u += 0.5f / center_x;
+ v += 0.5f / center_y;
+ }
+
+ vec[0] = tex_size[0] * (u + tex_offset[0]);
+ vec[1] = tex_size[1] * (v + tex_offset[1]);
+ vec[2] = tex_size[2] * tex_offset[2];
+
+ const int retval = multitex_ext(this->m_texture,
+ vec,
+ nullptr,
+ nullptr,
+ 0,
+ &tex_result,
+ thread_id,
+ m_pool,
+ m_sceneColorManage,
+ false);
+
+ it.out[3] = tex_result.talpha ? tex_result.ta : tex_result.tin;
+ if (retval & TEX_RGB) {
+ it.out[0] = tex_result.tr;
+ it.out[1] = tex_result.tg;
+ it.out[2] = tex_result.tb;
+ }
+ else {
+ it.out[0] = it.out[1] = it.out[2] = it.out[3];
+ }
+ }
+}
+
+void TextureAlphaOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ MemoryBuffer texture(DataType::Color, area);
+ TextureBaseOperation::update_memory_buffer_partial(&texture, area, inputs);
+ output->copy_from(&texture, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0);
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h
index 6fec9ab8f33..1e95cb270d0 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.h
+++ b/source/blender/compositor/operations/COM_TextureOperation.h
@@ -19,7 +19,7 @@
#pragma once
#include "BLI_listbase.h"
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_texture_types.h"
#include "MEM_guardedalloc.h"
@@ -33,7 +33,7 @@ namespace blender::compositor {
*
* \todo Rename to operation.
*/
-class TextureBaseOperation : public NodeOperation {
+class TextureBaseOperation : public MultiThreadedOperation {
private:
Tex *m_texture;
const RenderData *m_rd;
@@ -71,6 +71,10 @@ class TextureBaseOperation : public NodeOperation {
{
this->m_sceneColorManage = sceneColorManage;
}
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
class TextureOperation : public TextureBaseOperation {
@@ -81,6 +85,10 @@ class TextureAlphaOperation : public TextureBaseOperation {
public:
TextureAlphaOperation();
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cc b/source/blender/compositor/operations/COM_ViewerOperation.cc
index 860f56e23fa..37a45ac32cb 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cc
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cc
@@ -191,10 +191,11 @@ void ViewerOperation::initImage()
BLI_thread_unlock(LOCK_DRAW_IMAGE);
}
-void ViewerOperation::updateImage(rcti *rect)
+void ViewerOperation::updateImage(const rcti *rect)
{
+ float *buffer = m_outputBuffer;
IMB_partial_display_buffer_update(this->m_ibuf,
- this->m_outputBuffer,
+ buffer,
nullptr,
getWidth(),
0,
@@ -218,4 +219,44 @@ eCompositorPriority ViewerOperation::getRenderPriority() const
return eCompositorPriority::Low;
}
+void ViewerOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output),
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ if (!m_outputBuffer) {
+ return;
+ }
+
+ MemoryBuffer output_buffer(
+ m_outputBuffer, COM_DATA_TYPE_COLOR_CHANNELS, getWidth(), getHeight());
+ const MemoryBuffer *input_image = inputs[0];
+ output_buffer.copy_from(input_image, area);
+ if (this->m_useAlphaInput) {
+ const MemoryBuffer *input_alpha = inputs[1];
+ output_buffer.copy_from(input_alpha, area, 0, COM_DATA_TYPE_VALUE_CHANNELS, 3);
+ }
+
+ if (m_depthBuffer) {
+ MemoryBuffer depth_buffer(
+ m_depthBuffer, COM_DATA_TYPE_VALUE_CHANNELS, getWidth(), getHeight());
+ const MemoryBuffer *input_depth = inputs[2];
+ depth_buffer.copy_from(input_depth, area);
+ }
+
+ updateImage(&area);
+}
+
+void ViewerOperation::clear_display_buffer()
+{
+ BLI_assert(isActiveViewerOutput());
+ initImage();
+ size_t buf_bytes = (size_t)m_ibuf->y * m_ibuf->x * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float);
+ if (buf_bytes > 0) {
+ memset(m_outputBuffer, 0, buf_bytes);
+ rcti display_area;
+ BLI_rcti_init(&display_area, 0, m_ibuf->x, 0, m_ibuf->y);
+ updateImage(&display_area);
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.h b/source/blender/compositor/operations/COM_ViewerOperation.h
index c0f13ff79fc..06ac501a535 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.h
+++ b/source/blender/compositor/operations/COM_ViewerOperation.h
@@ -20,15 +20,17 @@
#include "BKE_global.h"
#include "BLI_rect.h"
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_image_types.h"
namespace blender::compositor {
-class ViewerOperation : public NodeOperation {
+class ViewerOperation : public MultiThreadedOperation {
private:
+ /* TODO(manzanilla): To be removed together with tiled implementation. */
float *m_outputBuffer;
float *m_depthBuffer;
+
Image *m_image;
ImageUser *m_imageUser;
bool m_active;
@@ -125,8 +127,14 @@ class ViewerOperation : public NodeOperation {
this->m_displaySettings = displaySettings;
}
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+
+ void clear_display_buffer();
+
private:
- void updateImage(rcti *rect);
+ void updateImage(const rcti *rect);
void initImage();
};
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index e561d0b653c..8d1074d912f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -1496,7 +1496,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob
add_operation_node(
&object->id,
NodeType::BATCH_CACHE,
- OperationCode::BATCH_UPDATE_SELECT,
+ OperationCode::GEOMETRY_SELECT_UPDATE,
[object_cow](::Depsgraph *depsgraph) { BKE_object_select_update(depsgraph, object_cow); });
}
@@ -1517,37 +1517,33 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
if (key) {
build_shapekeys(key);
}
-
- /* Geometry evaluation. */
- /* Entry operation, takes care of initialization, and some other
- * relations which needs to be run prior to actual geometry evaluation. */
- op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
- op_node->set_as_entry();
-
- add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM);
-
+ /* Nodes for result of obdata's evaluation, and geometry
+ * evaluation on object. */
const ID_Type id_type = GS(obdata->name);
switch (id_type) {
case ID_ME: {
- add_operation_node(obdata,
- NodeType::GEOMETRY,
- OperationCode::GEOMETRY_EVAL,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_mesh_eval_geometry(depsgraph, (Mesh *)obdata_cow);
- });
+ op_node = add_operation_node(obdata,
+ NodeType::GEOMETRY,
+ OperationCode::GEOMETRY_EVAL,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_mesh_eval_geometry(depsgraph, (Mesh *)obdata_cow);
+ });
+ op_node->set_as_entry();
break;
}
case ID_MB: {
- add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ op_node->set_as_entry();
break;
}
case ID_CU: {
- add_operation_node(obdata,
- NodeType::GEOMETRY,
- OperationCode::GEOMETRY_EVAL,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow);
- });
+ op_node = add_operation_node(obdata,
+ NodeType::GEOMETRY,
+ OperationCode::GEOMETRY_EVAL,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow);
+ });
+ op_node->set_as_entry();
/* Make sure objects used for bevel.taper are in the graph.
* NOTE: This objects might be not linked to the scene. */
Curve *cu = (Curve *)obdata;
@@ -1563,41 +1559,47 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
break;
}
case ID_LT: {
- add_operation_node(obdata,
- NodeType::GEOMETRY,
- OperationCode::GEOMETRY_EVAL,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_lattice_eval_geometry(depsgraph, (Lattice *)obdata_cow);
- });
+ op_node = add_operation_node(obdata,
+ NodeType::GEOMETRY,
+ OperationCode::GEOMETRY_EVAL,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_lattice_eval_geometry(depsgraph, (Lattice *)obdata_cow);
+ });
+ op_node->set_as_entry();
break;
}
case ID_GD: {
/* GPencil evaluation operations. */
- add_operation_node(obdata,
- NodeType::GEOMETRY,
- OperationCode::GEOMETRY_EVAL,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_gpencil_frame_active_set(depsgraph, (bGPdata *)obdata_cow);
- });
+ op_node = add_operation_node(obdata,
+ NodeType::GEOMETRY,
+ OperationCode::GEOMETRY_EVAL,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_gpencil_frame_active_set(depsgraph,
+ (bGPdata *)obdata_cow);
+ });
+ op_node->set_as_entry();
break;
}
case ID_HA: {
- add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ op_node->set_as_entry();
break;
}
case ID_PT: {
- add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ op_node->set_as_entry();
break;
}
case ID_VO: {
/* Volume frame update. */
- add_operation_node(obdata,
- NodeType::GEOMETRY,
- OperationCode::GEOMETRY_EVAL,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_volume_eval_geometry(depsgraph, (Volume *)obdata_cow);
- });
+ op_node = add_operation_node(obdata,
+ NodeType::GEOMETRY,
+ OperationCode::GEOMETRY_EVAL,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_volume_eval_geometry(depsgraph, (Volume *)obdata_cow);
+ });
+ op_node->set_as_entry();
break;
}
default:
@@ -1611,22 +1613,10 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
/* Batch cache. */
add_operation_node(obdata,
NodeType::BATCH_CACHE,
- OperationCode::BATCH_UPDATE_SELECT,
+ OperationCode::GEOMETRY_SELECT_UPDATE,
[obdata_cow](::Depsgraph *depsgraph) {
BKE_object_data_select_update(depsgraph, obdata_cow);
});
- add_operation_node(obdata,
- NodeType::BATCH_CACHE,
- OperationCode::BATCH_UPDATE_DEFORM,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_object_data_eval_batch_cache_deform_tag(depsgraph, obdata_cow);
- });
- add_operation_node(obdata,
- NodeType::BATCH_CACHE,
- OperationCode::BATCH_UPDATE_ALL,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_object_data_eval_batch_cache_dirty_tag(depsgraph, obdata_cow);
- });
}
void DepsgraphNodeBuilder::build_armature(bArmature *armature)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 415145c8fa1..c7c6fafa512 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -647,7 +647,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll
/* Only create geometry relations to child objects, if they have a geometry component. */
OperationKey object_geometry_key{
- &cob->ob->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT};
+ &cob->ob->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL};
if (find_node(object_geometry_key) != nullptr) {
add_relation(object_geometry_key, collection_geometry_key, "Collection Geometry");
}
@@ -1098,8 +1098,7 @@ void DepsgraphRelationBuilder::build_object_pointcache(Object *object)
}
else {
flag = FLAG_GEOMETRY;
- OperationKey geometry_key(
- &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
+ OperationKey geometry_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
add_relation(point_cache_key, geometry_key, "Point Cache -> Geometry");
}
BLI_assert(flag != -1);
@@ -1869,8 +1868,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
void DepsgraphRelationBuilder::build_particle_systems(Object *object)
{
TimeSourceKey time_src_key;
- OperationKey obdata_ubereval_key(
- &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
+ OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
OperationKey eval_init_key(
&object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_INIT);
OperationKey eval_done_key(
@@ -2018,8 +2016,7 @@ void DepsgraphRelationBuilder::build_particle_system_visualization_object(Object
{
OperationKey psys_key(
&object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_EVAL, psys->name);
- OperationKey obdata_ubereval_key(
- &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
+ OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
ComponentKey dup_ob_key(&draw_object->id, NodeType::TRANSFORM);
add_relation(dup_ob_key, psys_key, "Particle Object Visualization");
if (draw_object->type == OB_MBALL) {
@@ -2076,15 +2073,15 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
/* Get nodes for result of obdata's evaluation, and geometry evaluation
* on object. */
ComponentKey obdata_geom_key(obdata, NodeType::GEOMETRY);
- OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ ComponentKey geom_key(&object->id, NodeType::GEOMETRY);
/* Link components to each other. */
- add_relation(obdata_geom_key, obdata_ubereval_key, "Object Geometry Base Data");
-
+ add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data");
+ OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
/* Special case: modifiers evaluation queries scene for various things like
* data mask to be used. We add relation here to ensure object is never
* evaluated prior to Scene's CoW is ready. */
OperationKey scene_key(&scene_->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL);
- Relation *rel = add_relation(scene_key, geom_init_key, "CoW Relation");
+ Relation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation");
rel->flag |= RELATION_FLAG_NO_FLUSH;
/* Modifiers */
if (object->modifiers.first != nullptr) {
@@ -2094,13 +2091,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (mti->updateDepsgraph) {
- DepsNodeHandle handle = create_node_handle(geom_init_key);
+ DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
mti->updateDepsgraph(md, &ctx);
}
if (BKE_object_modifier_use_time(object, md)) {
TimeSourceKey time_src_key;
- add_relation(time_src_key, geom_init_key, "Time Source");
+ add_relation(time_src_key, obdata_ubereval_key, "Time Source");
}
}
}
@@ -2113,13 +2110,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(
(GpencilModifierType)md->type);
if (mti->updateDepsgraph) {
- DepsNodeHandle handle = create_node_handle(geom_init_key);
+ DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
mti->updateDepsgraph(md, &ctx, graph_->mode);
}
if (BKE_object_modifier_gpencil_use_time(object, md)) {
TimeSourceKey time_src_key;
- add_relation(time_src_key, geom_init_key, "Time Source");
+ add_relation(time_src_key, obdata_ubereval_key, "Time Source");
}
}
}
@@ -2131,13 +2128,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
LISTBASE_FOREACH (ShaderFxData *, fx, &object->shader_fx) {
const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info((ShaderFxType)fx->type);
if (fxi->updateDepsgraph) {
- DepsNodeHandle handle = create_node_handle(geom_init_key);
+ DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
fxi->updateDepsgraph(fx, &ctx);
}
if (BKE_object_shaderfx_use_time(object, fx)) {
TimeSourceKey time_src_key;
- add_relation(time_src_key, geom_init_key, "Time Source");
+ add_relation(time_src_key, obdata_ubereval_key, "Time Source");
}
}
}
@@ -2163,7 +2160,6 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
add_relation(mom_transform_key, mom_geom_key, "Metaball Motherball Transform -> Geometry");
}
else {
- ComponentKey geom_key(&object->id, NodeType::GEOMETRY);
ComponentKey transform_key(&object->id, NodeType::TRANSFORM);
add_relation(geom_key, mom_geom_key, "Metaball Motherball");
add_relation(transform_key, mom_geom_key, "Metaball Motherball");
@@ -2178,7 +2174,9 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
* Ideally we need to get rid of this relation. */
if (object_particles_depends_on_time(object)) {
TimeSourceKey time_key;
- add_relation(time_key, geom_init_key, "Legacy particle time");
+ OperationKey obdata_ubereval_key(
+ &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ add_relation(time_key, obdata_ubereval_key, "Legacy particle time");
}
/* Object data data-block. */
build_object_data_geometry_datablock((ID *)object->data);
@@ -2200,33 +2198,12 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
add_relation(final_geometry_key, synchronize_key, "Synchronize to Original");
/* Batch cache. */
OperationKey object_data_select_key(
- obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_SELECT);
+ obdata, NodeType::BATCH_CACHE, OperationCode::GEOMETRY_SELECT_UPDATE);
OperationKey object_select_key(
- &object->id, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_SELECT);
-
+ &object->id, NodeType::BATCH_CACHE, OperationCode::GEOMETRY_SELECT_UPDATE);
add_relation(object_data_select_key, object_select_key, "Data Selection -> Object Selection");
- add_relation(final_geometry_key,
- object_select_key,
- "Object Geometry -> Select Update",
- RELATION_FLAG_NO_FLUSH);
-
- OperationKey object_data_geom_deform_key(
- obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM);
- OperationKey object_data_geom_init_key(
- obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
-
- OperationKey object_data_batch_deform_key(
- obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_DEFORM);
- OperationKey object_data_batch_all_key(
- obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_ALL);
-
- add_relation(geom_init_key, object_data_batch_all_key, "Object Geometry -> Batch Update All");
-
add_relation(
- object_data_geom_init_key, object_data_batch_all_key, "Data Init -> Batch Update All");
- add_relation(object_data_geom_deform_key,
- object_data_batch_deform_key,
- "Data Deform -> Batch Update Deform");
+ geom_key, object_select_key, "Object Geometry -> Select Update", RELATION_FLAG_NO_FLUSH);
}
void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
@@ -2244,13 +2221,8 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
build_shapekeys(key);
}
/* Link object data evaluation node to exit operation. */
- OperationKey obdata_geom_deform_key(
- obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM);
- OperationKey obdata_geom_init_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
OperationKey obdata_geom_eval_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
OperationKey obdata_geom_done_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DONE);
- add_relation(obdata_geom_init_key, obdata_geom_eval_key, "ObData Init -> Geom Eval");
- add_relation(obdata_geom_deform_key, obdata_geom_eval_key, "ObData Deform -> Geom Eval");
add_relation(obdata_geom_eval_key, obdata_geom_done_key, "ObData Geom Eval Done");
/* Type-specific links. */
const ID_Type id_type = GS(obdata->name);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 8e3960e1a15..bdabd67cc07 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -153,8 +153,8 @@ bool RNANodeQuery::contains(const char *prop_identifier, const char *rna_path_co
return false;
}
- // If substr != prop_identifier, it means that the substring is found further in prop_identifier,
- // and that thus index -1 is a valid memory location.
+ /* If substr != prop_identifier, it means that the substring is found further in prop_identifier,
+ * and that thus index -1 is a valid memory location. */
const bool start_ok = substr == prop_identifier || substr[-1] == '.';
if (!start_ok) {
return false;
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 34b33e9a6c0..ab93464d09a 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -117,7 +117,7 @@ void depsgraph_select_tag_to_component_opcode(const ID *id,
}
else if (is_selectable_data_id_type(id_type)) {
*component_type = NodeType::BATCH_CACHE;
- *operation_code = OperationCode::BATCH_UPDATE_SELECT;
+ *operation_code = OperationCode::GEOMETRY_SELECT_UPDATE;
}
else {
*component_type = NodeType::COPY_ON_WRITE;
@@ -168,11 +168,6 @@ void depsgraph_tag_to_component_opcode(const ID *id,
break;
case ID_RECALC_GEOMETRY:
depsgraph_geometry_tag_to_component(id, component_type);
- *operation_code = OperationCode::GEOMETRY_EVAL_INIT;
- break;
- case ID_RECALC_GEOMETRY_DEFORM:
- depsgraph_geometry_tag_to_component(id, component_type);
- *operation_code = OperationCode::GEOMETRY_EVAL_DEFORM;
break;
case ID_RECALC_ANIMATION:
*component_type = NodeType::ANIMATION;
@@ -713,8 +708,6 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
return "GEOMETRY";
case ID_RECALC_GEOMETRY_ALL_MODES:
return "GEOMETRY_ALL_MODES";
- case ID_RECALC_GEOMETRY_DEFORM:
- return "GEOMETRY_DEFORM";
case ID_RECALC_ANIMATION:
return "ANIMATION";
case ID_RECALC_PSYS_REDO:
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index 915b9fedcec..ad88cf656ad 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -103,7 +103,7 @@ void evaluate_node(const DepsgraphEvalState *state, OperationNode *operation_nod
::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(state->graph);
/* Sanity checks. */
- BLI_assert(!operation_node->is_noop() && "NOOP nodes should not actually be scheduled");
+ BLI_assert_msg(!operation_node->is_noop(), "NOOP nodes should not actually be scheduled");
/* Perform operation. */
if (state->do_stats) {
const double start_time = PIL_check_seconds_timer();
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 346eba5bbc2..a844d23b558 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -348,7 +348,7 @@ bool scene_copy_inplace_no_main(const Scene *scene, Scene *new_scene)
/* For the given scene get view layer which corresponds to an original for the
* scene's evaluated one. This depends on how the scene is pulled into the
- * dependency graph. */
+ * dependency graph. */
ViewLayer *get_original_view_layer(const Depsgraph *depsgraph, const IDNode *id_node)
{
if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) {
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index 2cbb0b52e34..a015491e2d7 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -58,15 +58,15 @@
#include "intern/eval/deg_eval_copy_on_write.h"
-// Invalidate data-block data when update is flushed on it.
-//
-// The idea of this is to help catching cases when area is accessing data which
-// is not yet evaluated, which could happen due to missing relations. The issue
-// is that usually that data will be kept from previous frame, and it looks to
-// be plausible.
-//
-// This ensures that data does not look plausible, making it much easier to
-// catch usage of invalid state.
+/* Invalidate data-block data when update is flushed on it.
+ *
+ * The idea of this is to help catching cases when area is accessing data which
+ * is not yet evaluated, which could happen due to missing relations. The issue
+ * is that usually that data will be kept from previous frame, and it looks to
+ * be plausible.
+ *
+ * This ensures that data does not look plausible, making it much easier to
+ * catch usage of invalid state. */
#undef INVALIDATE_ON_FLUSH
namespace blender::deg {
@@ -144,10 +144,7 @@ inline void flush_handle_component_node(IDNode *id_node,
* special component where we don't want all operations to be tagged.
*
* TODO(sergey): Make this a more generic solution. */
- if (!ELEM(comp_node->type,
- NodeType::PARTICLE_SETTINGS,
- NodeType::PARTICLE_SYSTEM,
- NodeType::BATCH_CACHE)) {
+ if (!ELEM(comp_node->type, NodeType::PARTICLE_SETTINGS, NodeType::PARTICLE_SYSTEM)) {
for (OperationNode *op : comp_node->operations) {
op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
}
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index d98486b83a8..c25dc6fc8d5 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -98,8 +98,6 @@ const char *operationCodeAsString(OperationCode opcode)
/* Geometry. */
case OperationCode::GEOMETRY_EVAL_INIT:
return "GEOMETRY_EVAL_INIT";
- case OperationCode::GEOMETRY_EVAL_DEFORM:
- return "GEOMETRY_EVAL_DEFORM";
case OperationCode::GEOMETRY_EVAL:
return "GEOMETRY_EVAL";
case OperationCode::GEOMETRY_EVAL_DONE:
@@ -162,12 +160,8 @@ const char *operationCodeAsString(OperationCode opcode)
case OperationCode::FILE_CACHE_UPDATE:
return "FILE_CACHE_UPDATE";
/* Batch cache. */
- case OperationCode::BATCH_UPDATE_SELECT:
- return "BATCH_UPDATE_SELECT";
- case OperationCode::BATCH_UPDATE_DEFORM:
- return "BATCH_UPDATE_DEFORM";
- case OperationCode::BATCH_UPDATE_ALL:
- return "BATCH_UPDATE_ALL";
+ case OperationCode::GEOMETRY_SELECT_UPDATE:
+ return "GEOMETRY_SELECT_UPDATE";
/* Masks. */
case OperationCode::MASK_ANIMATION:
return "MASK_ANIMATION";
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h
index b0130d03c69..a17186da941 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.h
@@ -100,11 +100,7 @@ enum class OperationCode {
/* Initialize evaluation of the geometry. Is an entry operation of geometry
* component. */
GEOMETRY_EVAL_INIT,
- /* Evaluate the geometry, including modifiers, and update only batches that
- * are affected by deform operations. */
- GEOMETRY_EVAL_DEFORM,
- /* Evaluate the geometry, including modifiers, but don't update the batch
- * cache. */
+ /* Evaluate the whole geometry, including modifiers. */
GEOMETRY_EVAL,
/* Evaluation of geometry is completely done. */
GEOMETRY_EVAL_DONE,
@@ -182,9 +178,7 @@ enum class OperationCode {
WORLD_UPDATE,
/* Batch caches. -------------------------------------------------------- */
- BATCH_UPDATE_SELECT,
- BATCH_UPDATE_DEFORM,
- BATCH_UPDATE_ALL,
+ GEOMETRY_SELECT_UPDATE,
/* Masks. --------------------------------------------------------------- */
MASK_ANIMATION,
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index b7bcd127859..48c24d138e6 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -192,7 +192,7 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
gpumat, stl->effects->sss_sample_count, &sss_tex_profile);
if (!sss_profile) {
- BLI_assert(0 && "SSS pass requested but no SSS data was found");
+ BLI_assert_msg(0, "SSS pass requested but no SSS data was found");
return;
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
index b1368f90846..36a52e05a4a 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
@@ -327,7 +327,7 @@ vec2 safe_normalize_len(vec2 v, out float len)
float stroke_thickness_modulate(float thickness)
{
- /* Modify stroke thickness by object and layer factors.-*/
+ /* Modify stroke thickness by object and layer factors. */
thickness *= thicknessScale;
thickness += thicknessOffset;
thickness = max(1.0, thickness);
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
index e3f01d968ae..b50dc08bb97 100644
--- a/source/blender/draw/engines/overlay/overlay_outline.c
+++ b/source/blender/draw/engines/overlay/overlay_outline.c
@@ -340,7 +340,7 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
if (shgroup && geom) {
if (ob->type == OB_POINTCLOUD) {
- /* Draw range to avoid drawcall batching messing up the instance attrib. */
+ /* Draw range to avoid drawcall batching messing up the instance attribute. */
DRW_shgroup_call_instance_range(shgroup, ob, geom, 0, 0);
}
else {
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index e9d6763fbe9..f09c019ef8d 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -128,7 +128,7 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd,
BLI_INLINE void workbench_object_drawcall(DRWShadingGroup *grp, struct GPUBatch *geom, Object *ob)
{
if (ob->type == OB_POINTCLOUD) {
- /* Draw range to avoid drawcall batching messing up the instance attrib. */
+ /* Draw range to avoid drawcall batching messing up the instance attribute. */
DRW_shgroup_call_instance_range(grp, ob, geom, 0, 0);
}
else {
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index f5b95ac97ff..cd8b6531037 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -327,7 +327,7 @@ typedef enum {
/** Culling test */
DRW_STATE_CULL_BACK = (1 << 7),
DRW_STATE_CULL_FRONT = (1 << 8),
- /** Stencil test . These options are mutually exclusive and packed into 2 bits. */
+ /** Stencil test. These options are mutually exclusive and packed into 2 bits. */
DRW_STATE_STENCIL_ALWAYS = (1 << 9),
DRW_STATE_STENCIL_EQUAL = (2 << 9),
DRW_STATE_STENCIL_NEQUAL = (3 << 9),
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index a2e8dc20907..000ab540813 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -770,9 +770,9 @@ GPUBatch *DRW_cache_normal_arrow_get(void)
}
/* -------------------------------------------------------------------- */
-/** \name Dummy vbos
+/** \name Dummy VBO's
*
- * We need a dummy vbo containing the vertex count to draw instances ranges.
+ * We need a dummy VBO containing the vertex count to draw instances ranges.
*
* \{ */
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index a0694a08f0b..7dc468d1a73 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -81,11 +81,12 @@ typedef enum eMRDataType {
MR_DATA_POLY_NOR = 1 << 1,
MR_DATA_LOOP_NOR = 1 << 2,
MR_DATA_LOOPTRI = 1 << 3,
+ MR_DATA_LOOSE_GEOM = 1 << 4,
/** Force loop normals calculation. */
- MR_DATA_TAN_LOOP_NOR = 1 << 4,
- MR_DATA_MAT_OFFSETS = 1 << 5,
+ MR_DATA_TAN_LOOP_NOR = 1 << 5,
+ MR_DATA_POLYS_SORTED = 1 << 6,
} eMRDataType;
-ENUM_OPERATORS(eMRDataType, MR_DATA_MAT_OFFSETS)
+ENUM_OPERATORS(eMRDataType, MR_DATA_POLYS_SORTED)
#ifdef __cplusplus
extern "C" {
@@ -169,10 +170,10 @@ typedef struct MeshBufferExtractionCache {
} loose_geom;
struct {
- int *tri;
+ int *tri_first_index;
+ int *mat_tri_len;
int visible_tri_len;
- } mat_offsets;
-
+ } poly_sorted;
} MeshBufferExtractionCache;
#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 344150014ed..8d8bb14d953 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -76,27 +76,23 @@ struct ExtractorRunData {
class ExtractorRunDatas : public Vector<ExtractorRunData> {
public:
- void filter_into(ExtractorRunDatas &result, eMRIterType iter_type) const
+ void filter_into(ExtractorRunDatas &result, eMRIterType iter_type, const bool is_mesh) const
{
for (const ExtractorRunData &data : *this) {
const MeshExtract *extractor = data.extractor;
- if ((iter_type & MR_ITER_LOOPTRI) && extractor->iter_looptri_bm) {
- BLI_assert(extractor->iter_looptri_mesh);
+ if ((iter_type & MR_ITER_LOOPTRI) && *(&extractor->iter_looptri_bm + is_mesh)) {
result.append(data);
continue;
}
- if ((iter_type & MR_ITER_POLY) && extractor->iter_poly_bm) {
- BLI_assert(extractor->iter_poly_mesh);
+ if ((iter_type & MR_ITER_POLY) && *(&extractor->iter_poly_bm + is_mesh)) {
result.append(data);
continue;
}
- if ((iter_type & MR_ITER_LEDGE) && extractor->iter_ledge_bm) {
- BLI_assert(extractor->iter_ledge_mesh);
+ if ((iter_type & MR_ITER_LEDGE) && *(&extractor->iter_ledge_bm + is_mesh)) {
result.append(data);
continue;
}
- if ((iter_type & MR_ITER_LVERT) && extractor->iter_lvert_bm) {
- BLI_assert(extractor->iter_lvert_mesh);
+ if ((iter_type & MR_ITER_LVERT) && *(&extractor->iter_lvert_bm + is_mesh)) {
result.append(data);
continue;
}
@@ -427,7 +423,7 @@ BLI_INLINE void extract_task_range_run_iter(const MeshRenderData *mr,
return;
}
- extractors->filter_into(range_data.extractors, iter_type);
+ extractors->filter_into(range_data.extractors, iter_type, is_mesh);
BLI_task_parallel_range(0, stop, &range_data, func, settings);
}
@@ -535,7 +531,8 @@ static void mesh_extract_render_data_node_exec(void *__restrict task_data)
mesh_render_data_update_normals(mr, data_flag);
mesh_render_data_update_looptris(mr, iter_type, data_flag);
- mesh_render_data_update_mat_offsets(mr, update_task_data->cache, data_flag);
+ mesh_render_data_update_loose_geom(mr, update_task_data->cache, iter_type, data_flag);
+ mesh_render_data_update_polys_sorted(mr, update_task_data->cache, data_flag);
}
static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph,
@@ -689,19 +686,8 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
double rdata_start = PIL_check_seconds_timer();
#endif
- eMRIterType iter_type = extractors.iter_types();
- eMRDataType data_flag = extractors.data_types();
-
- MeshRenderData *mr = mesh_render_data_create(me,
- extraction_cache,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- obmat,
- do_final,
- do_uvedit,
- ts,
- iter_type);
+ MeshRenderData *mr = mesh_render_data_create(
+ me, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts);
mr->use_hide = use_hide;
mr->use_subsurf_fdots = use_subsurf_fdots;
mr->use_final_mesh = do_final;
@@ -710,6 +696,9 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
double rdata_end = PIL_check_seconds_timer();
#endif
+ eMRIterType iter_type = extractors.iter_types();
+ eMRDataType data_flag = extractors.data_types();
+
struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create(
task_graph, mr, extraction_cache, iter_type, data_flag);
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_private.h b/source/blender/draw/intern/draw_cache_extract_mesh_private.h
index 5f670bdc5ec..f24ccf1a028 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_private.h
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h
@@ -101,10 +101,12 @@ typedef struct MeshRenderData {
float (*loop_normals)[3];
float (*poly_normals)[3];
int *lverts, *ledges;
+
struct {
- int *tri;
+ int *tri_first_index;
+ int *mat_tri_len;
int visible_tri_len;
- } mat_offsets;
+ } poly_sorted;
} MeshRenderData;
BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
@@ -240,20 +242,22 @@ typedef struct MeshExtract {
/* draw_cache_extract_mesh_render_data.c */
MeshRenderData *mesh_render_data_create(Mesh *me,
- MeshBufferExtractionCache *cache,
const bool is_editmode,
const bool is_paint_mode,
const bool is_mode_active,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const ToolSettings *ts,
- const eMRIterType iter_type);
+ const ToolSettings *ts);
void mesh_render_data_free(MeshRenderData *mr);
void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag);
-void mesh_render_data_update_mat_offsets(MeshRenderData *mr,
- MeshBufferExtractionCache *cache,
- const eMRDataType data_flag);
+void mesh_render_data_update_loose_geom(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ const eMRIterType iter_type,
+ const eMRDataType data_flag);
+void mesh_render_data_update_polys_sorted(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ const eMRDataType data_flag);
void mesh_render_data_update_looptris(MeshRenderData *mr,
const eMRIterType iter_type,
const eMRDataType data_flag);
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
index bccf894cc53..987996ed696 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_alloca.h"
#include "BLI_bitmap.h"
#include "BLI_math.h"
#include "BLI_task.h"
@@ -165,119 +166,118 @@ static void mesh_render_data_ledges_bm(const MeshRenderData *mr,
}
}
+void mesh_render_data_update_loose_geom(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ const eMRIterType iter_type,
+ const eMRDataType data_flag)
+{
+ if ((iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) || (data_flag & MR_DATA_LOOSE_GEOM)) {
+ mesh_render_data_loose_geom_ensure(mr, cache);
+ mesh_render_data_loose_geom_load(mr, cache);
+ }
+}
+
/** \} */
/* ---------------------------------------------------------------------- */
-/** \name Material Offsets
+/** \name Polygons sorted per material
*
- * Material offsets contains the offset of a material after sorting tris based on their material.
+ * Contains polygon indices sorted based on their material.
*
* \{ */
-static void mesh_render_data_mat_offset_load(MeshRenderData *mr,
- const MeshBufferExtractionCache *cache);
-static void mesh_render_data_mat_offset_ensure(MeshRenderData *mr,
- MeshBufferExtractionCache *cache);
-static void mesh_render_data_mat_offset_build(MeshRenderData *mr,
- MeshBufferExtractionCache *cache);
-static void mesh_render_data_mat_offset_build_bm(MeshRenderData *mr,
+static void mesh_render_data_polys_sorted_load(MeshRenderData *mr,
+ const MeshBufferExtractionCache *cache);
+static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr,
MeshBufferExtractionCache *cache);
-static void mesh_render_data_mat_offset_build_mesh(MeshRenderData *mr,
- MeshBufferExtractionCache *cache);
-static void mesh_render_data_mat_offset_apply_offset(MeshRenderData *mr,
- MeshBufferExtractionCache *cache);
-
-void mesh_render_data_update_mat_offsets(MeshRenderData *mr,
- MeshBufferExtractionCache *cache,
- const eMRDataType data_flag)
+static void mesh_render_data_polys_sorted_build(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache);
+static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr);
+
+void mesh_render_data_update_polys_sorted(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ const eMRDataType data_flag)
{
- if (data_flag & MR_DATA_MAT_OFFSETS) {
- mesh_render_data_mat_offset_ensure(mr, cache);
- mesh_render_data_mat_offset_load(mr, cache);
+ if (data_flag & MR_DATA_POLYS_SORTED) {
+ mesh_render_data_polys_sorted_ensure(mr, cache);
+ mesh_render_data_polys_sorted_load(mr, cache);
}
}
-static void mesh_render_data_mat_offset_load(MeshRenderData *mr,
- const MeshBufferExtractionCache *cache)
+static void mesh_render_data_polys_sorted_load(MeshRenderData *mr,
+ const MeshBufferExtractionCache *cache)
{
- mr->mat_offsets.tri = cache->mat_offsets.tri;
- mr->mat_offsets.visible_tri_len = cache->mat_offsets.visible_tri_len;
+ mr->poly_sorted.tri_first_index = cache->poly_sorted.tri_first_index;
+ mr->poly_sorted.mat_tri_len = cache->poly_sorted.mat_tri_len;
+ mr->poly_sorted.visible_tri_len = cache->poly_sorted.visible_tri_len;
}
-static void mesh_render_data_mat_offset_ensure(MeshRenderData *mr,
- MeshBufferExtractionCache *cache)
+static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache)
{
- if (cache->mat_offsets.tri) {
+ if (cache->poly_sorted.tri_first_index) {
return;
}
- mesh_render_data_mat_offset_build(mr, cache);
+ mesh_render_data_polys_sorted_build(mr, cache);
}
-static void mesh_render_data_mat_offset_build(MeshRenderData *mr, MeshBufferExtractionCache *cache)
+static void mesh_render_data_polys_sorted_build(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache)
{
- size_t mat_tri_idx_size = sizeof(int) * mr->mat_len;
- cache->mat_offsets.tri = MEM_callocN(mat_tri_idx_size, __func__);
+ int *tri_first_index = MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__);
+ int *mat_tri_len = mesh_render_data_mat_tri_len_build(mr);
+
+ /* Apply offset. */
+ int visible_tri_len = 0;
+ int *mat_tri_offs = BLI_array_alloca(mat_tri_offs, mr->mat_len);
+ {
+ for (int i = 0; i < mr->mat_len; i++) {
+ mat_tri_offs[i] = visible_tri_len;
+ visible_tri_len += mat_tri_len[i];
+ }
+ }
- /* Count how many triangles for each material. */
+ /* Sort per material. */
+ int mat_last = mr->mat_len - 1;
if (mr->extract_type == MR_EXTRACT_BMESH) {
- mesh_render_data_mat_offset_build_bm(mr, cache);
+ BMIter iter;
+ BMFace *f;
+ int i;
+ BM_ITER_MESH_INDEX (f, &iter, mr->bm, BM_FACES_OF_MESH, i) {
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ const int mat = min_ii(f->mat_nr, mat_last);
+ tri_first_index[i] = mat_tri_offs[mat];
+ mat_tri_offs[mat] += f->len - 2;
+ }
+ else {
+ tri_first_index[i] = -1;
+ }
+ }
}
else {
- mesh_render_data_mat_offset_build_mesh(mr, cache);
- }
-
- mesh_render_data_mat_offset_apply_offset(mr, cache);
-}
-
-typedef struct MatOffsetUserData {
- MeshRenderData *mr;
- /** This struct is extended during allocation to hold mat_tri_len for each material. */
- int mat_tri_len[0];
-} MatOffsetUserData;
-
-static void mesh_render_data_mat_offset_reduce(const void *__restrict UNUSED(userdata),
- void *__restrict chunk_join,
- void *__restrict chunk)
-{
- MatOffsetUserData *dst = chunk_join;
- MatOffsetUserData *src = chunk;
- int *dst_mat_len = dst->mat_tri_len;
- int *src_mat_len = src->mat_tri_len;
- for (int i = 0; i < dst->mr->mat_len; i++) {
- dst_mat_len[i] += src_mat_len[i];
+ const MPoly *mp = &mr->mpoly[0];
+ for (int i = 0; i < mr->poly_len; i++, mp++) {
+ if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
+ const int mat = min_ii(mp->mat_nr, mat_last);
+ tri_first_index[i] = mat_tri_offs[mat];
+ mat_tri_offs[mat] += mp->totloop - 2;
+ }
+ else {
+ tri_first_index[i] = -1;
+ }
+ }
}
-}
-
-static void mesh_render_data_mat_offset_build_threaded(MeshRenderData *mr,
- MeshBufferExtractionCache *cache,
- int face_len,
- TaskParallelRangeFunc range_func)
-{
- /* Extending the #MatOffsetUserData with an int per material slot. */
- size_t userdata_size = sizeof(MatOffsetUserData) +
- (mr->mat_len) * sizeof(*cache->mat_offsets.tri);
- MatOffsetUserData *userdata = MEM_callocN(userdata_size, __func__);
- userdata->mr = mr;
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.userdata_chunk = userdata;
- settings.userdata_chunk_size = userdata_size;
- settings.min_iter_per_thread = MIN_RANGE_LEN;
- settings.func_reduce = mesh_render_data_mat_offset_reduce;
- BLI_task_parallel_range(0, face_len, NULL, range_func, &settings);
- memcpy(cache->mat_offsets.tri,
- &userdata->mat_tri_len,
- (mr->mat_len) * sizeof(*cache->mat_offsets.tri));
- MEM_freeN(userdata);
+ cache->poly_sorted.tri_first_index = tri_first_index;
+ cache->poly_sorted.mat_tri_len = mat_tri_len;
+ cache->poly_sorted.visible_tri_len = visible_tri_len;
}
-static void mesh_render_data_mat_offset_bm_range(void *__restrict UNUSED(userdata),
- const int iter,
- const TaskParallelTLS *__restrict tls)
+static void mesh_render_data_mat_tri_len_bm_range_fn(void *__restrict userdata,
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
{
- MatOffsetUserData *mat_offset_userdata = tls->userdata_chunk;
- MeshRenderData *mr = mat_offset_userdata->mr;
- int *mat_tri_len = mat_offset_userdata->mat_tri_len;
+ MeshRenderData *mr = userdata;
+ int *mat_tri_len = tls->userdata_chunk;
BMesh *bm = mr->bm;
BMFace *efa = BM_face_at_index(bm, iter);
@@ -287,21 +287,12 @@ static void mesh_render_data_mat_offset_bm_range(void *__restrict UNUSED(userdat
}
}
-static void mesh_render_data_mat_offset_build_bm(MeshRenderData *mr,
- MeshBufferExtractionCache *cache)
+static void mesh_render_data_mat_tri_len_mesh_range_fn(void *__restrict userdata,
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
{
- BMesh *bm = mr->bm;
- mesh_render_data_mat_offset_build_threaded(
- mr, cache, bm->totface, mesh_render_data_mat_offset_bm_range);
-}
-
-static void mesh_render_data_mat_offset_mesh_range(void *__restrict UNUSED(userdata),
- const int iter,
- const TaskParallelTLS *__restrict tls)
-{
- MatOffsetUserData *mat_offset_userdata = tls->userdata_chunk;
- const MeshRenderData *mr = mat_offset_userdata->mr;
- int *mat_tri_len = mat_offset_userdata->mat_tri_len;
+ MeshRenderData *mr = userdata;
+ int *mat_tri_len = tls->userdata_chunk;
const MPoly *mp = &mr->mpoly[iter];
if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
@@ -310,25 +301,49 @@ static void mesh_render_data_mat_offset_mesh_range(void *__restrict UNUSED(userd
}
}
-static void mesh_render_data_mat_offset_build_mesh(MeshRenderData *mr,
- MeshBufferExtractionCache *cache)
+static void mesh_render_data_mat_tri_len_reduce_fn(const void *__restrict userdata,
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ const MeshRenderData *mr = userdata;
+ int *dst_mat_len = chunk_join;
+ int *src_mat_len = chunk;
+ for (int i = 0; i < mr->mat_len; i++) {
+ dst_mat_len[i] += src_mat_len[i];
+ }
+}
+
+static int *mesh_render_data_mat_tri_len_build_threaded(MeshRenderData *mr,
+ int face_len,
+ TaskParallelRangeFunc range_func)
{
- mesh_render_data_mat_offset_build_threaded(
- mr, cache, mr->poly_len, mesh_render_data_mat_offset_mesh_range);
+ /* Extending the #MatOffsetUserData with an int per material slot. */
+ size_t mat_tri_len_size = sizeof(int) * mr->mat_len;
+ int *mat_tri_len = MEM_callocN(mat_tri_len_size, __func__);
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.userdata_chunk = mat_tri_len;
+ settings.userdata_chunk_size = mat_tri_len_size;
+ settings.min_iter_per_thread = MIN_RANGE_LEN;
+ settings.func_reduce = mesh_render_data_mat_tri_len_reduce_fn;
+ BLI_task_parallel_range(0, face_len, mr, range_func, &settings);
+
+ return mat_tri_len;
}
-static void mesh_render_data_mat_offset_apply_offset(MeshRenderData *mr,
- MeshBufferExtractionCache *cache)
+/* Count how many triangles for each material. */
+static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr)
{
- int *mat_tri_len = cache->mat_offsets.tri;
- int ofs = mat_tri_len[0];
- mat_tri_len[0] = 0;
- for (int i = 1; i < mr->mat_len; i++) {
- int tmp = mat_tri_len[i];
- mat_tri_len[i] = ofs;
- ofs += tmp;
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMesh *bm = mr->bm;
+ return mesh_render_data_mat_tri_len_build_threaded(
+ mr, bm->totface, mesh_render_data_mat_tri_len_bm_range_fn);
+ }
+ else {
+ return mesh_render_data_mat_tri_len_build_threaded(
+ mr, mr->poly_len, mesh_render_data_mat_tri_len_mesh_range_fn);
}
- cache->mat_offsets.visible_tri_len = ofs;
}
/** \} */
@@ -447,15 +462,13 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
* otherwise don't use modifiers as they are not from this object.
*/
MeshRenderData *mesh_render_data_create(Mesh *me,
- MeshBufferExtractionCache *cache,
const bool is_editmode,
const bool is_paint_mode,
const bool is_mode_active,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const ToolSettings *ts,
- const eMRIterType iter_type)
+ const ToolSettings *ts)
{
MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
mr->toolsettings = ts;
@@ -565,11 +578,6 @@ MeshRenderData *mesh_render_data_create(Mesh *me,
mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
}
- if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
- mesh_render_data_loose_geom_ensure(mr, cache);
- mesh_render_data_loose_geom_load(mr, cache);
- }
-
return mr;
}
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc
index 51bd4c535cd..1efe0c080be 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curve.cc
@@ -663,7 +663,7 @@ static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_c
for (const int i_spline : splines.index_range()) {
const int eval_size = splines[i_spline]->evaluated_points_size();
- if (splines[i_spline]->is_cyclic()) {
+ if (splines[i_spline]->is_cyclic() && splines[i_spline]->evaluated_edges_size() > 1) {
GPU_indexbuf_add_generic_vert(&elb, offsets[i_spline] + eval_size - 1);
}
for (const int i_point : IndexRange(eval_size)) {
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 0c002ff09f2..38ecdf7756b 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -821,17 +821,6 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
mesh_batch_cache_discard_shaded_tri(cache);
mesh_batch_cache_discard_uvedit(cache);
break;
- case BKE_MESH_BATCH_DIRTY_DEFORM:
- FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
- GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor);
- GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.lnor);
- GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_pos);
- GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_nor);
- GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.tris);
- }
- batch_map = MDEPS_CREATE_MAP(vbo.pos_nor, vbo.lnor, vbo.fdots_pos, vbo.fdots_nor, ibo.tris);
- mesh_batch_cache_discard_batch(cache, batch_map);
- break;
case BKE_MESH_BATCH_DIRTY_UVEDIT_ALL:
mesh_batch_cache_discard_uvedit(cache);
break;
@@ -867,7 +856,9 @@ static void mesh_buffer_extraction_cache_clear(MeshBufferExtractionCache *extrac
extraction_cache->loose_geom.edge_len = 0;
extraction_cache->loose_geom.vert_len = 0;
- MEM_SAFE_FREE(extraction_cache->mat_offsets.tri);
+ MEM_SAFE_FREE(extraction_cache->poly_sorted.tri_first_index);
+ MEM_SAFE_FREE(extraction_cache->poly_sorted.mat_tri_len);
+ extraction_cache->poly_sorted.visible_tri_len = 0;
}
static void mesh_batch_cache_clear(Mesh *me)
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index 449f2cd9606..e055192eb21 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -80,7 +80,7 @@ typedef struct DRWTempInstancingHandle {
GPUBatch *batch;
/** Batch containing instancing attributes. */
GPUBatch *instancer;
- /** Callbuffer to be used instead of instancer . */
+ /** Callbuffer to be used instead of instancer. */
GPUVertBuf *buf;
/** Original non-instanced batch pointer. */
GPUBatch *geom;
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 6f5e041fa79..35072518b66 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -147,7 +147,7 @@ static bool drw_draw_show_annotation(void)
* the draw manager is only used to draw the background. */
return false;
default:
- BLI_assert("");
+ BLI_assert(0);
return false;
}
}
@@ -2253,7 +2253,7 @@ static void draw_select_framebuffer_depth_only_setup(const int size[2])
/* Must run after all instance datas have been added. */
void DRW_render_instance_buffer_finish(void)
{
- BLI_assert(!DST.buffer_finish_called && "DRW_render_instance_buffer_finish called twice!");
+ BLI_assert_msg(!DST.buffer_finish_called, "DRW_render_instance_buffer_finish called twice!");
DST.buffer_finish_called = true;
DRW_instance_buffer_finish(DST.idatalist);
drw_resource_buffer_finish(DST.vmempool);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 0a0e1ba9ac3..b001c5bbf8f 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -74,7 +74,7 @@ static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_l
return;
}
}
- /* Cumulate batch indices */
+ /* Accumulate batch indices */
for (int i = 1; i < ARRAY_SIZE(idx); i++) {
idx[i] += idx[i - 1];
}
@@ -453,7 +453,7 @@ void DRW_shgroup_vertex_buffer(DRWShadingGroup *shgroup,
{
int location = GPU_shader_get_ssbo(shgroup->shader, name);
if (location == -1) {
- BLI_assert(false && "Unable to locate binding of shader storage buffer objects.");
+ BLI_assert_msg(0, "Unable to locate binding of shader storage buffer objects.");
return;
}
drw_shgroup_uniform_create_ex(
diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c
index 6c63838201e..265fdba66fd 100644
--- a/source/blender/draw/intern/draw_manager_text.c
+++ b/source/blender/draw/intern/draw_manager_text.c
@@ -266,7 +266,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
}
const short edge_tex_sep = (short)((edge_tex_count - 1) * 5.0f * U.dpi_fac);
- /* make the precision of the display value proportionate to the gridsize */
+ /* Make the precision of the display value proportionate to the grid-size. */
if (grid <= 0.01f) {
conv_float = "%.6g";
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 2c2603af1b2..6c677debf88 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
@@ -237,7 +237,7 @@ constexpr MeshExtract create_extractor_lines_loose_only()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_lines_loose_only_init;
- extractor.data_type = MR_DATA_NONE;
+ extractor.data_type = MR_DATA_LOOSE_GEOM;
extractor.data_size = 0;
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_loose);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
index 93f71f920eb..3b2da9879c5 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
@@ -27,59 +27,70 @@
namespace blender::draw {
+static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_from)
+{
+ GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to);
+ GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from);
+ GPU_indexbuf_join(elb_to, elb_from);
+}
+
/* ---------------------------------------------------------------------- */
/** \name Extract Triangles Indices (multi material)
* \{ */
-struct MeshExtract_Tri_Data {
- GPUIndexBufBuilder elb;
- const int *tri_mat_start;
- int *tri_mat_end;
-};
-
static void extract_tris_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
- MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(tls_data);
- data->tri_mat_start = mr->mat_offsets.tri;
- data->tri_mat_end = static_cast<int *>(MEM_dupallocN(data->tri_mat_start));
- GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, mr->mat_offsets.visible_tri_len, mr->loop_len);
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
+ GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr->poly_sorted.visible_tri_len, mr->loop_len);
}
-static void extract_tris_iter_looptri_bm(const MeshRenderData *mr,
- BMLoop **elt,
- const int UNUSED(elt_index),
- void *_data)
+static void extract_tris_iter_poly_bm(const MeshRenderData *mr,
+ const BMFace *f,
+ const int f_index,
+ void *_data)
{
- MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(_data);
- const int mat_last = mr->mat_len - 1;
+ int tri_first_index = mr->poly_sorted.tri_first_index[f_index];
+ if (tri_first_index == -1) {
+ return;
+ }
- if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
- int *mat_tri_ofs = data->tri_mat_end;
- const int mat = min_ii(elt[0]->f->mat_nr, mat_last);
- GPU_indexbuf_set_tri_verts(&data->elb,
- mat_tri_ofs[mat]++,
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
+ int tri_first_index_real = poly_to_tri_count(f_index, BM_elem_index_get(f->l_first));
+
+ struct BMLoop *(*looptris)[3] = mr->edit_bmesh->looptris;
+ int tri_len = f->len - 2;
+ for (int offs = 0; offs < tri_len; offs++) {
+ BMLoop **elt = looptris[tri_first_index_real + offs];
+ int tri_index = tri_first_index + offs;
+ GPU_indexbuf_set_tri_verts(elb,
+ tri_index,
BM_elem_index_get(elt[0]),
BM_elem_index_get(elt[1]),
BM_elem_index_get(elt[2]));
}
}
-static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr,
- const MLoopTri *mlt,
- const int UNUSED(elt_index),
- void *_data)
+static void extract_tris_iter_poly_mesh(const MeshRenderData *mr,
+ const MPoly *mp,
+ const int mp_index,
+ void *_data)
{
- MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(_data);
- const int mat_last = mr->mat_len - 1;
- const MPoly *mp = &mr->mpoly[mlt->poly];
- if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
- int *mat_tri_ofs = data->tri_mat_end;
- const int mat = min_ii(mp->mat_nr, mat_last);
- GPU_indexbuf_set_tri_verts(
- &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
+ int tri_first_index = mr->poly_sorted.tri_first_index[mp_index];
+ if (tri_first_index == -1) {
+ return;
+ }
+
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
+ int tri_first_index_real = poly_to_tri_count(mp_index, mp->loopstart);
+
+ int tri_len = mp->totloop - 2;
+ for (int offs = 0; offs < tri_len; offs++) {
+ const MLoopTri *mlt = &mr->mlooptri[tri_first_index_real + offs];
+ int tri_index = tri_first_index + offs;
+ GPU_indexbuf_set_tri_verts(elb, tri_index, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
}
}
@@ -89,40 +100,41 @@ static void extract_tris_finish(const MeshRenderData *mr,
void *_data)
{
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
- MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(_data);
- GPU_indexbuf_build_in_place(&data->elb, ibo);
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
+ GPU_indexbuf_build_in_place(elb, ibo);
/* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch
* is created before the surfaces-per-material. */
if (mr->use_final_mesh && cache->final.tris_per_mat) {
MeshBufferCache *mbc_final = &cache->final;
+ int mat_start = 0;
for (int i = 0; i < mr->mat_len; i++) {
/* These IBOs have not been queried yet but we create them just in case they are needed
* later since they are not tracked by mesh_buffer_cache_create_requested(). */
if (mbc_final->tris_per_mat[i] == nullptr) {
mbc_final->tris_per_mat[i] = GPU_indexbuf_calloc();
}
+ const int mat_tri_len = mr->poly_sorted.mat_tri_len[i];
/* Multiply by 3 because these are triangle indices. */
- const int mat_start = data->tri_mat_start[i];
- const int mat_end = data->tri_mat_end[i];
const int start = mat_start * 3;
- const int len = (mat_end - mat_start) * 3;
+ const int len = mat_tri_len * 3;
GPU_indexbuf_create_subrange_in_place(mbc_final->tris_per_mat[i], ibo, start, len);
+ mat_start += mat_tri_len;
}
}
- MEM_freeN(data->tri_mat_end);
}
constexpr MeshExtract create_extractor_tris()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_tris_init;
- extractor.iter_looptri_bm = extract_tris_iter_looptri_bm;
- extractor.iter_looptri_mesh = extract_tris_iter_looptri_mesh;
+ extractor.iter_poly_bm = extract_tris_iter_poly_bm;
+ extractor.iter_poly_mesh = extract_tris_iter_poly_mesh;
+ extractor.task_reduce = extract_tris_mat_task_reduce;
extractor.finish = extract_tris_finish;
- extractor.data_type = MR_DATA_MAT_OFFSETS;
- extractor.data_size = sizeof(MeshExtract_Tri_Data);
- extractor.use_threading = false;
+ extractor.data_type = MR_DATA_LOOPTRI | MR_DATA_POLYS_SORTED;
+ extractor.data_size = sizeof(GPUIndexBufBuilder);
+ extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris);
return extractor;
}
@@ -174,13 +186,6 @@ static void extract_tris_single_mat_iter_looptri_mesh(const MeshRenderData *mr,
}
}
-static void extract_tris_single_mat_task_reduce(void *_userdata_to, void *_userdata_from)
-{
- GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to);
- GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from);
- GPU_indexbuf_join(elb_to, elb_from);
-}
-
static void extract_tris_single_mat_finish(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buf,
@@ -213,7 +218,7 @@ constexpr MeshExtract create_extractor_tris_single_mat()
extractor.init = extract_tris_single_mat_init;
extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh;
- extractor.task_reduce = extract_tris_single_mat_task_reduce;
+ extractor.task_reduce = extract_tris_mat_task_reduce;
extractor.finish = extract_tris_single_mat_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(GPUIndexBufBuilder);
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index f50a5ffbb5e..7a53b54b5a4 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
keyframes_draw.c
keyframes_edit.c
keyframes_general.c
+ keyframes_keylist.c
keyframing.c
keyingsets.c
time_scrub_ui.c
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 2fcd59a1bbe..baf8adf28d0 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -48,6 +48,7 @@
#include "ED_anim_api.h"
#include "ED_keyframes_draw.h"
#include "ED_keyframes_edit.h"
+#include "ED_keyframes_keylist.h"
#include "RNA_access.h"
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 9d998326b4d..227af598f53 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -123,7 +123,7 @@ ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
* so don't assume anything.
* \param scene: Current scene (for getting current frame)
* \param mode: (TfmMode) transform mode that this transform is for
- * \param value: From the transform code, this is ``t->vec[0]``
+ * \param value: From the transform code, this is `t->vec[0]`
* (which is delta transform for grab/extend, and scale factor for scale)
* \param side: (B/L/R) for 'extend' functionality, which side of current frame to use
*/
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index 51a897600e1..bddd5dbff55 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -43,7 +43,7 @@
#include "GPU_vertex_buffer.h"
#include "ED_anim_api.h"
-#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "CLG_log.h"
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 06107b6fee6..4f512c9d7ca 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -24,28 +24,17 @@
/* System includes ----------------------------------------------------- */
#include <float.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
#include "BLI_dlrbTree.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_rect.h"
-#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_cachefile_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_mask_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_fcurve.h"
-
#include "GPU_immediate.h"
#include "GPU_state.h"
@@ -55,498 +44,7 @@
#include "ED_anim_api.h"
#include "ED_keyframes_draw.h"
-
-/* *************************** Keyframe Processing *************************** */
-
-/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
-
-BLI_INLINE bool is_cfra_eq(float a, float b)
-{
- return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
-}
-
-BLI_INLINE bool is_cfra_lt(float a, float b)
-{
- return (b - a) > BEZT_BINARYSEARCH_THRESH;
-}
-
-/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
-/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
-short compare_ak_cfraPtr(void *node, void *data)
-{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- const float *cframe = data;
- float val = *cframe;
-
- if (is_cfra_eq(val, ak->cfra)) {
- return 0;
- }
-
- if (val < ak->cfra) {
- return -1;
- }
- return 1;
-}
-
-/* --------------- */
-
-/* Set of references to three logically adjacent keys. */
-typedef struct BezTripleChain {
- /* Current keyframe. */
- BezTriple *cur;
-
- /* Logical neighbors. May be NULL. */
- BezTriple *prev, *next;
-} BezTripleChain;
-
-/* Categorize the interpolation & handle type of the keyframe. */
-static eKeyframeHandleDrawOpts bezt_handle_type(BezTriple *bezt)
-{
- if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM) {
- return KEYFRAME_HANDLE_AUTO_CLAMP;
- }
- if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) {
- return KEYFRAME_HANDLE_AUTO;
- }
- if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) {
- return KEYFRAME_HANDLE_VECTOR;
- }
- if (ELEM(HD_FREE, bezt->h1, bezt->h2)) {
- return KEYFRAME_HANDLE_FREE;
- }
- return KEYFRAME_HANDLE_ALIGNED;
-}
-
-/* Determine if the keyframe is an extreme by comparing with neighbors.
- * Ends of fixed-value sections and of the whole curve are also marked.
- */
-static eKeyframeExtremeDrawOpts bezt_extreme_type(BezTripleChain *chain)
-{
- if (chain->prev == NULL && chain->next == NULL) {
- return KEYFRAME_EXTREME_NONE;
- }
-
- /* Keyframe values for the current one and neighbors. */
- float cur_y = chain->cur->vec[1][1];
- float prev_y = cur_y, next_y = cur_y;
-
- if (chain->prev && !IS_EQF(cur_y, chain->prev->vec[1][1])) {
- prev_y = chain->prev->vec[1][1];
- }
- if (chain->next && !IS_EQF(cur_y, chain->next->vec[1][1])) {
- next_y = chain->next->vec[1][1];
- }
-
- /* Static hold. */
- if (prev_y == cur_y && next_y == cur_y) {
- return KEYFRAME_EXTREME_FLAT;
- }
-
- /* Middle of an incline. */
- if ((prev_y < cur_y && next_y > cur_y) || (prev_y > cur_y && next_y < cur_y)) {
- return KEYFRAME_EXTREME_NONE;
- }
-
- /* Bezier handle values for the overshoot check. */
- bool l_bezier = chain->prev && chain->prev->ipo == BEZT_IPO_BEZ;
- bool r_bezier = chain->next && chain->cur->ipo == BEZT_IPO_BEZ;
- float handle_l = l_bezier ? chain->cur->vec[0][1] : cur_y;
- float handle_r = r_bezier ? chain->cur->vec[2][1] : cur_y;
-
- /* Detect extremes. One of the neighbors is allowed to be equal to current. */
- if (prev_y < cur_y || next_y < cur_y) {
- bool is_overshoot = (handle_l > cur_y || handle_r > cur_y);
-
- return KEYFRAME_EXTREME_MAX | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
- }
-
- if (prev_y > cur_y || next_y > cur_y) {
- bool is_overshoot = (handle_l < cur_y || handle_r < cur_y);
-
- return KEYFRAME_EXTREME_MIN | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
- }
-
- return KEYFRAME_EXTREME_NONE;
-}
-
-/* Comparator callback used for ActKeyColumns and BezTripleChain */
-static short compare_ak_bezt(void *node, void *data)
-{
- BezTripleChain *chain = data;
-
- return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]);
-}
-
-/* New node callback used for building ActKeyColumns from BezTripleChain */
-static DLRBT_Node *nalloc_ak_bezt(void *data)
-{
- ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
- BezTripleChain *chain = data;
- BezTriple *bezt = chain->cur;
-
- /* store settings based on state of BezTriple */
- ak->cfra = bezt->vec[1][0];
- ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
- ak->key_type = BEZKEYTYPE(bezt);
- ak->handle_type = bezt_handle_type(bezt);
- ak->extreme_type = bezt_extreme_type(chain);
-
- /* count keyframes in this column */
- ak->totkey = 1;
-
- return (DLRBT_Node *)ak;
-}
-
-/* Node updater callback used for building ActKeyColumns from BezTripleChain */
-static void nupdate_ak_bezt(void *node, void *data)
-{
- ActKeyColumn *ak = node;
- BezTripleChain *chain = data;
- BezTriple *bezt = chain->cur;
-
- /* set selection status and 'touched' status */
- if (BEZT_ISSEL_ANY(bezt)) {
- ak->sel = SELECT;
- }
-
- /* count keyframes in this column */
- ak->totkey++;
-
- /* For keyframe type, 'proper' keyframes have priority over breakdowns
- * (and other types for now). */
- if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) {
- ak->key_type = BEZT_KEYTYPE_KEYFRAME;
- }
-
- /* For interpolation type, select the highest value (enum is sorted). */
- ak->handle_type = MAX2(ak->handle_type, bezt_handle_type(bezt));
-
- /* For extremes, detect when combining different states. */
- char new_extreme = bezt_extreme_type(chain);
-
- if (new_extreme != ak->extreme_type) {
- /* Replace the flat status without adding mixed. */
- if (ak->extreme_type == KEYFRAME_EXTREME_FLAT) {
- ak->extreme_type = new_extreme;
- }
- else if (new_extreme != KEYFRAME_EXTREME_FLAT) {
- ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED);
- }
- }
-}
-
-/* ......... */
-
-/* Comparator callback used for ActKeyColumns and GPencil frame */
-static short compare_ak_gpframe(void *node, void *data)
-{
- bGPDframe *gpf = (bGPDframe *)data;
-
- float frame = gpf->framenum;
- return compare_ak_cfraPtr(node, &frame);
-}
-
-/* New node callback used for building ActKeyColumns from GPencil frames */
-static DLRBT_Node *nalloc_ak_gpframe(void *data)
-{
- ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
- bGPDframe *gpf = (bGPDframe *)data;
-
- /* store settings based on state of BezTriple */
- ak->cfra = gpf->framenum;
- ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
- ak->key_type = gpf->key_type;
-
- /* count keyframes in this column */
- ak->totkey = 1;
- /* Set as visible block. */
- ak->totblock = 1;
- ak->block.sel = ak->sel;
- ak->block.flag |= ACTKEYBLOCK_FLAG_GPENCIL;
-
- return (DLRBT_Node *)ak;
-}
-
-/* Node updater callback used for building ActKeyColumns from GPencil frames */
-static void nupdate_ak_gpframe(void *node, void *data)
-{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- bGPDframe *gpf = (bGPDframe *)data;
-
- /* set selection status and 'touched' status */
- if (gpf->flag & GP_FRAME_SELECT) {
- ak->sel = SELECT;
- }
-
- /* count keyframes in this column */
- ak->totkey++;
-
- /* for keyframe type, 'proper' keyframes have priority over breakdowns
- * (and other types for now). */
- if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME) {
- ak->key_type = BEZT_KEYTYPE_KEYFRAME;
- }
-}
-
-/* ......... */
-
-/* Comparator callback used for ActKeyColumns and GPencil frame */
-static short compare_ak_masklayshape(void *node, void *data)
-{
- MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
-
- float frame = masklay_shape->frame;
- return compare_ak_cfraPtr(node, &frame);
-}
-
-/* New node callback used for building ActKeyColumns from GPencil frames */
-static DLRBT_Node *nalloc_ak_masklayshape(void *data)
-{
- ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
- MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
-
- /* store settings based on state of BezTriple */
- ak->cfra = masklay_shape->frame;
- ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0;
-
- /* count keyframes in this column */
- ak->totkey = 1;
-
- return (DLRBT_Node *)ak;
-}
-
-/* Node updater callback used for building ActKeyColumns from GPencil frames */
-static void nupdate_ak_masklayshape(void *node, void *data)
-{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
-
- /* set selection status and 'touched' status */
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
- ak->sel = SELECT;
- }
-
- /* count keyframes in this column */
- ak->totkey++;
-}
-
-/* --------------- */
-
-/* Add the given BezTriple to the given 'list' of Keyframes */
-static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTripleChain *bezt)
-{
- if (ELEM(NULL, keys, bezt)) {
- return;
- }
-
- BLI_dlrbTree_add(keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt);
-}
-
-/* Add the given GPencil Frame to the given 'list' of Keyframes */
-static void add_gpframe_to_keycolumns_list(DLRBT_Tree *keys, bGPDframe *gpf)
-{
- if (ELEM(NULL, keys, gpf)) {
- return;
- }
-
- BLI_dlrbTree_add(keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf);
-}
-
-/* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */
-static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *masklay_shape)
-{
- if (ELEM(NULL, keys, masklay_shape)) {
- return;
- }
-
- BLI_dlrbTree_add(keys,
- compare_ak_masklayshape,
- nalloc_ak_masklayshape,
- nupdate_ak_masklayshape,
- masklay_shape);
-}
-
-/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
-
-static const ActKeyBlockInfo dummy_keyblock = {0};
-
-static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTriple *beztn)
-{
- memset(info, 0, sizeof(ActKeyBlockInfo));
-
- if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
- /* Animator tagged a "moving hold"
- * - Previous key must also be tagged as a moving hold, otherwise
- * we're just dealing with the first of a pair, and we don't
- * want to be creating any phantom holds...
- */
- if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) {
- info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
- }
- }
-
- /* Check for same values...
- * - Handles must have same central value as each other
- * - Handles which control that section of the curve must be constant
- */
- if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) {
- bool hold;
-
- /* Only check handles in case of actual bezier interpolation. */
- if (prev->ipo == BEZT_IPO_BEZ) {
- hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) &&
- IS_EQF(prev->vec[1][1], prev->vec[2][1]);
- }
- /* This interpolation type induces movement even between identical keys. */
- else {
- hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC);
- }
-
- if (hold) {
- info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
- }
- }
-
- /* Remember non-bezier interpolation info. */
- if (prev->ipo != BEZT_IPO_BEZ) {
- info->flag |= ACTKEYBLOCK_FLAG_NON_BEZIER;
- }
-
- info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn);
-}
-
-static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block)
-{
- /* New curve and block. */
- if (col->totcurve <= 1 && col->totblock == 0) {
- memcpy(&col->block, block, sizeof(ActKeyBlockInfo));
- }
- /* Existing curve. */
- else {
- col->block.conflict |= (col->block.flag ^ block->flag);
- col->block.flag |= block->flag;
- col->block.sel |= block->sel;
- }
-
- if (block->flag) {
- col->totblock++;
- }
-}
-
-static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
-{
- ActKeyColumn *col = keys->first;
-
- if (bezt && bezt_len >= 2) {
- ActKeyBlockInfo block;
-
- /* Find the first key column while inserting dummy blocks. */
- for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) {
- add_keyblock_info(col, &dummy_keyblock);
- }
-
- BLI_assert(col != NULL);
-
- /* Insert real blocks. */
- for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) {
- /* Wrong order of bezier keys: resync position. */
- if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
- /* Backtrack to find the right location. */
- if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
- ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact(
- keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]);
-
- if (newcol != NULL) {
- col = newcol;
-
- /* The previous keyblock is garbage too. */
- if (col->prev != NULL) {
- add_keyblock_info(col->prev, &dummy_keyblock);
- }
- }
- else {
- BLI_assert(false);
- }
- }
-
- continue;
- }
-
- /* Normal sequence */
- BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0]));
-
- compute_keyblock_data(&block, bezt, bezt + 1);
-
- for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) {
- add_keyblock_info(col, &block);
- }
-
- BLI_assert(col != NULL);
- }
- }
-
- /* Insert dummy blocks at the end. */
- for (; col != NULL; col = col->next) {
- add_keyblock_info(col, &dummy_keyblock);
- }
-}
-
-/* Walk through columns and propagate blocks and totcurve.
- *
- * This must be called even by animation sources that don't generate
- * keyblocks to keep the data structure consistent after adding columns.
- */
-static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
-{
- /* Recompute the prev/next linked list. */
- BLI_dlrbTree_linkedlist_sync(keys);
-
- /* Find the curve count */
- int max_curve = 0;
-
- LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
- max_curve = MAX2(max_curve, col->totcurve);
- }
-
- /* Propagate blocks to inserted keys */
- ActKeyColumn *prev_ready = NULL;
-
- LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
- /* Pre-existing column. */
- if (col->totcurve > 0) {
- prev_ready = col;
- }
- /* Newly inserted column, so copy block data from previous. */
- else if (prev_ready != NULL) {
- col->totblock = prev_ready->totblock;
- memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo));
- }
-
- col->totcurve = max_curve + 1;
- }
-
- /* Add blocks on top */
- add_bezt_to_keyblocks_list(keys, bezt, bezt_len);
-}
-
-/* --------- */
-
-bool actkeyblock_is_valid(ActKeyColumn *ac)
-{
- return ac != NULL && ac->next != NULL && ac->totblock > 0;
-}
-
-/* Checks if ActKeyBlock should exist... */
-int actkeyblock_get_valid_hold(ActKeyColumn *ac)
-{
- /* check that block is valid */
- if (!actkeyblock_is_valid(ac)) {
- return 0;
- }
-
- const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD);
- return (ac->block.flag & ~ac->block.conflict) & hold_mask;
-}
+#include "ED_keyframes_keylist.h"
/* *************************** Keyframe Drawing *************************** */
@@ -1029,257 +527,3 @@ void draw_masklay_channel(View2D *v2d,
BLI_dlrbTree_free(&keys);
}
-
-/* *************************** Keyframe List Conversions *************************** */
-
-void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, int saction_flag)
-{
- if (ac) {
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- /* get F-Curves to take keyframes from */
- filter = ANIMFILTER_DATA_VISIBLE;
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
-
- /* loop through each F-Curve, grabbing the keyframes */
- for (ale = anim_data.first; ale; ale = ale->next) {
- /* Why not use all #eAnim_KeyType here?
- * All of the other key types are actually "summaries" themselves,
- * and will just end up duplicating stuff that comes up through
- * standard filtering of just F-Curves. Given the way that these work,
- * there isn't really any benefit at all from including them. - Aligorith */
-
- switch (ale->datatype) {
- case ALE_FCURVE:
- fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
- break;
- case ALE_MASKLAY:
- mask_to_keylist(ac->ads, ale->data, keys);
- break;
- case ALE_GPFRAME:
- gpl_to_keylist(ac->ads, ale->data, keys);
- break;
- default:
- // printf("%s: datatype %d unhandled\n", __func__, ale->datatype);
- break;
- }
- }
-
- ANIM_animdata_freelist(&anim_data);
- }
-}
-
-void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, int saction_flag)
-{
- bAnimContext ac = {NULL};
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- bAnimListElem dummychan = {NULL};
-
- if (sce == NULL) {
- return;
- }
-
- /* create a dummy wrapper data to work with */
- dummychan.type = ANIMTYPE_SCENE;
- dummychan.data = sce;
- dummychan.id = &sce->id;
- dummychan.adt = sce->adt;
-
- ac.ads = ads;
- ac.data = &dummychan;
- ac.datatype = ANIMCONT_CHANNEL;
-
- /* get F-Curves to take keyframes from */
- filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* loop through each F-Curve, grabbing the keyframes */
- for (ale = anim_data.first; ale; ale = ale->next) {
- fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
- }
-
- ANIM_animdata_freelist(&anim_data);
-}
-
-void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, int saction_flag)
-{
- bAnimContext ac = {NULL};
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- bAnimListElem dummychan = {NULL};
- Base dummybase = {NULL};
-
- if (ob == NULL) {
- return;
- }
-
- /* create a dummy wrapper data to work with */
- dummybase.object = ob;
-
- dummychan.type = ANIMTYPE_OBJECT;
- dummychan.data = &dummybase;
- dummychan.id = &ob->id;
- dummychan.adt = ob->adt;
-
- ac.ads = ads;
- ac.data = &dummychan;
- ac.datatype = ANIMCONT_CHANNEL;
-
- /* get F-Curves to take keyframes from */
- filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* loop through each F-Curve, grabbing the keyframes */
- for (ale = anim_data.first; ale; ale = ale->next) {
- fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
- }
-
- ANIM_animdata_freelist(&anim_data);
-}
-
-void cachefile_to_keylist(bDopeSheet *ads,
- CacheFile *cache_file,
- DLRBT_Tree *keys,
- int saction_flag)
-{
- if (cache_file == NULL) {
- return;
- }
-
- /* create a dummy wrapper data to work with */
- bAnimListElem dummychan = {NULL};
- dummychan.type = ANIMTYPE_DSCACHEFILE;
- dummychan.data = cache_file;
- dummychan.id = &cache_file->id;
- dummychan.adt = cache_file->adt;
-
- bAnimContext ac = {NULL};
- ac.ads = ads;
- ac.data = &dummychan;
- ac.datatype = ANIMCONT_CHANNEL;
-
- /* get F-Curves to take keyframes from */
- ListBase anim_data = {NULL, NULL};
- int filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* loop through each F-Curve, grabbing the keyframes */
- LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
- fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
- }
-
- ANIM_animdata_freelist(&anim_data);
-}
-
-void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, int saction_flag)
-{
- if (fcu && fcu->totvert && fcu->bezt) {
- /* apply NLA-mapping (if applicable) */
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
- }
-
- /* Check if the curve is cyclic. */
- bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2);
- bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0;
-
- /* loop through beztriples, making ActKeysColumns */
- BezTripleChain chain = {0};
-
- for (int v = 0; v < fcu->totvert; v++) {
- chain.cur = &fcu->bezt[v];
-
- /* Neighbor keys, accounting for being cyclic. */
- if (do_extremes) {
- chain.prev = (v > 0) ? &fcu->bezt[v - 1] : is_cyclic ? &fcu->bezt[fcu->totvert - 2] : NULL;
- chain.next = (v + 1 < fcu->totvert) ? &fcu->bezt[v + 1] : is_cyclic ? &fcu->bezt[1] : NULL;
- }
-
- add_bezt_to_keycolumns_list(keys, &chain);
- }
-
- /* Update keyblocks. */
- update_keyblocks(keys, fcu->bezt, fcu->totvert);
-
- /* unapply NLA-mapping if applicable */
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
- }
- }
-}
-
-void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, int saction_flag)
-{
- FCurve *fcu;
-
- if (agrp) {
- /* loop through F-Curves */
- for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
- fcurve_to_keylist(adt, fcu, keys, saction_flag);
- }
- }
-}
-
-void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, int saction_flag)
-{
- FCurve *fcu;
-
- if (act) {
- /* loop through F-Curves */
- for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- fcurve_to_keylist(adt, fcu, keys, saction_flag);
- }
- }
-}
-
-void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active)
-{
- bGPDlayer *gpl;
-
- if (gpd && keys) {
- /* for now, just aggregate out all the frames, but only for visible layers */
- for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
- if ((gpl->flag & GP_LAYER_HIDE) == 0) {
- if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) {
- gpl_to_keylist(ads, gpl, keys);
- }
- }
- }
- }
-}
-
-void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys)
-{
- bGPDframe *gpf;
-
- if (gpl && keys) {
- /* Although the frames should already be in an ordered list,
- * they are not suitable for displaying yet. */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- add_gpframe_to_keycolumns_list(keys, gpf);
- }
-
- update_keyblocks(keys, NULL, 0);
- }
-}
-
-void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *keys)
-{
- MaskLayerShape *masklay_shape;
-
- if (masklay && keys) {
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- add_masklay_to_keycolumns_list(keys, masklay_shape);
- }
-
- update_keyblocks(keys, NULL, 0);
- }
-}
diff --git a/source/blender/editors/animation/keyframes_keylist.c b/source/blender/editors/animation/keyframes_keylist.c
new file mode 100644
index 00000000000..47ed2b56300
--- /dev/null
+++ b/source/blender/editors/animation/keyframes_keylist.c
@@ -0,0 +1,793 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edanimation
+ */
+
+/* System includes ----------------------------------------------------- */
+
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_dlrbTree.h"
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_cachefile_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_fcurve.h"
+
+#include "ED_anim_api.h"
+#include "ED_keyframes_keylist.h"
+
+/* *************************** Keyframe Processing *************************** */
+
+/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
+
+BLI_INLINE bool is_cfra_eq(float a, float b)
+{
+ return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
+}
+
+BLI_INLINE bool is_cfra_lt(float a, float b)
+{
+ return (b - a) > BEZT_BINARYSEARCH_THRESH;
+}
+
+/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
+/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
+short compare_ak_cfraPtr(void *node, void *data)
+{
+ ActKeyColumn *ak = (ActKeyColumn *)node;
+ const float *cframe = data;
+ float val = *cframe;
+
+ if (is_cfra_eq(val, ak->cfra)) {
+ return 0;
+ }
+
+ if (val < ak->cfra) {
+ return -1;
+ }
+ return 1;
+}
+
+/* --------------- */
+
+/* Set of references to three logically adjacent keys. */
+typedef struct BezTripleChain {
+ /* Current keyframe. */
+ BezTriple *cur;
+
+ /* Logical neighbors. May be NULL. */
+ BezTriple *prev, *next;
+} BezTripleChain;
+
+/* Categorize the interpolation & handle type of the keyframe. */
+static eKeyframeHandleDrawOpts bezt_handle_type(BezTriple *bezt)
+{
+ if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM) {
+ return KEYFRAME_HANDLE_AUTO_CLAMP;
+ }
+ if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) {
+ return KEYFRAME_HANDLE_AUTO;
+ }
+ if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) {
+ return KEYFRAME_HANDLE_VECTOR;
+ }
+ if (ELEM(HD_FREE, bezt->h1, bezt->h2)) {
+ return KEYFRAME_HANDLE_FREE;
+ }
+ return KEYFRAME_HANDLE_ALIGNED;
+}
+
+/* Determine if the keyframe is an extreme by comparing with neighbors.
+ * Ends of fixed-value sections and of the whole curve are also marked.
+ */
+static eKeyframeExtremeDrawOpts bezt_extreme_type(BezTripleChain *chain)
+{
+ if (chain->prev == NULL && chain->next == NULL) {
+ return KEYFRAME_EXTREME_NONE;
+ }
+
+ /* Keyframe values for the current one and neighbors. */
+ float cur_y = chain->cur->vec[1][1];
+ float prev_y = cur_y, next_y = cur_y;
+
+ if (chain->prev && !IS_EQF(cur_y, chain->prev->vec[1][1])) {
+ prev_y = chain->prev->vec[1][1];
+ }
+ if (chain->next && !IS_EQF(cur_y, chain->next->vec[1][1])) {
+ next_y = chain->next->vec[1][1];
+ }
+
+ /* Static hold. */
+ if (prev_y == cur_y && next_y == cur_y) {
+ return KEYFRAME_EXTREME_FLAT;
+ }
+
+ /* Middle of an incline. */
+ if ((prev_y < cur_y && next_y > cur_y) || (prev_y > cur_y && next_y < cur_y)) {
+ return KEYFRAME_EXTREME_NONE;
+ }
+
+ /* Bezier handle values for the overshoot check. */
+ bool l_bezier = chain->prev && chain->prev->ipo == BEZT_IPO_BEZ;
+ bool r_bezier = chain->next && chain->cur->ipo == BEZT_IPO_BEZ;
+ float handle_l = l_bezier ? chain->cur->vec[0][1] : cur_y;
+ float handle_r = r_bezier ? chain->cur->vec[2][1] : cur_y;
+
+ /* Detect extremes. One of the neighbors is allowed to be equal to current. */
+ if (prev_y < cur_y || next_y < cur_y) {
+ bool is_overshoot = (handle_l > cur_y || handle_r > cur_y);
+
+ return KEYFRAME_EXTREME_MAX | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
+ }
+
+ if (prev_y > cur_y || next_y > cur_y) {
+ bool is_overshoot = (handle_l < cur_y || handle_r < cur_y);
+
+ return KEYFRAME_EXTREME_MIN | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
+ }
+
+ return KEYFRAME_EXTREME_NONE;
+}
+
+/* Comparator callback used for ActKeyColumns and BezTripleChain */
+static short compare_ak_bezt(void *node, void *data)
+{
+ BezTripleChain *chain = data;
+
+ return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]);
+}
+
+/* New node callback used for building ActKeyColumns from BezTripleChain */
+static DLRBT_Node *nalloc_ak_bezt(void *data)
+{
+ ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
+ BezTripleChain *chain = data;
+ BezTriple *bezt = chain->cur;
+
+ /* store settings based on state of BezTriple */
+ ak->cfra = bezt->vec[1][0];
+ ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
+ ak->key_type = BEZKEYTYPE(bezt);
+ ak->handle_type = bezt_handle_type(bezt);
+ ak->extreme_type = bezt_extreme_type(chain);
+
+ /* count keyframes in this column */
+ ak->totkey = 1;
+
+ return (DLRBT_Node *)ak;
+}
+
+/* Node updater callback used for building ActKeyColumns from BezTripleChain */
+static void nupdate_ak_bezt(void *node, void *data)
+{
+ ActKeyColumn *ak = node;
+ BezTripleChain *chain = data;
+ BezTriple *bezt = chain->cur;
+
+ /* set selection status and 'touched' status */
+ if (BEZT_ISSEL_ANY(bezt)) {
+ ak->sel = SELECT;
+ }
+
+ /* count keyframes in this column */
+ ak->totkey++;
+
+ /* For keyframe type, 'proper' keyframes have priority over breakdowns
+ * (and other types for now). */
+ if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) {
+ ak->key_type = BEZT_KEYTYPE_KEYFRAME;
+ }
+
+ /* For interpolation type, select the highest value (enum is sorted). */
+ ak->handle_type = MAX2(ak->handle_type, bezt_handle_type(bezt));
+
+ /* For extremes, detect when combining different states. */
+ char new_extreme = bezt_extreme_type(chain);
+
+ if (new_extreme != ak->extreme_type) {
+ /* Replace the flat status without adding mixed. */
+ if (ak->extreme_type == KEYFRAME_EXTREME_FLAT) {
+ ak->extreme_type = new_extreme;
+ }
+ else if (new_extreme != KEYFRAME_EXTREME_FLAT) {
+ ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED);
+ }
+ }
+}
+
+/* ......... */
+
+/* Comparator callback used for ActKeyColumns and GPencil frame */
+static short compare_ak_gpframe(void *node, void *data)
+{
+ bGPDframe *gpf = (bGPDframe *)data;
+
+ float frame = gpf->framenum;
+ return compare_ak_cfraPtr(node, &frame);
+}
+
+/* New node callback used for building ActKeyColumns from GPencil frames */
+static DLRBT_Node *nalloc_ak_gpframe(void *data)
+{
+ ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
+ bGPDframe *gpf = (bGPDframe *)data;
+
+ /* store settings based on state of BezTriple */
+ ak->cfra = gpf->framenum;
+ ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
+ ak->key_type = gpf->key_type;
+
+ /* count keyframes in this column */
+ ak->totkey = 1;
+ /* Set as visible block. */
+ ak->totblock = 1;
+ ak->block.sel = ak->sel;
+ ak->block.flag |= ACTKEYBLOCK_FLAG_GPENCIL;
+
+ return (DLRBT_Node *)ak;
+}
+
+/* Node updater callback used for building ActKeyColumns from GPencil frames */
+static void nupdate_ak_gpframe(void *node, void *data)
+{
+ ActKeyColumn *ak = (ActKeyColumn *)node;
+ bGPDframe *gpf = (bGPDframe *)data;
+
+ /* set selection status and 'touched' status */
+ if (gpf->flag & GP_FRAME_SELECT) {
+ ak->sel = SELECT;
+ }
+
+ /* count keyframes in this column */
+ ak->totkey++;
+
+ /* for keyframe type, 'proper' keyframes have priority over breakdowns
+ * (and other types for now). */
+ if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME) {
+ ak->key_type = BEZT_KEYTYPE_KEYFRAME;
+ }
+}
+
+/* ......... */
+
+/* Comparator callback used for ActKeyColumns and GPencil frame */
+static short compare_ak_masklayshape(void *node, void *data)
+{
+ MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
+
+ float frame = masklay_shape->frame;
+ return compare_ak_cfraPtr(node, &frame);
+}
+
+/* New node callback used for building ActKeyColumns from GPencil frames */
+static DLRBT_Node *nalloc_ak_masklayshape(void *data)
+{
+ ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
+ MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
+
+ /* store settings based on state of BezTriple */
+ ak->cfra = masklay_shape->frame;
+ ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0;
+
+ /* count keyframes in this column */
+ ak->totkey = 1;
+
+ return (DLRBT_Node *)ak;
+}
+
+/* Node updater callback used for building ActKeyColumns from GPencil frames */
+static void nupdate_ak_masklayshape(void *node, void *data)
+{
+ ActKeyColumn *ak = (ActKeyColumn *)node;
+ MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
+
+ /* set selection status and 'touched' status */
+ if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ ak->sel = SELECT;
+ }
+
+ /* count keyframes in this column */
+ ak->totkey++;
+}
+
+/* --------------- */
+
+/* Add the given BezTriple to the given 'list' of Keyframes */
+static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTripleChain *bezt)
+{
+ if (ELEM(NULL, keys, bezt)) {
+ return;
+ }
+
+ BLI_dlrbTree_add(keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt);
+}
+
+/* Add the given GPencil Frame to the given 'list' of Keyframes */
+static void add_gpframe_to_keycolumns_list(DLRBT_Tree *keys, bGPDframe *gpf)
+{
+ if (ELEM(NULL, keys, gpf)) {
+ return;
+ }
+
+ BLI_dlrbTree_add(keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf);
+}
+
+/* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */
+static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *masklay_shape)
+{
+ if (ELEM(NULL, keys, masklay_shape)) {
+ return;
+ }
+
+ BLI_dlrbTree_add(keys,
+ compare_ak_masklayshape,
+ nalloc_ak_masklayshape,
+ nupdate_ak_masklayshape,
+ masklay_shape);
+}
+
+/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
+
+static const ActKeyBlockInfo dummy_keyblock = {0};
+
+static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTriple *beztn)
+{
+ memset(info, 0, sizeof(ActKeyBlockInfo));
+
+ if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
+ /* Animator tagged a "moving hold"
+ * - Previous key must also be tagged as a moving hold, otherwise
+ * we're just dealing with the first of a pair, and we don't
+ * want to be creating any phantom holds...
+ */
+ if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) {
+ info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
+ }
+ }
+
+ /* Check for same values...
+ * - Handles must have same central value as each other
+ * - Handles which control that section of the curve must be constant
+ */
+ if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) {
+ bool hold;
+
+ /* Only check handles in case of actual bezier interpolation. */
+ if (prev->ipo == BEZT_IPO_BEZ) {
+ hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) &&
+ IS_EQF(prev->vec[1][1], prev->vec[2][1]);
+ }
+ /* This interpolation type induces movement even between identical keys. */
+ else {
+ hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC);
+ }
+
+ if (hold) {
+ info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
+ }
+ }
+
+ /* Remember non-bezier interpolation info. */
+ if (prev->ipo != BEZT_IPO_BEZ) {
+ info->flag |= ACTKEYBLOCK_FLAG_NON_BEZIER;
+ }
+
+ info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn);
+}
+
+static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block)
+{
+ /* New curve and block. */
+ if (col->totcurve <= 1 && col->totblock == 0) {
+ memcpy(&col->block, block, sizeof(ActKeyBlockInfo));
+ }
+ /* Existing curve. */
+ else {
+ col->block.conflict |= (col->block.flag ^ block->flag);
+ col->block.flag |= block->flag;
+ col->block.sel |= block->sel;
+ }
+
+ if (block->flag) {
+ col->totblock++;
+ }
+}
+
+static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
+{
+ ActKeyColumn *col = keys->first;
+
+ if (bezt && bezt_len >= 2) {
+ ActKeyBlockInfo block;
+
+ /* Find the first key column while inserting dummy blocks. */
+ for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) {
+ add_keyblock_info(col, &dummy_keyblock);
+ }
+
+ BLI_assert(col != NULL);
+
+ /* Insert real blocks. */
+ for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) {
+ /* Wrong order of bezier keys: resync position. */
+ if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
+ /* Backtrack to find the right location. */
+ if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
+ ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact(
+ keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]);
+
+ if (newcol != NULL) {
+ col = newcol;
+
+ /* The previous keyblock is garbage too. */
+ if (col->prev != NULL) {
+ add_keyblock_info(col->prev, &dummy_keyblock);
+ }
+ }
+ else {
+ BLI_assert(false);
+ }
+ }
+
+ continue;
+ }
+
+ /* Normal sequence */
+ BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0]));
+
+ compute_keyblock_data(&block, bezt, bezt + 1);
+
+ for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) {
+ add_keyblock_info(col, &block);
+ }
+
+ BLI_assert(col != NULL);
+ }
+ }
+
+ /* Insert dummy blocks at the end. */
+ for (; col != NULL; col = col->next) {
+ add_keyblock_info(col, &dummy_keyblock);
+ }
+}
+
+/* Walk through columns and propagate blocks and totcurve.
+ *
+ * This must be called even by animation sources that don't generate
+ * keyblocks to keep the data structure consistent after adding columns.
+ */
+static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
+{
+ /* Recompute the prev/next linked list. */
+ BLI_dlrbTree_linkedlist_sync(keys);
+
+ /* Find the curve count */
+ int max_curve = 0;
+
+ LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
+ max_curve = MAX2(max_curve, col->totcurve);
+ }
+
+ /* Propagate blocks to inserted keys */
+ ActKeyColumn *prev_ready = NULL;
+
+ LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
+ /* Pre-existing column. */
+ if (col->totcurve > 0) {
+ prev_ready = col;
+ }
+ /* Newly inserted column, so copy block data from previous. */
+ else if (prev_ready != NULL) {
+ col->totblock = prev_ready->totblock;
+ memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo));
+ }
+
+ col->totcurve = max_curve + 1;
+ }
+
+ /* Add blocks on top */
+ add_bezt_to_keyblocks_list(keys, bezt, bezt_len);
+}
+
+/* --------- */
+
+bool actkeyblock_is_valid(ActKeyColumn *ac)
+{
+ return ac != NULL && ac->next != NULL && ac->totblock > 0;
+}
+
+/* Checks if ActKeyBlock should exist... */
+int actkeyblock_get_valid_hold(ActKeyColumn *ac)
+{
+ /* check that block is valid */
+ if (!actkeyblock_is_valid(ac)) {
+ return 0;
+ }
+
+ const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD);
+ return (ac->block.flag & ~ac->block.conflict) & hold_mask;
+}
+
+/* *************************** Keyframe List Conversions *************************** */
+
+void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, int saction_flag)
+{
+ if (ac) {
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ /* get F-Curves to take keyframes from */
+ filter = ANIMFILTER_DATA_VISIBLE;
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* loop through each F-Curve, grabbing the keyframes */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ /* Why not use all #eAnim_KeyType here?
+ * All of the other key types are actually "summaries" themselves,
+ * and will just end up duplicating stuff that comes up through
+ * standard filtering of just F-Curves. Given the way that these work,
+ * there isn't really any benefit at all from including them. - Aligorith */
+
+ switch (ale->datatype) {
+ case ALE_FCURVE:
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
+ break;
+ case ALE_MASKLAY:
+ mask_to_keylist(ac->ads, ale->data, keys);
+ break;
+ case ALE_GPFRAME:
+ gpl_to_keylist(ac->ads, ale->data, keys);
+ break;
+ default:
+ // printf("%s: datatype %d unhandled\n", __func__, ale->datatype);
+ break;
+ }
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+ }
+}
+
+void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, int saction_flag)
+{
+ bAnimContext ac = {NULL};
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ bAnimListElem dummychan = {NULL};
+
+ if (sce == NULL) {
+ return;
+ }
+
+ /* create a dummy wrapper data to work with */
+ dummychan.type = ANIMTYPE_SCENE;
+ dummychan.data = sce;
+ dummychan.id = &sce->id;
+ dummychan.adt = sce->adt;
+
+ ac.ads = ads;
+ ac.data = &dummychan;
+ ac.datatype = ANIMCONT_CHANNEL;
+
+ /* get F-Curves to take keyframes from */
+ filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* loop through each F-Curve, grabbing the keyframes */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+}
+
+void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, int saction_flag)
+{
+ bAnimContext ac = {NULL};
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ bAnimListElem dummychan = {NULL};
+ Base dummybase = {NULL};
+
+ if (ob == NULL) {
+ return;
+ }
+
+ /* create a dummy wrapper data to work with */
+ dummybase.object = ob;
+
+ dummychan.type = ANIMTYPE_OBJECT;
+ dummychan.data = &dummybase;
+ dummychan.id = &ob->id;
+ dummychan.adt = ob->adt;
+
+ ac.ads = ads;
+ ac.data = &dummychan;
+ ac.datatype = ANIMCONT_CHANNEL;
+
+ /* get F-Curves to take keyframes from */
+ filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* loop through each F-Curve, grabbing the keyframes */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+}
+
+void cachefile_to_keylist(bDopeSheet *ads,
+ CacheFile *cache_file,
+ DLRBT_Tree *keys,
+ int saction_flag)
+{
+ if (cache_file == NULL) {
+ return;
+ }
+
+ /* create a dummy wrapper data to work with */
+ bAnimListElem dummychan = {NULL};
+ dummychan.type = ANIMTYPE_DSCACHEFILE;
+ dummychan.data = cache_file;
+ dummychan.id = &cache_file->id;
+ dummychan.adt = cache_file->adt;
+
+ bAnimContext ac = {NULL};
+ ac.ads = ads;
+ ac.data = &dummychan;
+ ac.datatype = ANIMCONT_CHANNEL;
+
+ /* get F-Curves to take keyframes from */
+ ListBase anim_data = {NULL, NULL};
+ int filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* loop through each F-Curve, grabbing the keyframes */
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+}
+
+void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, int saction_flag)
+{
+ if (fcu && fcu->totvert && fcu->bezt) {
+ /* apply NLA-mapping (if applicable) */
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
+ }
+
+ /* Check if the curve is cyclic. */
+ bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2);
+ bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0;
+
+ /* loop through beztriples, making ActKeysColumns */
+ BezTripleChain chain = {0};
+
+ for (int v = 0; v < fcu->totvert; v++) {
+ chain.cur = &fcu->bezt[v];
+
+ /* Neighbor keys, accounting for being cyclic. */
+ if (do_extremes) {
+ chain.prev = (v > 0) ? &fcu->bezt[v - 1] : is_cyclic ? &fcu->bezt[fcu->totvert - 2] : NULL;
+ chain.next = (v + 1 < fcu->totvert) ? &fcu->bezt[v + 1] : is_cyclic ? &fcu->bezt[1] : NULL;
+ }
+
+ add_bezt_to_keycolumns_list(keys, &chain);
+ }
+
+ /* Update keyblocks. */
+ update_keyblocks(keys, fcu->bezt, fcu->totvert);
+
+ /* unapply NLA-mapping if applicable */
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
+ }
+ }
+}
+
+void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, int saction_flag)
+{
+ FCurve *fcu;
+
+ if (agrp) {
+ /* loop through F-Curves */
+ for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
+ fcurve_to_keylist(adt, fcu, keys, saction_flag);
+ }
+ }
+}
+
+void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, int saction_flag)
+{
+ FCurve *fcu;
+
+ if (act) {
+ /* loop through F-Curves */
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ fcurve_to_keylist(adt, fcu, keys, saction_flag);
+ }
+ }
+}
+
+void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active)
+{
+ bGPDlayer *gpl;
+
+ if (gpd && keys) {
+ /* for now, just aggregate out all the frames, but only for visible layers */
+ for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
+ if ((gpl->flag & GP_LAYER_HIDE) == 0) {
+ if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) {
+ gpl_to_keylist(ads, gpl, keys);
+ }
+ }
+ }
+ }
+}
+
+void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys)
+{
+ bGPDframe *gpf;
+
+ if (gpl && keys) {
+ /* Although the frames should already be in an ordered list,
+ * they are not suitable for displaying yet. */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ add_gpframe_to_keycolumns_list(keys, gpf);
+ }
+
+ update_keyblocks(keys, NULL, 0);
+ }
+}
+
+void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *keys)
+{
+ MaskLayerShape *masklay_shape;
+
+ if (masklay && keys) {
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ add_masklay_to_keycolumns_list(keys, masklay_shape);
+ }
+
+ update_keyblocks(keys, NULL, 0);
+ }
+}
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index e942bcf2902..aff5803f037 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -44,7 +44,7 @@ set(SRC
armature_utils.c
editarmature_undo.c
meshlaplacian.c
- pose_backup.c
+ pose_backup.cc
pose_edit.c
pose_group.c
pose_lib.c
diff --git a/source/blender/editors/armature/pose_backup.c b/source/blender/editors/armature/pose_backup.cc
index dffcd9bdc5a..9b2d3e37d98 100644
--- a/source/blender/editors/armature/pose_backup.c
+++ b/source/blender/editors/armature/pose_backup.cc
@@ -20,7 +20,7 @@
#include "ED_armature.h"
-#include <string.h>
+#include <cstring>
#include "BLI_listbase.h"
@@ -31,9 +31,12 @@
#include "DNA_object_types.h"
#include "BKE_action.h"
-#include "BKE_armature.h"
+#include "BKE_action.hh"
+#include "BKE_armature.hh"
#include "BKE_idprop.h"
+using namespace blender::bke;
+
/* simple struct for storing backup info for one pose channel */
typedef struct PoseChannelBackup {
struct PoseChannelBackup *next, *prev;
@@ -44,31 +47,38 @@ typedef struct PoseChannelBackup {
struct IDProperty *oldprops; /* Backup copy (needs freeing) of pose channel's ID properties. */
} PoseChannelBackup;
-typedef struct PoseBackup {
+struct PoseBackup {
bool is_bone_selection_relevant;
ListBase /* PoseChannelBackup* */ backups;
-} PoseBackup;
+};
static PoseBackup *pose_backup_create(const Object *ob,
const bAction *action,
- const bool is_bone_selection_relevant)
+ const BoneNameSet &selected_bone_names)
{
- ListBase backups = {NULL, NULL};
- const bArmature *armature = ob->data;
-
- /* TODO(Sybren): reuse same approach as in `armature_pose.cc` in this function, as that doesn't
- * have the assumption that action group names are bone names. */
- LISTBASE_FOREACH (bActionGroup *, agrp, &action->groups) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
- if (pchan == NULL) {
- continue;
+ ListBase backups = {nullptr, nullptr};
+ const bool is_bone_selection_relevant = !selected_bone_names.is_empty();
+
+ BoneNameSet backed_up_bone_names;
+ /* Make a backup of the given pose channel. */
+ auto store_animated_pchans = [&](FCurve *, const char *bone_name) {
+ if (backed_up_bone_names.contains(bone_name)) {
+ /* Only backup each bone once. */
+ return;
+ }
+
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (pchan == nullptr) {
+ /* FCurve targets non-existent bone. */
+ return;
}
- if (is_bone_selection_relevant && !PBONE_SELECTED(armature, pchan->bone)) {
- continue;
+ if (is_bone_selection_relevant && !selected_bone_names.contains(bone_name)) {
+ return;
}
- PoseChannelBackup *chan_bak = MEM_callocN(sizeof(*chan_bak), "PoseChannelBackup");
+ PoseChannelBackup *chan_bak = static_cast<PoseChannelBackup *>(
+ MEM_callocN(sizeof(*chan_bak), "PoseChannelBackup"));
chan_bak->pchan = pchan;
memcpy(&chan_bak->olddata, chan_bak->pchan, sizeof(chan_bak->olddata));
@@ -77,10 +87,14 @@ static PoseBackup *pose_backup_create(const Object *ob,
}
BLI_addtail(&backups, chan_bak);
- }
+ backed_up_bone_names.add_new(bone_name);
+ };
+
+ /* Call `store_animated_pchans()` for each FCurve that targets a bone. */
+ BKE_action_find_fcurves_with_bones(action, store_animated_pchans);
/* PoseBackup is constructed late, so that the above loop can use stack variables. */
- PoseBackup *pose_backup = MEM_callocN(sizeof(*pose_backup), __func__);
+ PoseBackup *pose_backup = static_cast<PoseBackup *>(MEM_callocN(sizeof(*pose_backup), __func__));
pose_backup->is_bone_selection_relevant = is_bone_selection_relevant;
pose_backup->backups = backups;
return pose_backup;
@@ -88,24 +102,14 @@ static PoseBackup *pose_backup_create(const Object *ob,
PoseBackup *ED_pose_backup_create_all_bones(const Object *ob, const bAction *action)
{
- return pose_backup_create(ob, action, false);
+ return pose_backup_create(ob, action, BoneNameSet());
}
PoseBackup *ED_pose_backup_create_selected_bones(const Object *ob, const bAction *action)
{
- /* See if bone selection is relevant. */
- bool all_bones_selected = true;
- bool no_bones_selected = true;
- const bArmature *armature = ob->data;
- LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
- const bool is_selected = PBONE_SELECTED(armature, pchan->bone);
- all_bones_selected &= is_selected;
- no_bones_selected &= !is_selected;
- }
-
- /* If no bones are selected, act as if all are. */
- const bool is_bone_selection_relevant = !all_bones_selected && !no_bones_selected;
- return pose_backup_create(ob, action, is_bone_selection_relevant);
+ const bArmature *armature = static_cast<const bArmature *>(ob->data);
+ const BoneNameSet selected_bone_names = BKE_armature_find_selected_bone_names(armature);
+ return pose_backup_create(ob, action, selected_bone_names);
}
bool ED_pose_backup_is_selection_relevant(const struct PoseBackup *pose_backup)
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index df3550d5db6..cb70b2810d1 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -62,8 +62,8 @@
#include "ED_anim_api.h"
#include "ED_armature.h"
-#include "ED_keyframes_draw.h"
#include "ED_keyframes_edit.h"
+#include "ED_keyframes_keylist.h"
#include "ED_keyframing.h"
#include "ED_object.h"
#include "ED_screen.h"
diff --git a/source/blender/editors/armature/pose_lib_2.c b/source/blender/editors/armature/pose_lib_2.c
index eb091296282..32440f941ba 100644
--- a/source/blender/editors/armature/pose_lib_2.c
+++ b/source/blender/editors/armature/pose_lib_2.c
@@ -130,7 +130,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, PoseBlendData *pbd)
/* start tagging/keying */
const bArmature *armature = pbd->ob->data;
LISTBASE_FOREACH (bActionGroup *, agrp, &act->groups) {
- /* only for selected bones unless there aren't any selected, in which case all are included */
+ /* Only for selected bones unless there aren't any selected, in which case all are included. */
bPoseChannel *pchan = BKE_pose_channel_find_name(pose, agrp->name);
if (pchan == NULL) {
continue;
@@ -422,7 +422,7 @@ static void poselib_blend_cleanup(bContext *C, wmOperator *op)
case POSE_BLEND_BLENDING:
case POSE_BLEND_ORIGINAL:
/* Cleanup should not be called directly from these states. */
- BLI_assert(!"poselib_blend_cleanup: unexpected pose blend state");
+ BLI_assert_msg(0, "poselib_blend_cleanup: unexpected pose blend state");
BKE_report(op->reports, RPT_ERROR, "Internal pose library error, cancelling operator");
ATTR_FALLTHROUGH;
case POSE_BLEND_CANCEL:
@@ -544,7 +544,7 @@ static bool poselib_asset_in_context(bContext *C)
AssetHandle asset_handle = CTX_wm_asset_handle(C, &asset_handle_valid);
return (asset_library != NULL) && asset_handle_valid &&
- (asset_handle.file_data->blentype == ID_AC);
+ (ED_asset_handle_get_id_type(&asset_handle) == ID_AC);
}
/* Poll callback for operators that require existing PoseLib data (with poses) to work. */
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 1a1685e4a01..e87d221058c 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -77,11 +77,12 @@
#include "UI_resources.h"
#include "ED_armature.h"
-#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "ED_markers.h"
#include "ED_numinput.h"
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "ED_util.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
@@ -137,8 +138,8 @@ typedef struct tPoseSlideOp {
Scene *scene;
/** area that we're operating in (needed for modal()) */
ScrArea *area;
- /** Header of the region used for drawing the slider. */
- ARegion *region_header;
+ /** Region we're operating in (needed for modal()). */
+ ARegion *region;
/** len of the PoseSlideObject array. */
uint objects_len;
@@ -168,26 +169,7 @@ typedef struct tPoseSlideOp {
/** Axis-limits for transforms. */
ePoseSlide_AxisLock axislock;
- /** Allow overshoot or clamp between 0% and 100%. */
- bool overshoot;
-
- /** Reduces factor delta from mouse movement. */
- bool precision;
-
- /** Move factor in 10% steps. */
- bool increments;
-
- /** Draw callback handler. */
- void *draw_handle;
-
- /** Accumulative, unclamped and unrounded factor. */
- float raw_factor;
-
- /** 0-1 value for determining the influence of whatever is relevant. */
- float factor;
-
- /** Last cursor position in screen space used for mouse movement delta calculation. */
- int last_cursor_x;
+ struct tSlider *slider;
/** Numeric input. */
NumInput num;
@@ -232,256 +214,6 @@ static const EnumPropertyItem prop_axis_lock_types[] = {
/* ------------------------------------ */
-static void draw_overshoot_triangle(const uint8_t color[4],
- const bool facing_right,
- const float x,
- const float y)
-{
- const uint shdr_pos_2d = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_polygon_smooth(true);
- immUniformColor3ubvAlpha(color, 225);
- const float triangle_side_length = facing_right ? 6 * U.pixelsize : -6 * U.pixelsize;
- const float triangle_offset = facing_right ? 2 * U.pixelsize : -2 * U.pixelsize;
-
- immBegin(GPU_PRIM_TRIS, 3);
- immVertex2f(shdr_pos_2d, x + triangle_offset + triangle_side_length, y);
- immVertex2f(shdr_pos_2d, x + triangle_offset, y + triangle_side_length / 2);
- immVertex2f(shdr_pos_2d, x + triangle_offset, y - triangle_side_length / 2);
- immEnd();
-
- GPU_polygon_smooth(false);
- GPU_blend(GPU_BLEND_NONE);
- immUnbindProgram();
-}
-
-static void draw_ticks(const float start_factor,
- const float end_factor,
- const float line_start[2],
- const float base_tick_height,
- const float line_width,
- const uint8_t color_overshoot[4],
- const uint8_t color_line[4])
-{
- /* Use factor represented as 0-100 int to avoid floating point precision problems. */
- const int tick_increment = 10;
-
- /* Round initial_tick_factor up to the next tick_increment. */
- int tick_percentage = ceil((start_factor * 100) / tick_increment) * tick_increment;
-
- while (tick_percentage <= (int)(end_factor * 100)) {
- float tick_height;
- /* Different ticks have different heights. Multiples of 100% are the tallest, 50% is a bit
- * smaller and the rest is the minimum size. */
- if (tick_percentage % 100 == 0) {
- tick_height = base_tick_height;
- }
- else if (tick_percentage % 50 == 0) {
- tick_height = base_tick_height * 0.8;
- }
- else {
- tick_height = base_tick_height * 0.5;
- }
-
- const float x = line_start[0] +
- (((float)tick_percentage / 100) - start_factor) * SLIDE_PIXEL_DISTANCE;
- const rctf tick_rect = {
- .xmin = x - (line_width / 2),
- .xmax = x + (line_width / 2),
- .ymin = line_start[1] - (tick_height / 2),
- .ymax = line_start[1] + (tick_height / 2),
- };
-
- if (tick_percentage < 0 || tick_percentage > 100) {
- UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_overshoot, 255);
- }
- else {
- UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_line, 255);
- }
- tick_percentage += tick_increment;
- }
-}
-
-static void draw_main_line(const rctf *main_line_rect,
- const float factor,
- const bool overshoot,
- const uint8_t color_overshoot[4],
- const uint8_t color_line[4])
-{
- if (overshoot) {
- /* In overshoot mode, draw the 0-100% range differently to provide a visual reference. */
- const float line_zero_percent = main_line_rect->xmin -
- ((factor - 0.5f - OVERSHOOT_RANGE_DELTA) *
- SLIDE_PIXEL_DISTANCE);
-
- const float clamped_line_zero_percent = clamp_f(
- line_zero_percent, main_line_rect->xmin, main_line_rect->xmax);
- const float clamped_line_hundred_percent = clamp_f(
- line_zero_percent + SLIDE_PIXEL_DISTANCE, main_line_rect->xmin, main_line_rect->xmax);
-
- const rctf left_overshoot_line_rect = {
- .xmin = main_line_rect->xmin,
- .xmax = clamped_line_zero_percent,
- .ymin = main_line_rect->ymin,
- .ymax = main_line_rect->ymax,
- };
- const rctf right_overshoot_line_rect = {
- .xmin = clamped_line_hundred_percent,
- .xmax = main_line_rect->xmax,
- .ymin = main_line_rect->ymin,
- .ymax = main_line_rect->ymax,
- };
- UI_draw_roundbox_3ub_alpha(&left_overshoot_line_rect, true, 0, color_overshoot, 255);
- UI_draw_roundbox_3ub_alpha(&right_overshoot_line_rect, true, 0, color_overshoot, 255);
-
- const rctf non_overshoot_line_rect = {
- .xmin = clamped_line_zero_percent,
- .xmax = clamped_line_hundred_percent,
- .ymin = main_line_rect->ymin,
- .ymax = main_line_rect->ymax,
- };
- UI_draw_roundbox_3ub_alpha(&non_overshoot_line_rect, true, 0, color_line, 255);
- }
- else {
- UI_draw_roundbox_3ub_alpha(main_line_rect, true, 0, color_line, 255);
- }
-}
-
-static void draw_backdrop(const int fontid,
- const rctf *main_line_rect,
- const float color_bg[4],
- const short region_y_size,
- const float base_tick_height)
-{
- float string_pixel_size[2];
- const char *percentage_string_placeholder = "000%%";
- BLF_width_and_height(fontid,
- percentage_string_placeholder,
- sizeof(percentage_string_placeholder),
- &string_pixel_size[0],
- &string_pixel_size[1]);
- const float pad[2] = {(region_y_size - base_tick_height) / 2, 2.0f * U.pixelsize};
- const rctf backdrop_rect = {
- .xmin = main_line_rect->xmin - string_pixel_size[0] - pad[0],
- .xmax = main_line_rect->xmax + pad[0],
- .ymin = pad[1],
- .ymax = region_y_size - pad[1],
- };
- UI_draw_roundbox_aa(&backdrop_rect, true, 4.0f, color_bg);
-}
-
-/**
- * Draw an on screen Slider for a Pose Slide Operator.
- */
-static void pose_slide_draw_2d_slider(const struct bContext *UNUSED(C), ARegion *region, void *arg)
-{
- tPoseSlideOp *pso = arg;
-
- /* Only draw in region from which the Operator was started. */
- if (region != pso->region_header) {
- return;
- }
-
- uint8_t color_text[4];
- uint8_t color_line[4];
- uint8_t color_handle[4];
- uint8_t color_overshoot[4];
- float color_bg[4];
-
- /* Get theme colors. */
- UI_GetThemeColor4ubv(TH_TEXT, color_text);
- UI_GetThemeColor4ubv(TH_TEXT, color_line);
- UI_GetThemeColor4ubv(TH_TEXT, color_overshoot);
- UI_GetThemeColor4ubv(TH_ACTIVE, color_handle);
- UI_GetThemeColor3fv(TH_BACK, color_bg);
-
- color_bg[3] = 0.5f;
- color_overshoot[0] = color_overshoot[0] * 0.7;
- color_overshoot[1] = color_overshoot[1] * 0.7;
- color_overshoot[2] = color_overshoot[2] * 0.7;
-
- /* Get the default font. */
- const uiStyle *style = UI_style_get();
- const uiFontStyle *fstyle = &style->widget;
- const int fontid = fstyle->uifont_id;
- BLF_color3ubv(fontid, color_text);
- BLF_rotation(fontid, 0.0f);
-
- const float line_width = 1.5 * U.pixelsize;
- const float base_tick_height = 12.0 * U.pixelsize;
- const float line_y = region->winy / 2;
-
- rctf main_line_rect = {
- .xmin = (region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2),
- .xmax = (region->winx / 2) + (SLIDE_PIXEL_DISTANCE / 2),
- .ymin = line_y - line_width / 2,
- .ymax = line_y + line_width / 2,
- };
- float line_start_factor = 0;
- int handle_pos_x = main_line_rect.xmin + SLIDE_PIXEL_DISTANCE * pso->factor;
-
- if (pso->overshoot) {
- main_line_rect.xmin = main_line_rect.xmin - SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA;
- main_line_rect.xmax = main_line_rect.xmax + SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA;
- line_start_factor = pso->factor - 0.5f - OVERSHOOT_RANGE_DELTA;
- handle_pos_x = region->winx / 2;
- }
-
- draw_backdrop(fontid, &main_line_rect, color_bg, pso->region_header->winy, base_tick_height);
-
- draw_main_line(&main_line_rect, pso->factor, pso->overshoot, color_overshoot, color_line);
-
- const float factor_range = pso->overshoot ? 1 + OVERSHOOT_RANGE_DELTA * 2 : 1;
- const float line_start_position[2] = {main_line_rect.xmin, line_y};
- draw_ticks(line_start_factor,
- line_start_factor + factor_range,
- line_start_position,
- base_tick_height,
- line_width,
- color_overshoot,
- color_line);
-
- /* Draw triangles at the ends of the line in overshoot mode to indicate direction of 0-100%
- * range. */
- if (pso->overshoot) {
- if (pso->factor > 1 + OVERSHOOT_RANGE_DELTA + 0.5) {
- draw_overshoot_triangle(color_line, false, main_line_rect.xmin, line_y);
- }
- if (pso->factor < 0 - OVERSHOOT_RANGE_DELTA - 0.5) {
- draw_overshoot_triangle(color_line, true, main_line_rect.xmax, line_y);
- }
- }
-
- char percentage_string[256];
-
- /* Draw handle indicating current factor. */
- const rctf handle_rect = {
- .xmin = handle_pos_x - (line_width),
- .xmax = handle_pos_x + (line_width),
- .ymin = line_y - (base_tick_height / 2),
- .ymax = line_y + (base_tick_height / 2),
- };
-
- UI_draw_roundbox_3ub_alpha(&handle_rect, true, 1, color_handle, 255);
- BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", pso->factor * 100);
-
- /* Draw percentage string. */
- float percentage_string_pixel_size[2];
- BLF_width_and_height(fontid,
- percentage_string,
- sizeof(percentage_string),
- &percentage_string_pixel_size[0],
- &percentage_string_pixel_size[1]);
-
- BLF_position(fontid,
- main_line_rect.xmin - 24.0 * U.pixelsize - percentage_string_pixel_size[0] / 2,
- (region->winy / 2) - percentage_string_pixel_size[1] / 2,
- 0.0f);
- BLF_draw(fontid, percentage_string, sizeof(percentage_string));
-}
-
/** Operator custom-data initialization. */
static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
{
@@ -492,15 +224,13 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
/* Get info from context. */
pso->scene = CTX_data_scene(C);
- pso->area = CTX_wm_area(C); /* Only really needed when doing modal(). */
- pso->region_header = CTX_wm_region(C); /* Only really needed when doing modal(). */
+ pso->area = CTX_wm_area(C); /* Only really needed when doing modal(). */
+ pso->region = CTX_wm_region(C); /* Only really needed when doing modal(). */
pso->cframe = pso->scene->r.cfra;
pso->mode = mode;
/* Set range info from property values - these may get overridden for the invoke(). */
- pso->factor = RNA_float_get(op->ptr, "factor");
- pso->raw_factor = pso->factor;
pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
@@ -508,6 +238,9 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
pso->channels = RNA_enum_get(op->ptr, "channels");
pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
+ pso->slider = ED_slider_create(C);
+ ED_slider_factor_set(pso->slider, RNA_float_get(op->ptr, "factor"));
+
/* For each Pose-Channel which gets affected, get the F-Curves for that channel
* and set the relevant transform flags. */
poseAnim_mapping_get(C, &pso->pfLinks);
@@ -552,14 +285,6 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
pso->num.unit_type[0] = B_UNIT_NONE; /* Percentages don't have any units. */
- /* Register UI drawing callback. */
- ARegion *region_header = BKE_area_find_region_type(pso->area, RGN_TYPE_HEADER);
- if (region_header != NULL) {
- pso->region_header = region_header;
- pso->draw_handle = ED_region_draw_cb_activate(
- region_header->type, pose_slide_draw_2d_slider, pso, REGION_DRAW_POST_PIXEL);
- }
-
/* Return status is whether we've got all the data we were requested to get. */
return 1;
}
@@ -567,17 +292,16 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
/**
* Exiting the operator (free data).
*/
-static void pose_slide_exit(wmOperator *op)
+static void pose_slide_exit(bContext *C, wmOperator *op)
{
tPoseSlideOp *pso = op->customdata;
+ ED_slider_destroy(C, pso->slider);
+
/* Hide Bone Overlay. */
View3D *v3d = pso->area->spacedata.first;
v3d->overlay.flag = pso->overlay_flag;
- /* Remove UI drawing callback. */
- ED_region_draw_cb_exit(pso->region_header->type, pso->draw_handle);
-
/* Free the temp pchan links and their data. */
poseAnim_mapping_free(&pso->pfLinks);
@@ -655,8 +379,8 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, flo
/* Calculate the relative weights of the endpoints. */
if (pso->mode == POSESLIDE_BREAKDOWN) {
/* Get weights from the factor control. */
- w1 = pso->factor; /* This must come second. */
- w2 = 1.0f - w1; /* This must come first. */
+ w1 = ED_slider_factor_get(pso->slider); /* This must come second. */
+ w2 = 1.0f - w1; /* This must come first. */
}
else {
/* - these weights are derived from the relative distance of these
@@ -682,13 +406,13 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, flo
case POSESLIDE_PUSH: /* Make the current pose more pronounced. */
{
/* Slide the pose away from the breakdown pose in the timeline */
- (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * pso->factor;
+ (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * ED_slider_factor_get(pso->slider);
break;
}
case POSESLIDE_RELAX: /* Make the current pose more like its surrounding ones. */
{
/* Slide the pose towards the breakdown pose in the timeline */
- (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * pso->factor;
+ (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * ED_slider_factor_get(pso->slider);
break;
}
case POSESLIDE_BREAKDOWN: /* Make the current pose slide around between the endpoints. */
@@ -888,7 +612,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
normalize_qt(quat_prev);
normalize_qt(quat_next);
- interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->factor);
+ interp_qt_qtqt(quat_final, quat_prev, quat_next, ED_slider_factor_get(pso->slider));
}
else {
/* POSESLIDE_PUSH and POSESLIDE_RELAX. */
@@ -906,11 +630,12 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
normalize_qt(quat_curr);
if (pso->mode == POSESLIDE_PUSH) {
- interp_qt_qtqt(quat_final, quat_breakdown, quat_curr, 1.0f + pso->factor);
+ interp_qt_qtqt(
+ quat_final, quat_breakdown, quat_curr, 1.0f + ED_slider_factor_get(pso->slider));
}
else {
BLI_assert(pso->mode == POSESLIDE_RELAX);
- interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, pso->factor);
+ interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, ED_slider_factor_get(pso->slider));
}
}
@@ -931,11 +656,11 @@ static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], flo
((lock & PS_LOCK_Z) && (idx == 2))) {
float diff_val = default_value - vec[idx];
if (pso->mode == POSESLIDE_RELAX_REST) {
- vec[idx] += pso->factor * diff_val;
+ vec[idx] += ED_slider_factor_get(pso->slider) * diff_val;
}
else {
/* Push */
- vec[idx] -= pso->factor * diff_val;
+ vec[idx] -= ED_slider_factor_get(pso->slider) * diff_val;
}
}
}
@@ -953,11 +678,11 @@ static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4]
for (int idx = 0; idx < 4; idx++) {
float diff_val = default_values[idx] - vec[idx];
if (pso->mode == POSESLIDE_RELAX_REST) {
- vec[idx] += pso->factor * diff_val;
+ vec[idx] += ED_slider_factor_get(pso->slider) * diff_val;
}
else {
/* Push */
- vec[idx] -= pso->factor * diff_val;
+ vec[idx] -= ED_slider_factor_get(pso->slider) * diff_val;
}
}
}
@@ -1130,9 +855,7 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
char limits_str[UI_MAX_DRAW_STR];
char axis_str[50];
char mode_str[32];
- char overshoot_str[50];
- char precision_str[50];
- char increments_str[50];
+ char slider_str[UI_MAX_DRAW_STR];
char bone_vis_str[50];
switch (pso->mode) {
@@ -1203,29 +926,10 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
break;
}
- if (pso->overshoot) {
- STRNCPY(overshoot_str, TIP_("[E] - Disable overshoot"));
- }
- else {
- STRNCPY(overshoot_str, TIP_("[E] - Enable overshoot"));
- }
-
- if (pso->precision) {
- STRNCPY(precision_str, TIP_("[Shift] - Precision active"));
- }
- else {
- STRNCPY(precision_str, TIP_("Shift - Hold for precision"));
- }
-
- if (pso->increments) {
- STRNCPY(increments_str, TIP_("[Ctrl] - Increments active"));
- }
- else {
- STRNCPY(increments_str, TIP_("Ctrl - Hold for 10% increments"));
- }
-
STRNCPY(bone_vis_str, TIP_("[H] - Toggle bone visibility"));
+ ED_slider_status_string_get(pso->slider, slider_str, sizeof(slider_str));
+
if (hasNumInput(&pso->num)) {
Scene *scene = pso->scene;
char str_offs[NUM_STR_REP_LEN];
@@ -1237,12 +941,10 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
else {
BLI_snprintf(status_str,
sizeof(status_str),
- "%s: %s | %s | %s | %s | %s",
+ "%s: %s | %s | %s",
mode_str,
limits_str,
- overshoot_str,
- precision_str,
- increments_str,
+ slider_str,
bone_vis_str);
}
@@ -1253,11 +955,15 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
/**
* Common code for invoke() methods.
*/
-static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
+static int pose_slide_invoke_common(bContext *C, wmOperator *op, const wmEvent *event)
{
tPChanFCurveLink *pfl;
wmWindow *win = CTX_wm_window(C);
+ tPoseSlideOp *pso = op->customdata;
+
+ ED_slider_init(pso->slider, event);
+
/* For each link, add all its keyframes to the search tree. */
for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
LinkData *ld;
@@ -1315,7 +1021,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
}
else {
BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_CANCELLED;
}
@@ -1349,29 +1055,6 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
}
/**
- * Calculate factor based on mouse movement, clamp or round to increments if
- * enabled by the user. Store the new factor value.
- */
-static void pose_slide_mouse_update_factor(tPoseSlideOp *pso, wmOperator *op, const wmEvent *event)
-{
- const float factor_delta = (event->x - pso->last_cursor_x) / ((float)(SLIDE_PIXEL_DISTANCE));
- /* Reduced factor delta in precision mode (shift held). */
- pso->raw_factor += pso->precision ? (factor_delta / 8) : factor_delta;
- pso->factor = pso->raw_factor;
- pso->last_cursor_x = event->x;
-
- if (!pso->overshoot) {
- pso->factor = clamp_f(pso->factor, 0, 1);
- }
-
- if (pso->increments) {
- pso->factor = round(pso->factor * 10) / 10;
- }
-
- RNA_float_set(op->ptr, "factor", pso->factor);
-}
-
-/**
* Handle an event to toggle channels mode.
*/
static void pose_slide_toggle_channels_mode(wmOperator *op,
@@ -1434,6 +1117,8 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
const bool has_numinput = hasNumInput(&pso->num);
+ do_pose_update = ED_slider_modal(pso->slider, event);
+
switch (event->type) {
case LEFTMOUSE: /* Confirm. */
case EVT_RETKEY:
@@ -1449,7 +1134,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Insert keyframes as required. */
pose_slide_autoKeyframe(C, pso);
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
/* Done! */
return OPERATOR_FINISHED;
@@ -1472,7 +1157,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
pose_slide_refresh(C, pso);
/* Clean up temp data. */
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
/* Canceled! */
return OPERATOR_CANCELLED;
@@ -1485,9 +1170,6 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
/* Only handle mouse-move if not doing numinput. */
if (has_numinput == false) {
- /* Update factor based on position of mouse. */
- pose_slide_mouse_update_factor(pso, op, event);
-
/* Update pose to reflect the new values (see below). */
do_pose_update = true;
}
@@ -1500,12 +1182,13 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Grab percentage from numeric input, and store this new value for redo
* NOTE: users see ints, while internally we use a 0-1 float
*/
- value = pso->factor * 100.0f;
+ value = ED_slider_factor_get(pso->slider) * 100.0f;
applyNumInput(&pso->num, &value);
- pso->factor = value / 100.0f;
- CLAMP(pso->factor, 0.0f, 1.0f);
- RNA_float_set(op->ptr, "factor", pso->factor);
+ float factor = value / 100;
+ CLAMP(factor, 0.0f, 1.0f);
+ ED_slider_factor_set(pso->slider, factor);
+ RNA_float_set(op->ptr, "factor", ED_slider_factor_get(pso->slider));
/* Update pose to reflect the new values (see below) */
do_pose_update = true;
@@ -1567,29 +1250,6 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
- /* Overshoot. */
- case EVT_EKEY: {
- pso->overshoot = !pso->overshoot;
- do_pose_update = true;
- break;
- }
-
- /* Precision mode. */
- case EVT_LEFTSHIFTKEY:
- case EVT_RIGHTSHIFTKEY: {
- pso->precision = true;
- do_pose_update = true;
- break;
- }
-
- /* Increments mode. */
- case EVT_LEFTCTRLKEY:
- case EVT_RIGHTCTRLKEY: {
- pso->increments = true;
- do_pose_update = true;
- break;
- }
-
/* Toggle Bone visibility. */
case EVT_HKEY: {
View3D *v3d = pso->area->spacedata.first;
@@ -1600,25 +1260,6 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
}
- /* Precision and stepping only active while button is held. */
- else if (event->val == KM_RELEASE) {
- switch (event->type) {
- case EVT_LEFTSHIFTKEY:
- case EVT_RIGHTSHIFTKEY: {
- pso->precision = false;
- do_pose_update = true;
- break;
- }
- case EVT_LEFTCTRLKEY:
- case EVT_RIGHTCTRLKEY: {
- pso->increments = false;
- do_pose_update = true;
- break;
- }
- default:
- break;
- }
- }
else {
/* Unhandled event - maybe it was some view manipulation? */
/* Allow to pass through. */
@@ -1652,10 +1293,10 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/**
* Common code for cancel()
*/
-static void pose_slide_cancel(bContext *UNUSED(C), wmOperator *op)
+static void pose_slide_cancel(bContext *C, wmOperator *op)
{
/* Cleanup and done. */
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
}
/**
@@ -1675,7 +1316,7 @@ static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso
pose_slide_autoKeyframe(C, pso);
/* Cleanup and done. */
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_FINISHED;
}
@@ -1743,23 +1384,14 @@ static void pose_slide_opdef_properties(wmOperatorType *ot)
*/
static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso;
-
/* Initialize data. */
if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_CANCELLED;
}
- pso = op->customdata;
-
- pso->last_cursor_x = event->x;
-
- /* Initialize factor so that it won't pop on first mouse move. */
- pose_slide_mouse_update_factor(pso, op, event);
-
/* Do common setup work. */
- return pose_slide_invoke_common(C, op, pso);
+ return pose_slide_invoke_common(C, op, event);
}
/**
@@ -1771,7 +1403,7 @@ static int pose_slide_push_exec(bContext *C, wmOperator *op)
/* Initialize data (from RNA-props). */
if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_CANCELLED;
}
@@ -1809,23 +1441,14 @@ void POSE_OT_push(wmOperatorType *ot)
*/
static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso;
-
/* Initialize data. */
if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_CANCELLED;
}
- pso = op->customdata;
-
- pso->last_cursor_x = event->x;
-
- /* Initialize factor so that it won't pop on first mouse move. */
- pose_slide_mouse_update_factor(pso, op, event);
-
/* Do common setup work. */
- return pose_slide_invoke_common(C, op, pso);
+ return pose_slide_invoke_common(C, op, event);
}
/**
@@ -1837,7 +1460,7 @@ static int pose_slide_relax_exec(bContext *C, wmOperator *op)
/* Initialize data (from RNA-props). */
if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_CANCELLED;
}
@@ -1874,23 +1497,14 @@ void POSE_OT_relax(wmOperatorType *ot)
*/
static int pose_slide_push_rest_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso;
-
/* Initialize data. */
if (pose_slide_init(C, op, POSESLIDE_PUSH_REST) == 0) {
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_CANCELLED;
}
- pso = op->customdata;
-
- pso->last_cursor_x = event->x;
-
- /* Initialize factor so that it won't pop on first mouse move. */
- pose_slide_mouse_update_factor(pso, op, event);
-
/* do common setup work */
- return pose_slide_invoke_common(C, op, pso);
+ return pose_slide_invoke_common(C, op, event);
}
/**
@@ -1902,7 +1516,7 @@ static int pose_slide_push_rest_exec(bContext *C, wmOperator *op)
/* Initialize data (from RNA-props). */
if (pose_slide_init(C, op, POSESLIDE_PUSH_REST) == 0) {
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_CANCELLED;
}
@@ -1940,23 +1554,14 @@ void POSE_OT_push_rest(wmOperatorType *ot)
*/
static int pose_slide_relax_rest_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso;
-
/* Initialize data. */
if (pose_slide_init(C, op, POSESLIDE_RELAX_REST) == 0) {
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_CANCELLED;
}
- pso = op->customdata;
-
- pso->last_cursor_x = event->x;
-
- /* Initialize factor so that it won't pop on first mouse move. */
- pose_slide_mouse_update_factor(pso, op, event);
-
/* Do common setup work. */
- return pose_slide_invoke_common(C, op, pso);
+ return pose_slide_invoke_common(C, op, event);
}
/**
@@ -1968,7 +1573,7 @@ static int pose_slide_relax_rest_exec(bContext *C, wmOperator *op)
/* Initialize data (from RNA-props). */
if (pose_slide_init(C, op, POSESLIDE_RELAX_REST) == 0) {
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_CANCELLED;
}
@@ -2006,23 +1611,14 @@ void POSE_OT_relax_rest(wmOperatorType *ot)
*/
static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso;
-
/* Initialize data. */
if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_CANCELLED;
}
- pso = op->customdata;
-
- pso->last_cursor_x = event->x;
-
- /* Initialize factor so that it won't pop on first mouse move. */
- pose_slide_mouse_update_factor(pso, op, event);
-
/* Do common setup work. */
- return pose_slide_invoke_common(C, op, pso);
+ return pose_slide_invoke_common(C, op, event);
}
/**
@@ -2034,7 +1630,7 @@ static int pose_slide_breakdown_exec(bContext *C, wmOperator *op)
/* Initialize data (from RNA-props). */
if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
- pose_slide_exit(op);
+ pose_slide_exit(C, op);
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt
index a27975bc37b..d56edd43d7d 100644
--- a/source/blender/editors/asset/CMakeLists.txt
+++ b/source/blender/editors/asset/CMakeLists.txt
@@ -16,6 +16,7 @@
# ***** END GPL LICENSE BLOCK *****
set(INC
+ .
../include
../../blenkernel
../../blenlib
@@ -30,10 +31,21 @@ set(INC_SYS
)
set(SRC
- asset_edit.cc
- asset_list.cc
- asset_ops.cc
- asset_temp_id_consumer.cc
+ intern/asset_handle.cc
+ intern/asset_library_reference.cc
+ intern/asset_library_reference_enum.cc
+ intern/asset_list.cc
+ intern/asset_mark_clear.cc
+ intern/asset_ops.cc
+ intern/asset_temp_id_consumer.cc
+
+ ED_asset_handle.h
+ ED_asset_library.h
+ ED_asset_list.h
+ ED_asset_list.hh
+ ED_asset_mark_clear.h
+ ED_asset_temp_id_consumer.h
+ intern/asset_library_reference.hh
)
set(LIB
diff --git a/source/blender/editors/asset/ED_asset_handle.h b/source/blender/editors/asset/ED_asset_handle.h
new file mode 100644
index 00000000000..c51ce422c25
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_handle.h
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ */
+
+#pragma once
+
+#include "DNA_ID_enums.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AssetHandle;
+struct AssetLibraryReference;
+struct bContext;
+
+const char *ED_asset_handle_get_name(const struct AssetHandle *asset);
+struct AssetMetaData *ED_asset_handle_get_metadata(const struct AssetHandle *asset);
+struct ID *ED_asset_handle_get_local_id(const struct AssetHandle *asset);
+ID_Type ED_asset_handle_get_id_type(const struct AssetHandle *asset);
+int ED_asset_handle_get_preview_icon_id(const struct AssetHandle *asset);
+void ED_asset_handle_get_full_library_path(const struct bContext *C,
+ const struct AssetLibraryReference *asset_library,
+ const struct AssetHandle *asset,
+ char r_full_lib_path[]);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/asset/ED_asset_library.h b/source/blender/editors/asset/ED_asset_library.h
new file mode 100644
index 00000000000..905d097d223
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_library.h
@@ -0,0 +1,35 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ */
+
+#pragma once
+
+#include "DNA_asset_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library);
+AssetLibraryReference ED_asset_library_reference_from_enum_value(int value);
+const struct EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h
new file mode 100644
index 00000000000..1e7f0f0de55
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_list.h
@@ -0,0 +1,54 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AssetFilterSettings;
+struct AssetHandle;
+struct AssetLibraryReference;
+struct bContext;
+struct ID;
+struct wmNotifier;
+
+void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference,
+ const struct AssetFilterSettings *filter_settings,
+ const struct bContext *C);
+void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference,
+ struct bContext *C);
+void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C);
+bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference);
+void ED_assetlist_storage_tag_main_data_dirty(void);
+void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new);
+void ED_assetlist_storage_exit(void);
+
+struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle);
+const char *ED_assetlist_library_path(const struct AssetLibraryReference *library_reference);
+
+bool ED_assetlist_listen(const struct AssetLibraryReference *library_reference,
+ const struct wmNotifier *notifier);
+int ED_assetlist_size(const struct AssetLibraryReference *library_reference);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/asset/ED_asset_list.hh b/source/blender/editors/asset/ED_asset_list.hh
new file mode 100644
index 00000000000..7f41fba3457
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_list.hh
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ */
+
+#pragma once
+
+#include <string>
+
+#include "BLI_function_ref.hh"
+
+struct AssetLibraryReference;
+struct AssetHandle;
+struct bContext;
+struct FileDirEntry;
+
+std::string ED_assetlist_asset_filepath_get(const bContext *C,
+ const AssetLibraryReference &library_reference,
+ const AssetHandle &asset_handle);
+
+/* Can return false to stop iterating. */
+using AssetListIterFn = blender::FunctionRef<bool(FileDirEntry &)>;
+void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn);
diff --git a/source/blender/editors/asset/ED_asset_mark_clear.h b/source/blender/editors/asset/ED_asset_mark_clear.h
new file mode 100644
index 00000000000..cdd1f0d080b
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_mark_clear.h
@@ -0,0 +1,37 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bContext;
+struct ID;
+
+bool ED_asset_mark_id(const struct bContext *C, struct ID *id);
+bool ED_asset_clear_id(struct ID *id);
+
+bool ED_asset_can_mark_single_from_context(const struct bContext *C);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/asset/ED_asset_temp_id_consumer.h b/source/blender/editors/asset/ED_asset_temp_id_consumer.h
new file mode 100644
index 00000000000..8aa53f9ea3b
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_temp_id_consumer.h
@@ -0,0 +1,48 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ */
+
+#pragma once
+
+#include "DNA_ID_enums.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct AssetTempIDConsumer AssetTempIDConsumer;
+
+struct AssetHandle;
+struct AssetLibraryReference;
+struct bContext;
+struct Main;
+struct ReportList;
+
+AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const struct AssetHandle *handle);
+void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer);
+struct ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer,
+ const struct bContext *C,
+ const struct AssetLibraryReference *asset_library,
+ ID_Type id_type,
+ struct Main *bmain,
+ struct ReportList *reports);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/asset/asset_edit.cc b/source/blender/editors/asset/asset_edit.cc
deleted file mode 100644
index f4860737193..00000000000
--- a/source/blender/editors/asset/asset_edit.cc
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup edasset
- */
-
-#include <memory>
-#include <string>
-
-#include "BKE_asset.h"
-#include "BKE_context.h"
-#include "BKE_lib_id.h"
-
-#include "BLO_readfile.h"
-
-#include "DNA_ID.h"
-#include "DNA_asset_types.h"
-#include "DNA_space_types.h"
-
-#include "UI_interface_icons.h"
-
-#include "RNA_access.h"
-
-#include "ED_asset.h"
-
-using namespace blender;
-
-bool ED_asset_mark_id(const bContext *C, ID *id)
-{
- if (id->asset_data) {
- return false;
- }
- if (!BKE_id_can_be_asset(id)) {
- return false;
- }
-
- id_fake_user_set(id);
-
- id->asset_data = BKE_asset_metadata_create();
-
- UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true);
-
- /* Important for asset storage to update properly! */
- ED_assetlist_storage_tag_main_data_dirty();
-
- return true;
-}
-
-bool ED_asset_clear_id(ID *id)
-{
- if (!id->asset_data) {
- return false;
- }
- BKE_asset_metadata_free(&id->asset_data);
- /* Don't clear fake user here, there's no guarantee that it was actually set by
- * #ED_asset_mark_id(), it might have been something/someone else. */
-
- /* Important for asset storage to update properly! */
- ED_assetlist_storage_tag_main_data_dirty();
-
- return true;
-}
-
-bool ED_asset_can_make_single_from_context(const bContext *C)
-{
- /* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */
- return CTX_data_pointer_get_type_silent(C, "id", &RNA_ID).data != nullptr;
-}
-
-/* TODO better place? */
-/* TODO What about the setter and the `itemf` callback? */
-#include "BKE_preferences.h"
-#include "DNA_asset_types.h"
-#include "DNA_userdef_types.h"
-int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library)
-{
- /* Simple case: Predefined repository, just set the value. */
- if (library->type < ASSET_LIBRARY_CUSTOM) {
- return library->type;
- }
-
- /* Note that the path isn't checked for validity here. If an invalid library path is used, the
- * Asset Browser can give a nice hint on what's wrong. */
- const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
- &U, library->custom_library_index);
- if (user_library) {
- return ASSET_LIBRARY_CUSTOM + library->custom_library_index;
- }
-
- BLI_assert(0);
- return ASSET_LIBRARY_LOCAL;
-}
-
-AssetLibraryReference ED_asset_library_reference_from_enum_value(int value)
-{
- AssetLibraryReference library;
-
- /* Simple case: Predefined repository, just set the value. */
- if (value < ASSET_LIBRARY_CUSTOM) {
- library.type = value;
- library.custom_library_index = -1;
- BLI_assert(ELEM(value, ASSET_LIBRARY_LOCAL));
- return library;
- }
-
- const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
- &U, value - ASSET_LIBRARY_CUSTOM);
-
- /* Note that the path isn't checked for validity here. If an invalid library path is used, the
- * Asset Browser can give a nice hint on what's wrong. */
- const bool is_valid = (user_library->name[0] && user_library->path[0]);
- if (!user_library) {
- library.type = ASSET_LIBRARY_LOCAL;
- library.custom_library_index = -1;
- }
- else if (user_library && is_valid) {
- library.custom_library_index = value - ASSET_LIBRARY_CUSTOM;
- library.type = ASSET_LIBRARY_CUSTOM;
- }
- return library;
-}
-
-const char *ED_asset_handle_get_name(const AssetHandle *asset)
-{
- return asset->file_data->name;
-}
-
-void ED_asset_handle_get_full_library_path(const bContext *C,
- const AssetLibraryReference *asset_library,
- const AssetHandle *asset,
- char r_full_lib_path[FILE_MAX_LIBEXTRA])
-{
- *r_full_lib_path = '\0';
-
- std::string asset_path = ED_assetlist_asset_filepath_get(C, *asset_library, *asset);
- if (asset_path.empty()) {
- return;
- }
-
- BLO_library_path_explode(asset_path.c_str(), r_full_lib_path, nullptr, nullptr);
-}
diff --git a/source/blender/editors/asset/intern/asset_handle.cc b/source/blender/editors/asset/intern/asset_handle.cc
new file mode 100644
index 00000000000..aae85e61372
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_handle.cc
@@ -0,0 +1,75 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ *
+ * Asset-handle is a temporary design, not part of the core asset system design.
+ *
+ * Currently asset-list items are just file directory items (#FileDirEntry). So an asset-handle is
+ * just wraps a pointer to this. We try to abstract away the fact that it's just a file entry,
+ * although that doesn't always work (see #rna_def_asset_handle()).
+ */
+
+#include <string>
+
+#include "DNA_asset_types.h"
+#include "DNA_space_types.h"
+
+#include "BLO_readfile.h"
+
+#include "ED_asset_handle.h"
+#include "ED_asset_list.hh"
+
+const char *ED_asset_handle_get_name(const AssetHandle *asset)
+{
+ return asset->file_data->name;
+}
+
+AssetMetaData *ED_asset_handle_get_metadata(const AssetHandle *asset)
+{
+ return asset->file_data->asset_data;
+}
+
+ID *ED_asset_handle_get_local_id(const AssetHandle *asset)
+{
+ return asset->file_data->id;
+}
+
+ID_Type ED_asset_handle_get_id_type(const AssetHandle *asset)
+{
+ return static_cast<ID_Type>(asset->file_data->blentype);
+}
+
+int ED_asset_handle_get_preview_icon_id(const AssetHandle *asset)
+{
+ return asset->file_data->preview_icon_id;
+}
+
+void ED_asset_handle_get_full_library_path(const bContext *C,
+ const AssetLibraryReference *asset_library,
+ const AssetHandle *asset,
+ char r_full_lib_path[FILE_MAX_LIBEXTRA])
+{
+ *r_full_lib_path = '\0';
+
+ std::string asset_path = ED_assetlist_asset_filepath_get(C, *asset_library, *asset);
+ if (asset_path.empty()) {
+ return;
+ }
+
+ BLO_library_path_explode(asset_path.c_str(), r_full_lib_path, nullptr, nullptr);
+}
diff --git a/source/blender/editors/asset/intern/asset_library_reference.cc b/source/blender/editors/asset/intern/asset_library_reference.cc
new file mode 100644
index 00000000000..df1d58df5f9
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_library_reference.cc
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ */
+
+#include "BLI_hash.hh"
+
+#include "asset_library_reference.hh"
+
+namespace blender::ed::asset {
+
+AssetLibraryReferenceWrapper::AssetLibraryReferenceWrapper(const AssetLibraryReference &reference)
+ : AssetLibraryReference(reference)
+{
+}
+
+bool operator==(const AssetLibraryReferenceWrapper &a, const AssetLibraryReferenceWrapper &b)
+{
+ return (a.type == b.type) && (a.type == ASSET_LIBRARY_CUSTOM) ?
+ (a.custom_library_index == b.custom_library_index) :
+ true;
+}
+
+uint64_t AssetLibraryReferenceWrapper::hash() const
+{
+ uint64_t hash1 = DefaultHash<decltype(type)>{}(type);
+ if (type != ASSET_LIBRARY_CUSTOM) {
+ return hash1;
+ }
+
+ uint64_t hash2 = DefaultHash<decltype(custom_library_index)>{}(custom_library_index);
+ return hash1 ^ (hash2 * 33); /* Copied from DefaultHash for std::pair. */
+}
+
+} // namespace blender::ed::asset
diff --git a/source/blender/editors/asset/intern/asset_library_reference.hh b/source/blender/editors/asset/intern/asset_library_reference.hh
new file mode 100644
index 00000000000..7e8cb4a3472
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_library_reference.hh
@@ -0,0 +1,46 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ *
+ * Utility to extend #AssetLibraryReference with C++ functionality (operators, hash function, etc).
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include "DNA_asset_types.h"
+
+namespace blender::ed::asset {
+
+/**
+ * Wrapper to add logic to the AssetLibraryReference DNA struct.
+ */
+class AssetLibraryReferenceWrapper : public AssetLibraryReference {
+ public:
+ /* Intentionally not `explicit`, allow implicit conversion for convenience. Might have to be
+ * NOLINT */
+ AssetLibraryReferenceWrapper(const AssetLibraryReference &reference);
+ ~AssetLibraryReferenceWrapper() = default;
+
+ friend bool operator==(const AssetLibraryReferenceWrapper &a,
+ const AssetLibraryReferenceWrapper &b);
+ uint64_t hash() const;
+};
+
+} // namespace blender::ed::asset
diff --git a/source/blender/editors/asset/intern/asset_library_reference_enum.cc b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
new file mode 100644
index 00000000000..13595ffa6ba
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
@@ -0,0 +1,156 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ *
+ * Helpers to convert asset library references from and to enum values and RNA enums.
+ * In some cases it's simply not possible to reference an asset library with
+ * #AssetLibraryReferences. This API guarantees a safe translation to indices/enum values for as
+ * long as there is no change in the order of registered custom asset libraries.
+ */
+
+#include "BLI_listbase.h"
+
+#include "BKE_preferences.h"
+
+#include "DNA_asset_types.h"
+#include "DNA_userdef_types.h"
+
+#include "UI_resources.h"
+
+#include "RNA_define.h"
+
+#include "ED_asset_library.h"
+
+/**
+ * Return an index that can be used to uniquely identify \a library, assuming
+ * that all relevant indices were created with this function.
+ */
+int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library)
+{
+ /* Simple case: Predefined repository, just set the value. */
+ if (library->type < ASSET_LIBRARY_CUSTOM) {
+ return library->type;
+ }
+
+ /* Note that the path isn't checked for validity here. If an invalid library path is used, the
+ * Asset Browser can give a nice hint on what's wrong. */
+ const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
+ &U, library->custom_library_index);
+ if (user_library) {
+ return ASSET_LIBRARY_CUSTOM + library->custom_library_index;
+ }
+
+ BLI_assert_unreachable();
+ return ASSET_LIBRARY_LOCAL;
+}
+
+/**
+ * Return an asset library reference matching the index returned by
+ * #ED_asset_library_reference_to_enum_value().
+ */
+AssetLibraryReference ED_asset_library_reference_from_enum_value(int value)
+{
+ AssetLibraryReference library;
+
+ /* Simple case: Predefined repository, just set the value. */
+ if (value < ASSET_LIBRARY_CUSTOM) {
+ library.type = value;
+ library.custom_library_index = -1;
+ BLI_assert(ELEM(value, ASSET_LIBRARY_LOCAL));
+ return library;
+ }
+
+ const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
+ &U, value - ASSET_LIBRARY_CUSTOM);
+
+ /* Note that there is no check if the path exists here. If an invalid library path is used, the
+ * Asset Browser can give a nice hint on what's wrong. */
+ const bool is_valid = (user_library->name[0] && user_library->path[0]);
+ if (!user_library) {
+ library.type = ASSET_LIBRARY_LOCAL;
+ library.custom_library_index = -1;
+ }
+ else if (user_library && is_valid) {
+ library.custom_library_index = value - ASSET_LIBRARY_CUSTOM;
+ library.type = ASSET_LIBRARY_CUSTOM;
+ }
+ return library;
+}
+
+/**
+ * Translate all available asset libraries to an RNA enum, whereby the enum values match the result
+ * of #ED_asset_library_reference_to_enum_value() for any given library.
+ *
+ * Since this is meant for UI display, skips non-displayable libraries, that is, libraries with an
+ * empty name or path.
+ */
+const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf()
+{
+ const EnumPropertyItem predefined_items[] = {
+ /* For the future. */
+ // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
+ {ASSET_LIBRARY_LOCAL,
+ "LOCAL",
+ ICON_BLENDER,
+ "Current File",
+ "Show the assets currently available in this Blender session"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+
+ /* Add separator if needed. */
+ if (!BLI_listbase_is_empty(&U.asset_libraries)) {
+ const EnumPropertyItem sepr = {0, "", 0, "Custom", NULL};
+ RNA_enum_item_add(&item, &totitem, &sepr);
+ }
+
+ int i = 0;
+ for (bUserAssetLibrary *user_library = (bUserAssetLibrary *)U.asset_libraries.first;
+ user_library;
+ user_library = user_library->next, i++) {
+ /* Note that the path itself isn't checked for validity here. If an invalid library path is
+ * used, the Asset Browser can give a nice hint on what's wrong. */
+ const bool is_valid = (user_library->name[0] && user_library->path[0]);
+ if (!is_valid) {
+ continue;
+ }
+
+ AssetLibraryReference library_reference;
+ library_reference.type = ASSET_LIBRARY_CUSTOM;
+ library_reference.custom_library_index = i;
+
+ const int enum_value = ED_asset_library_reference_to_enum_value(&library_reference);
+ /* Use library path as description, it's a nice hint for users. */
+ EnumPropertyItem tmp = {
+ enum_value, user_library->name, ICON_NONE, user_library->name, user_library->path};
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ }
+
+ if (totitem) {
+ const EnumPropertyItem sepr = {0, "", 0, "Built-in", NULL};
+ RNA_enum_item_add(&item, &totitem, &sepr);
+ }
+
+ /* Add predefined items. */
+ RNA_enum_items_add(&item, &totitem, predefined_items);
+
+ RNA_enum_item_end(&item, &totitem);
+ return item;
+}
diff --git a/source/blender/editors/asset/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc
index dd1c5f360a0..445269d563e 100644
--- a/source/blender/editors/asset/asset_list.cc
+++ b/source/blender/editors/asset/intern/asset_list.cc
@@ -26,12 +26,8 @@
#include <optional>
#include <string>
-#include "BKE_asset.h"
#include "BKE_context.h"
-#include "BKE_screen.h"
-#include "BLI_function_ref.hh"
-#include "BLI_hash.hh"
#include "BLI_map.hh"
#include "BLI_path_util.h"
#include "BLI_utility_mixins.hh"
@@ -41,9 +37,7 @@
#include "BKE_preferences.h"
-#include "ED_asset.h"
#include "ED_fileselect.h"
-#include "ED_screen.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -51,48 +45,12 @@
/* XXX uses private header of file-space. */
#include "../space_file/filelist.h"
-using namespace blender;
+#include "ED_asset_handle.h"
+#include "ED_asset_list.h"
+#include "ED_asset_list.hh"
+#include "asset_library_reference.hh"
-/**
- * Wrapper to add logic to the AssetLibraryReference DNA struct.
- */
-class AssetLibraryReferenceWrapper {
- const AssetLibraryReference reference_;
-
- public:
- /* Intentionally not `explicit`, allow implicit conversion for convenience. Might have to be
- * NOLINT */
- AssetLibraryReferenceWrapper(const AssetLibraryReference &reference);
- ~AssetLibraryReferenceWrapper() = default;
-
- friend bool operator==(const AssetLibraryReferenceWrapper &a,
- const AssetLibraryReferenceWrapper &b);
- uint64_t hash() const;
-};
-
-AssetLibraryReferenceWrapper::AssetLibraryReferenceWrapper(const AssetLibraryReference &reference)
- : reference_(reference)
-{
-}
-
-bool operator==(const AssetLibraryReferenceWrapper &a, const AssetLibraryReferenceWrapper &b)
-{
- return (a.reference_.type == b.reference_.type) && (a.reference_.type == ASSET_LIBRARY_CUSTOM) ?
- (a.reference_.custom_library_index == b.reference_.custom_library_index) :
- true;
-}
-
-uint64_t AssetLibraryReferenceWrapper::hash() const
-{
- uint64_t hash1 = DefaultHash<decltype(reference_.type)>{}(reference_.type);
- if (reference_.type != ASSET_LIBRARY_CUSTOM) {
- return hash1;
- }
-
- uint64_t hash2 = DefaultHash<decltype(reference_.custom_library_index)>{}(
- reference_.custom_library_index);
- return hash1 ^ (hash2 * 33); /* Copied from DefaultHash for std::pair. */
-}
+namespace blender::ed::asset {
/* -------------------------------------------------------------------- */
/** \name Asset list API
@@ -187,11 +145,6 @@ void AssetList::setup(const AssetFilterSettings *filter_settings)
{
FileList *files = filelist_;
- /* TODO there should only be one (FileSelectAssetLibraryUID vs. AssetLibraryReference). */
- FileSelectAssetLibraryUID file_asset_lib_ref;
- file_asset_lib_ref.type = library_ref_.type;
- file_asset_lib_ref.custom_library_index = library_ref_.custom_library_index;
-
bUserAssetLibrary *user_library = nullptr;
/* Ensure valid repository, or fall-back to local one. */
@@ -206,7 +159,7 @@ void AssetList::setup(const AssetFilterSettings *filter_settings)
/* TODO pass options properly. */
filelist_setrecursion(files, 1);
filelist_setsorting(files, FILE_SORT_ALPHA, false);
- filelist_setlibrary(files, &file_asset_lib_ref);
+ filelist_setlibrary(files, &library_ref_);
/* TODO different filtering settings require the list to be reread. That's a no-go for when we
* want to allow showing the same asset library with different filter settings (as in,
* different ID types). The filelist needs to be made smarter somehow, maybe goes together with
@@ -469,10 +422,14 @@ AssetListStorage::AssetListMap &AssetListStorage::global_storage()
/** \} */
+} // namespace blender::ed::asset
+
/* -------------------------------------------------------------------- */
/** \name C-API
* \{ */
+using namespace blender::ed::asset;
+
/**
* Invoke asset list reading, potentially in a parallel job. Won't wait until the job is done,
* and may return earlier.
@@ -506,7 +463,6 @@ bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *libr
return AssetListStorage::lookup_list(*library_reference) != nullptr;
}
-/* TODO expose AssetList with an iterator? */
void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
@@ -536,11 +492,12 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C,
const AssetLibraryReference &library_reference,
const AssetHandle &asset_handle)
{
- if (asset_handle.file_data->id || !asset_handle.file_data->asset_data) {
+ if (ED_asset_handle_get_local_id(&asset_handle) ||
+ !ED_asset_handle_get_metadata(&asset_handle)) {
return {};
}
const char *library_path = ED_assetlist_library_path(&library_reference);
- if (!library_path) {
+ if (!library_path && C) {
library_path = assetlist_library_path_from_sfile_get_hack(C);
}
if (!library_path) {
@@ -554,11 +511,6 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C,
return path;
}
-ID *ED_assetlist_asset_local_id_get(const AssetHandle *asset_handle)
-{
- return asset_handle->file_data->asset_data ? asset_handle->file_data->id : nullptr;
-}
-
ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle)
{
ImBuf *imbuf = filelist_file_getimage(asset_handle->file_data);
diff --git a/source/blender/editors/asset/intern/asset_mark_clear.cc b/source/blender/editors/asset/intern/asset_mark_clear.cc
new file mode 100644
index 00000000000..ba348e38823
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_mark_clear.cc
@@ -0,0 +1,83 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ *
+ * Functions for marking and clearing assets.
+ */
+
+#include <memory>
+#include <string>
+
+#include "BKE_asset.h"
+#include "BKE_context.h"
+#include "BKE_lib_id.h"
+
+#include "BLO_readfile.h"
+
+#include "DNA_ID.h"
+#include "DNA_asset_types.h"
+#include "DNA_space_types.h"
+
+#include "UI_interface_icons.h"
+
+#include "RNA_access.h"
+
+#include "ED_asset_list.h"
+#include "ED_asset_mark_clear.h"
+
+bool ED_asset_mark_id(const bContext *C, ID *id)
+{
+ if (id->asset_data) {
+ return false;
+ }
+ if (!BKE_id_can_be_asset(id)) {
+ return false;
+ }
+
+ id_fake_user_set(id);
+
+ id->asset_data = BKE_asset_metadata_create();
+
+ UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true);
+
+ /* Important for asset storage to update properly! */
+ ED_assetlist_storage_tag_main_data_dirty();
+
+ return true;
+}
+
+bool ED_asset_clear_id(ID *id)
+{
+ if (!id->asset_data) {
+ return false;
+ }
+ BKE_asset_metadata_free(&id->asset_data);
+ /* Don't clear fake user here, there's no guarantee that it was actually set by
+ * #ED_asset_mark_id(), it might have been something/someone else. */
+
+ /* Important for asset storage to update properly! */
+ ED_assetlist_storage_tag_main_data_dirty();
+
+ return true;
+}
+
+bool ED_asset_can_mark_single_from_context(const bContext *C)
+{
+ /* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */
+ return CTX_data_pointer_get_type_silent(C, "id", &RNA_ID).data != nullptr;
+}
diff --git a/source/blender/editors/asset/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index 79edd1f8a6a..79edd1f8a6a 100644
--- a/source/blender/editors/asset/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
diff --git a/source/blender/editors/asset/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
index 24e1fc86fef..bed35fdeeb5 100644
--- a/source/blender/editors/asset/asset_temp_id_consumer.cc
+++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
@@ -21,6 +21,8 @@
* Uses the `BLO_library_temp_xxx()` API internally.
*/
+#include <new>
+
#include "DNA_asset_types.h"
#include "DNA_space_types.h"
@@ -32,7 +34,8 @@
#include "MEM_guardedalloc.h"
-#include "ED_asset.h"
+#include "ED_asset_handle.h"
+#include "ED_asset_temp_id_consumer.h"
using namespace blender;
@@ -53,7 +56,7 @@ class AssetTemporaryIDConsumer : NonCopyable, NonMovable {
ID *get_local_id()
{
- return ED_assetlist_asset_local_id_get(&handle_);
+ return ED_asset_handle_get_local_id(&handle_);
}
ID *import_id(const bContext *C,
diff --git a/source/blender/editors/geometry/geometry_attributes.c b/source/blender/editors/geometry/geometry_attributes.c
index 9b034d82a51..5cb491f116a 100644
--- a/source/blender/editors/geometry/geometry_attributes.c
+++ b/source/blender/editors/geometry/geometry_attributes.c
@@ -47,6 +47,21 @@ static bool geometry_attributes_poll(bContext *C)
BKE_id_attributes_supported(data);
}
+static bool geometry_attributes_remove_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? ob->data : NULL;
+ if (BKE_id_attributes_active_get(data) != NULL) {
+ return true;
+ }
+
+ return false;
+}
+
static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -160,7 +175,7 @@ void GEOMETRY_OT_attribute_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = geometry_attribute_remove_exec;
- ot->poll = geometry_attributes_poll;
+ ot->poll = geometry_attributes_remove_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 78eaab01b1a..cf49aefe2ea 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -1316,8 +1316,7 @@ static void gpencil_primitive_interaction_end(bContext *C,
BrushGpencilSettings *brush_settings = brush->gpencil_settings;
const int def_nr = tgpi->gpd->vertex_group_active_index - 1;
- const ListBase *defbase = BKE_object_defgroup_list(tgpi->ob);
- const bool have_weight = (bool)BLI_findlink(defbase, def_nr);
+ const bool have_weight = BLI_findlink(&tgpi->gpd->vertex_group_names, def_nr) != NULL;
/* return to normal cursor and header status */
ED_workspace_status_text(C, NULL);
diff --git a/source/blender/editors/include/ED_asset.h b/source/blender/editors/include/ED_asset.h
index 0058c0615c3..42faf716560 100644
--- a/source/blender/editors/include/ED_asset.h
+++ b/source/blender/editors/include/ED_asset.h
@@ -16,66 +16,19 @@
/** \file
* \ingroup editors
+ *
+ * The public API for assets is defined in dedicated headers. This is a utility file that just
+ * includes all of these.
*/
#pragma once
-#include "DNA_ID_enums.h"
-
#ifdef __cplusplus
extern "C" {
#endif
-struct AssetFilterSettings;
-struct AssetLibraryReference;
-struct Main;
-struct ReportList;
-struct bContext;
-struct wmNotifier;
-
-typedef struct AssetTempIDConsumer AssetTempIDConsumer;
-
-bool ED_asset_mark_id(const struct bContext *C, struct ID *id);
-bool ED_asset_clear_id(struct ID *id);
-
-bool ED_asset_can_make_single_from_context(const struct bContext *C);
-
-int ED_asset_library_reference_to_enum_value(const struct AssetLibraryReference *library);
-struct AssetLibraryReference ED_asset_library_reference_from_enum_value(int value);
-
-const char *ED_asset_handle_get_name(const AssetHandle *asset);
-void ED_asset_handle_get_full_library_path(const struct bContext *C,
- const AssetLibraryReference *asset_library,
- const AssetHandle *asset,
- char r_full_lib_path[]);
-
-AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle);
-void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer);
-struct ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer,
- const struct bContext *C,
- const AssetLibraryReference *asset_library,
- ID_Type id_type,
- struct Main *bmain,
- struct ReportList *reports);
-
-void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference,
- const struct AssetFilterSettings *filter_settings,
- const struct bContext *C);
-void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference,
- struct bContext *C);
-void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C);
-bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference);
-void ED_assetlist_storage_tag_main_data_dirty(void);
-void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new);
-void ED_assetlist_storage_exit(void);
-
-ID *ED_assetlist_asset_local_id_get(const AssetHandle *asset_handle);
-struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle);
-const char *ED_assetlist_library_path(const struct AssetLibraryReference *library_reference);
-
-bool ED_assetlist_listen(const struct AssetLibraryReference *library_reference,
- const struct wmNotifier *notifier);
-int ED_assetlist_size(const struct AssetLibraryReference *library_reference);
+/* Barely anything here. Just general editor level functions. Actual asset level code is in
+ * dedicated headers. */
void ED_operatortypes_asset(void);
@@ -83,17 +36,13 @@ void ED_operatortypes_asset(void);
}
#endif
-/* TODO move to C++ asset-list header? */
-#ifdef __cplusplus
+#include "../asset/ED_asset_handle.h"
+#include "../asset/ED_asset_library.h"
+#include "../asset/ED_asset_list.h"
+#include "../asset/ED_asset_mark_clear.h"
+#include "../asset/ED_asset_temp_id_consumer.h"
-# include <string>
-
-std::string ED_assetlist_asset_filepath_get(const bContext *C,
- const AssetLibraryReference &library_reference,
- const AssetHandle &asset_handle);
-
-# include "BLI_function_ref.hh"
-/* Can return false to stop iterating. */
-using AssetListIterFn = blender::FunctionRef<bool(FileDirEntry &)>;
-void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn);
+/* C++ only headers. */
+#ifdef __cplusplus
+# include "../asset/ED_asset_list.hh"
#endif
diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h
index 2f8faf1b2bd..d2d22dd38dc 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -28,10 +28,7 @@ extern "C" {
#endif
struct AnimData;
-struct CacheFile;
-struct DLRBT_Tree;
struct FCurve;
-struct ListBase;
struct MaskLayer;
struct Object;
struct Scene;
@@ -42,99 +39,6 @@ struct bAnimContext;
struct bDopeSheet;
struct bGPDlayer;
-/* ****************************** Base Structs ****************************** */
-
-/* Information about the stretch of time from current to the next column */
-typedef struct ActKeyBlockInfo {
- /* Combination of flags from all curves. */
- short flag;
- /* Mask of flags that differ between curves. */
- short conflict;
-
- /* Selection flag. */
- char sel;
-} ActKeyBlockInfo;
-
-/* Keyframe Column Struct */
-typedef struct ActKeyColumn {
- /* ListBase linkage */
- struct ActKeyColumn *next, *prev;
-
- /* sorting-tree linkage */
- /** 'children' of this node, less than and greater than it (respectively) */
- struct ActKeyColumn *left, *right;
- /** parent of this node in the tree */
- struct ActKeyColumn *parent;
- /** DLRB_BLACK or DLRB_RED */
- char tree_col;
-
- /* keyframe info */
- /** eBezTripe_KeyframeType */
- char key_type;
- /** eKeyframeHandleDrawOpts */
- char handle_type;
- /** eKeyframeExtremeDrawOpts */
- char extreme_type;
- short sel;
- float cfra;
-
- /* key-block info */
- ActKeyBlockInfo block;
-
- /* number of curves and keys in this column */
- short totcurve, totkey, totblock;
-} ActKeyColumn;
-
-/* ActKeyBlockInfo - Flag */
-typedef enum eActKeyBlock_Hold {
- /* Key block represents a moving hold */
- ACTKEYBLOCK_FLAG_MOVING_HOLD = (1 << 0),
- /* Key block represents a static hold */
- ACTKEYBLOCK_FLAG_STATIC_HOLD = (1 << 1),
- /* Key block represents any kind of hold */
- ACTKEYBLOCK_FLAG_ANY_HOLD = (1 << 2),
- /* The curve segment uses non-bezier interpolation */
- ACTKEYBLOCK_FLAG_NON_BEZIER = (1 << 3),
- /* The block is grease pencil */
- ACTKEYBLOCK_FLAG_GPENCIL = (1 << 4),
-} eActKeyBlock_Flag;
-
-/* *********************** Keyframe Drawing ****************************** */
-
-/* options for keyframe shape drawing */
-typedef enum eKeyframeShapeDrawOpts {
- /* only the border */
- KEYFRAME_SHAPE_FRAME = 0,
- /* only the inside filling */
- KEYFRAME_SHAPE_INSIDE,
- /* the whole thing */
- KEYFRAME_SHAPE_BOTH,
-} eKeyframeShapeDrawOpts;
-
-/* Handle type. */
-typedef enum eKeyframeHandleDrawOpts {
- /* Don't draw */
- KEYFRAME_HANDLE_NONE = 0,
- /* Various marks in order of increasing display priority. */
- KEYFRAME_HANDLE_AUTO_CLAMP,
- KEYFRAME_HANDLE_AUTO,
- KEYFRAME_HANDLE_VECTOR,
- KEYFRAME_HANDLE_ALIGNED,
- KEYFRAME_HANDLE_FREE,
-} eKeyframeHandleDrawOpts;
-
-/* Extreme type. */
-typedef enum eKeyframeExtremeDrawOpts {
- KEYFRAME_EXTREME_NONE = 0,
- /* Minimum/maximum present. */
- KEYFRAME_EXTREME_MIN = (1 << 0),
- KEYFRAME_EXTREME_MAX = (1 << 1),
- /* Grouped keys have different states. */
- KEYFRAME_EXTREME_MIXED = (1 << 2),
- /* Both neighbors are equal to this key. */
- KEYFRAME_EXTREME_FLAT = (1 << 3),
-} eKeyframeExtremeDrawOpts;
-
/* draw simple diamond-shape keyframe */
/* caller should set up vertex format, bind GPU_SHADER_KEYFRAME_DIAMOND,
* immBegin(GPU_PRIM_POINTS, n), then call this n times */
@@ -216,59 +120,6 @@ void draw_masklay_channel(struct View2D *v2d,
float yscale_fac,
int saction_flag);
-/* Keydata Generation --------------- */
-/* F-Curve */
-void fcurve_to_keylist(struct AnimData *adt,
- struct FCurve *fcu,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* Action Group */
-void agroup_to_keylist(struct AnimData *adt,
- struct bActionGroup *agrp,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* Action */
-void action_to_keylist(struct AnimData *adt,
- struct bAction *act,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* Object */
-void ob_to_keylist(struct bDopeSheet *ads,
- struct Object *ob,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* Cache File */
-void cachefile_to_keylist(struct bDopeSheet *ads,
- struct CacheFile *cache_file,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* Scene */
-void scene_to_keylist(struct bDopeSheet *ads,
- struct Scene *sce,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* DopeSheet Summary */
-void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, int saction_flag);
-/* Grease Pencil datablock summary */
-void gpencil_to_keylist(struct bDopeSheet *ads,
- struct bGPdata *gpd,
- struct DLRBT_Tree *keys,
- const bool active);
-/* Grease Pencil Layer */
-void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys);
-/* Mask */
-void mask_to_keylist(struct bDopeSheet *ads, struct MaskLayer *masklay, struct DLRBT_Tree *keys);
-
-/* ActKeyColumn API ---------------- */
-/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
-short compare_ak_cfraPtr(void *node, void *data);
-
-/* Checks if ActKeyColumn has any block data */
-bool actkeyblock_is_valid(ActKeyColumn *ac);
-
-/* Checks if ActKeyColumn can be used as a block (i.e. drawn/used to detect "holds") */
-int actkeyblock_get_valid_hold(ActKeyColumn *ac);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_keyframes_keylist.h b/source/blender/editors/include/ED_keyframes_keylist.h
new file mode 100644
index 00000000000..be3eac66771
--- /dev/null
+++ b/source/blender/editors/include/ED_keyframes_keylist.h
@@ -0,0 +1,192 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AnimData;
+struct CacheFile;
+struct DLRBT_Tree;
+struct FCurve;
+struct MaskLayer;
+struct Object;
+struct Scene;
+struct bAnimContext;
+struct bDopeSheet;
+struct bGPDlayer;
+
+/* ****************************** Base Structs ****************************** */
+
+/* Information about the stretch of time from current to the next column */
+typedef struct ActKeyBlockInfo {
+ /* Combination of flags from all curves. */
+ short flag;
+ /* Mask of flags that differ between curves. */
+ short conflict;
+
+ /* Selection flag. */
+ char sel;
+} ActKeyBlockInfo;
+
+/* Keyframe Column Struct */
+typedef struct ActKeyColumn {
+ /* ListBase linkage */
+ struct ActKeyColumn *next, *prev;
+
+ /* sorting-tree linkage */
+ /** 'children' of this node, less than and greater than it (respectively) */
+ struct ActKeyColumn *left, *right;
+ /** parent of this node in the tree */
+ struct ActKeyColumn *parent;
+ /** DLRB_BLACK or DLRB_RED */
+ char tree_col;
+
+ /* keyframe info */
+ /** eBezTripe_KeyframeType */
+ char key_type;
+ /** eKeyframeHandleDrawOpts */
+ char handle_type;
+ /** eKeyframeExtremeDrawOpts */
+ char extreme_type;
+ short sel;
+ float cfra;
+
+ /* key-block info */
+ ActKeyBlockInfo block;
+
+ /* number of curves and keys in this column */
+ short totcurve, totkey, totblock;
+} ActKeyColumn;
+
+/* ActKeyBlockInfo - Flag */
+typedef enum eActKeyBlock_Hold {
+ /* Key block represents a moving hold */
+ ACTKEYBLOCK_FLAG_MOVING_HOLD = (1 << 0),
+ /* Key block represents a static hold */
+ ACTKEYBLOCK_FLAG_STATIC_HOLD = (1 << 1),
+ /* Key block represents any kind of hold */
+ ACTKEYBLOCK_FLAG_ANY_HOLD = (1 << 2),
+ /* The curve segment uses non-bezier interpolation */
+ ACTKEYBLOCK_FLAG_NON_BEZIER = (1 << 3),
+ /* The block is grease pencil */
+ ACTKEYBLOCK_FLAG_GPENCIL = (1 << 4),
+} eActKeyBlock_Flag;
+
+/* *********************** Keyframe Drawing ****************************** */
+
+/* options for keyframe shape drawing */
+typedef enum eKeyframeShapeDrawOpts {
+ /* only the border */
+ KEYFRAME_SHAPE_FRAME = 0,
+ /* only the inside filling */
+ KEYFRAME_SHAPE_INSIDE,
+ /* the whole thing */
+ KEYFRAME_SHAPE_BOTH,
+} eKeyframeShapeDrawOpts;
+
+/* Handle type. */
+typedef enum eKeyframeHandleDrawOpts {
+ /* Don't draw */
+ KEYFRAME_HANDLE_NONE = 0,
+ /* Various marks in order of increasing display priority. */
+ KEYFRAME_HANDLE_AUTO_CLAMP,
+ KEYFRAME_HANDLE_AUTO,
+ KEYFRAME_HANDLE_VECTOR,
+ KEYFRAME_HANDLE_ALIGNED,
+ KEYFRAME_HANDLE_FREE,
+} eKeyframeHandleDrawOpts;
+
+/* Extreme type. */
+typedef enum eKeyframeExtremeDrawOpts {
+ KEYFRAME_EXTREME_NONE = 0,
+ /* Minimum/maximum present. */
+ KEYFRAME_EXTREME_MIN = (1 << 0),
+ KEYFRAME_EXTREME_MAX = (1 << 1),
+ /* Grouped keys have different states. */
+ KEYFRAME_EXTREME_MIXED = (1 << 2),
+ /* Both neighbors are equal to this key. */
+ KEYFRAME_EXTREME_FLAT = (1 << 3),
+} eKeyframeExtremeDrawOpts;
+
+/* ******************************* Methods ****************************** */
+
+/* Key-data Generation --------------- */
+
+/* F-Curve */
+void fcurve_to_keylist(struct AnimData *adt,
+ struct FCurve *fcu,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* Action Group */
+void agroup_to_keylist(struct AnimData *adt,
+ struct bActionGroup *agrp,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* Action */
+void action_to_keylist(struct AnimData *adt,
+ struct bAction *act,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* Object */
+void ob_to_keylist(struct bDopeSheet *ads,
+ struct Object *ob,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* Cache File */
+void cachefile_to_keylist(struct bDopeSheet *ads,
+ struct CacheFile *cache_file,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* Scene */
+void scene_to_keylist(struct bDopeSheet *ads,
+ struct Scene *sce,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* DopeSheet Summary */
+void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, int saction_flag);
+/* Grease Pencil datablock summary */
+void gpencil_to_keylist(struct bDopeSheet *ads,
+ struct bGPdata *gpd,
+ struct DLRBT_Tree *keys,
+ const bool active);
+/* Grease Pencil Layer */
+void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys);
+/* Mask */
+void mask_to_keylist(struct bDopeSheet *ads, struct MaskLayer *masklay, struct DLRBT_Tree *keys);
+
+/* ActKeyColumn API ---------------- */
+/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
+short compare_ak_cfraPtr(void *node, void *data);
+
+/* Checks if ActKeyColumn has any block data */
+bool actkeyblock_is_valid(ActKeyColumn *ac);
+
+/* Checks if ActKeyColumn can be used as a block (i.e. drawn/used to detect "holds") */
+int actkeyblock_get_valid_hold(ActKeyColumn *ac);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 0fb06639dbf..5cdcbbab42a 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -72,13 +72,12 @@ struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
* - PR_NODE_RENDER: preview is rendered for node editor
* - PR_ICON_DEFERRED: No render, we just ensure deferred icon data gets generated.
*/
-
-enum {
+typedef enum ePreviewRenderMethod {
PR_BUTS_RENDER = 0,
PR_ICON_RENDER = 1,
PR_NODE_RENDER = 2,
PR_ICON_DEFERRED = 3,
-};
+} ePreviewRenderMethod;
void ED_preview_ensure_dbase(void);
void ED_preview_free_dbase(void);
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 953f26aa45f..0105af843bb 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -24,6 +24,7 @@
#pragma once
#include "BLI_compiler_attrs.h"
+#include "WM_types.h"
#ifdef __cplusplus
extern "C" {
@@ -61,6 +62,24 @@ void ED_region_draw_mouse_line_cb(const struct bContext *C,
void ED_region_image_metadata_draw(
int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy);
+/* Slider */
+struct tSlider;
+
+struct tSlider *ED_slider_create(struct bContext *C);
+void ED_slider_init(struct tSlider *slider, const struct wmEvent *event);
+bool ED_slider_modal(struct tSlider *slider, const struct wmEvent *event);
+void ED_slider_destroy(struct bContext *C, struct tSlider *slider);
+
+void ED_slider_status_string_get(const struct tSlider *slider,
+ char *status_string,
+ const size_t size_of_status_string);
+
+float ED_slider_factor_get(struct tSlider *slider);
+void ED_slider_factor_set(struct tSlider *slider, float factor);
+
+bool ED_slider_allow_overshoot_get(struct tSlider *slider);
+void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value);
+
/* ************** XXX OLD CRUFT WARNING ************* */
void apply_keyb_grid(
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index a25aac5803c..a6e465d04e8 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -35,9 +35,11 @@ extern "C" {
/* Struct Declarations */
struct ARegion;
+struct AssetHandle;
struct AssetFilterSettings;
struct AutoComplete;
struct EnumPropertyItem;
+struct FileDirEntry;
struct FileSelectParams;
struct ID;
struct IDProperty;
@@ -769,9 +771,8 @@ int UI_but_return_value_get(uiBut *but);
void UI_but_drag_set_id(uiBut *but, struct ID *id);
void UI_but_drag_set_asset(uiBut *but,
- const char *name,
+ const struct AssetHandle *asset,
const char *path,
- int id_type,
int import_type, /* eFileAssetImportType */
int icon,
struct ImBuf *imb,
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index ddde4f5a9dc..72e379e9b0a 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -6176,10 +6176,12 @@ void UI_but_drag_set_id(uiBut *but, ID *id)
but->dragpoin = (void *)id;
}
+/**
+ * \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 char *name,
+ const AssetHandle *asset,
const char *path,
- int id_type,
int import_type,
int icon,
struct ImBuf *imb,
@@ -6187,9 +6189,10 @@ void UI_but_drag_set_asset(uiBut *but,
{
wmDragAsset *asset_drag = MEM_mallocN(sizeof(*asset_drag), "wmDragAsset");
- BLI_strncpy(asset_drag->name, name, sizeof(asset_drag->name));
+ asset_drag->asset_handle = MEM_mallocN(sizeof(asset_drag->asset_handle),
+ "wmDragAsset asset handle");
+ *asset_drag->asset_handle = *asset;
asset_drag->path = path;
- asset_drag->id_type = id_type;
asset_drag->import_type = import_type;
but->dragtype = WM_DRAG_ASSET;
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 3049e2bd7b8..d917534895d 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -952,7 +952,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
}
/* If the button represents an id, it can set the "id" context pointer. */
- if (U.experimental.use_asset_browser && ED_asset_can_make_single_from_context(C)) {
+ if (U.experimental.use_asset_browser && ED_asset_can_mark_single_from_context(C)) {
ID *id = CTX_data_pointer_get_type(C, "id", &RNA_ID).data;
/* Gray out items depending on if data-block is an asset. Preferably this could be done via
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 4f8bb6342f7..bfc03a95949 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -3066,7 +3066,7 @@ static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str),
/**
* \param x: Screen space cursor location - #wmEvent.x
*
- * \note ``but->block->aspect`` is used here, so drawing button style is getting scaled too.
+ * \note `but->block->aspect` is used here, so drawing button style is getting scaled too.
*/
static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, const float x)
{
@@ -3929,7 +3929,7 @@ static void ui_do_but_textedit(
/* exception that's useful for number buttons, some keyboard
* numpads have a comma instead of a period */
- if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* could use data->min*/
+ if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* Could use `data->min`. */
if (event->type == EVT_PADPERIOD && ascii == ',') {
ascii = '.';
utf8_buf = NULL; /* force ascii fallback */
@@ -9486,7 +9486,7 @@ static void ui_list_activate_row_from_index(
/* A bit ugly, set the active index in RNA directly. That's because a button that's
* scrolled away in the list box isn't created at all.
* The custom activate operator (#uiList.custom_activate_opname) is not called in this case
- * (which may need the row button context).*/
+ * (which may need the row button context). */
RNA_property_int_set(&listbox->rnapoin, listbox->rnaprop, index);
RNA_property_update(C, &listbox->rnapoin, listbox->rnaprop);
ui_apply_but_undo(listbox);
@@ -9505,7 +9505,7 @@ static int ui_list_get_increment(const uiList *ui_list, const int type, const in
increment = (type == EVT_UPARROWKEY) ? -columns : columns;
}
else {
- /* Left or right in grid layouts or any direction in single column layouts increments by 1. */
+ /* Left or right in grid layouts or any direction in single column layouts increments by 1. */
increment = ELEM(type, EVT_UPARROWKEY, EVT_LEFTARROWKEY, WHEELUPMOUSE) ? -1 : 1;
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 43ac646f053..975c86f3e71 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -66,6 +66,7 @@
#include "ED_datafiles.h"
#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "ED_render.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 376a41ff9bb..3ab49b8773b 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -675,7 +675,7 @@ static int override_remove_button_exec(bContext *C, wmOperator *op)
PropertyRNA *src_prop;
RNA_id_pointer_create(id->override_library->reference, &id_refptr);
if (!RNA_path_resolve_property(&id_refptr, oprop->rna_path, &src, &src_prop)) {
- BLI_assert(0 && "Failed to create matching source (linked data) RNA pointer");
+ BLI_assert_msg(0, "Failed to create matching source (linked data) RNA pointer");
}
}
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index 5a05813f947..de3b49eec07 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -52,25 +52,24 @@ static void asset_view_item_but_drag_set(uiBut *but,
AssetViewListData *list_data,
AssetHandle *asset_handle)
{
- ID *id = asset_handle->file_data->id;
+ ID *id = ED_asset_handle_get_local_id(asset_handle);
if (id != nullptr) {
UI_but_drag_set_id(but, id);
return;
}
- const blender::StringRef asset_list_path = ED_assetlist_library_path(&list_data->asset_library);
char blend_path[FILE_MAX_LIBEXTRA];
+ /* Context can be NULL here, it's only needed for a File Browser specific hack that should go
+ * away before too long. */
+ ED_asset_handle_get_full_library_path(NULL, &list_data->asset_library, asset_handle, blend_path);
- char path[FILE_MAX_LIBEXTRA];
- BLI_join_dirfile(path, sizeof(path), asset_list_path.data(), asset_handle->file_data->relpath);
- if (BLO_library_path_explode(path, blend_path, nullptr, nullptr)) {
+ if (blend_path[0]) {
ImBuf *imbuf = ED_assetlist_asset_image_get(asset_handle);
UI_but_drag_set_asset(but,
- asset_handle->file_data->name,
+ asset_handle,
BLI_strdup(blend_path),
- asset_handle->file_data->blentype,
FILE_ASSET_IMPORT_APPEND,
- asset_handle->file_data->preview_icon_id,
+ ED_asset_handle_get_preview_icon_id(asset_handle),
imbuf,
1.0f);
}
@@ -101,8 +100,8 @@ static void asset_view_draw_item(uiList *ui_list,
uiBut *but = uiDefIconTextBut(block,
UI_BTYPE_PREVIEW_TILE,
0,
- asset_handle->file_data->preview_icon_id,
- asset_handle->file_data->name,
+ ED_asset_handle_get_preview_icon_id(asset_handle),
+ ED_asset_handle_get_name(asset_handle),
0,
0,
size_x,
@@ -114,7 +113,7 @@ static void asset_view_draw_item(uiList *ui_list,
0,
"");
ui_def_but_icon(but,
- asset_handle->file_data->preview_icon_id,
+ ED_asset_handle_get_preview_icon_id(asset_handle),
/* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
if (!ui_list->dyn_data->custom_drag_optype) {
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index eaab33e32c9..0ab45ea0f81 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -1170,7 +1170,7 @@ uiList *uiTemplateList_ex(uiLayout *layout,
enum uiTemplateListFlags flags,
void *customdata)
{
- TemplateListInputData input_data = {nullptr};
+ TemplateListInputData input_data = {{nullptr}};
uiListType *ui_list_type;
if (!ui_template_list_data_retrieve(listtype_name,
list_id,
@@ -1271,7 +1271,9 @@ PointerRNA *UI_list_custom_activate_operator_set(uiList *ui_list,
}
if (create_properties) {
- WM_operator_properties_alloc(&dyn_data->custom_activate_opptr, nullptr, opname);
+ PointerRNA *opptr = dyn_data->custom_activate_opptr;
+ WM_operator_properties_alloc(
+ &dyn_data->custom_activate_opptr, opptr ? (IDProperty **)&opptr->data : nullptr, opname);
}
return dyn_data->custom_activate_opptr;
@@ -1291,7 +1293,9 @@ PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list,
}
if (create_properties) {
- WM_operator_properties_alloc(&dyn_data->custom_drag_opptr, nullptr, opname);
+ PointerRNA *opptr = dyn_data->custom_drag_opptr;
+ WM_operator_properties_alloc(
+ &dyn_data->custom_drag_opptr, opptr ? (IDProperty **)&opptr->data : nullptr, opname);
}
return dyn_data->custom_drag_opptr;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index e9804840801..db2766f1b19 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -1914,7 +1914,7 @@ float UI_view2d_scale_get_y(const View2D *v2d)
return BLI_rcti_size_y(&v2d->mask) / BLI_rctf_size_y(&v2d->cur);
}
/**
- * Same as ``UI_view2d_scale_get() - 1.0f / x, y``
+ * Same as `UI_view2d_scale_get() - 1.0f / x, y`.
*/
void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y)
{
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 880d27e1615..ad71f4d9da7 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -361,8 +361,10 @@ static bool add_vertex_extrude(const bContext *C,
}
}
- // print_v2("", tangent_point);
- // printf("%d\n", point_index);
+#if 0
+ print_v2("", tangent_point);
+ printf("%d\n", point_index);
+#endif
mask_spline_add_point_at_index(spline, point_index);
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 73b3fb9724e..b2379610f65 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -482,8 +482,34 @@ bool ED_mesh_color_remove_named(Mesh *me, const char *name)
return false;
}
+/*********************** General poll ************************/
+
+static bool layers_poll(bContext *C)
+{
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? ob->data : NULL;
+ return (ob && !ID_IS_LINKED(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED(data));
+}
+
/*********************** Sculpt Vertex colors operators ************************/
+static bool sculpt_vertex_color_remove_poll(bContext *C)
+{
+ if (!layers_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ Mesh *me = ob->data;
+ CustomData *vdata = GET_CD_DATA(me, vdata);
+ const int active = CustomData_get_active_layer(vdata, CD_PROP_COLOR);
+ if (active != -1) {
+ return true;
+ }
+
+ return false;
+}
+
/* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool active_set, const bool do_init)
{
@@ -591,11 +617,21 @@ bool ED_mesh_sculpt_color_remove_named(Mesh *me, const char *name)
/*********************** UV texture operators ************************/
-static bool layers_poll(bContext *C)
+static bool uv_texture_remove_poll(bContext *C)
{
+ if (!layers_poll(C)) {
+ return false;
+ }
+
Object *ob = ED_object_context(C);
- ID *data = (ob) ? ob->data : NULL;
- return (ob && !ID_IS_LINKED(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED(data));
+ Mesh *me = ob->data;
+ CustomData *ldata = GET_CD_DATA(me, ldata);
+ const int active = CustomData_get_active_layer(ldata, CD_MLOOPUV);
+ if (active != -1) {
+ return true;
+ }
+
+ return false;
}
static int mesh_uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -657,7 +693,7 @@ void MESH_OT_uv_texture_remove(wmOperatorType *ot)
ot->idname = "MESH_OT_uv_texture_remove";
/* api callbacks */
- ot->poll = layers_poll;
+ ot->poll = uv_texture_remove_poll;
ot->exec = mesh_uv_texture_remove_exec;
/* flags */
@@ -666,6 +702,23 @@ void MESH_OT_uv_texture_remove(wmOperatorType *ot)
/*********************** vertex color operators ************************/
+static bool vertex_color_remove_poll(bContext *C)
+{
+ if (!layers_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ Mesh *me = ob->data;
+ CustomData *ldata = GET_CD_DATA(me, ldata);
+ const int active = CustomData_get_active_layer(ldata, CD_MLOOPCOL);
+ if (active != -1) {
+ return true;
+ }
+
+ return false;
+}
+
static int mesh_vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
@@ -714,7 +767,7 @@ void MESH_OT_vertex_color_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = mesh_vertex_color_remove_exec;
- ot->poll = layers_poll;
+ ot->poll = vertex_color_remove_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -770,7 +823,7 @@ void MESH_OT_sculpt_vertex_color_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = mesh_sculpt_vertex_color_remove_exec;
- ot->poll = layers_poll;
+ ot->poll = sculpt_vertex_color_remove_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 34e9a3f45a5..94823b92c44 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -336,7 +336,7 @@ void ED_operatormacros_mesh(void)
ot = WM_operatortype_append_macro("MESH_OT_polybuild_face_at_cursor_move",
"Face at Cursor Move",
- "",
+ NULL,
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "MESH_OT_polybuild_face_at_cursor");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
@@ -345,7 +345,7 @@ void ED_operatormacros_mesh(void)
ot = WM_operatortype_append_macro("MESH_OT_polybuild_split_at_cursor_move",
"Split at Cursor Move",
- "",
+ NULL,
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "MESH_OT_polybuild_split_at_cursor");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
@@ -354,7 +354,7 @@ void ED_operatormacros_mesh(void)
ot = WM_operatortype_append_macro("MESH_OT_polybuild_transform_at_cursor_move",
"Transform at Cursor Move",
- "",
+ NULL,
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
@@ -363,7 +363,7 @@ void ED_operatormacros_mesh(void)
ot = WM_operatortype_append_macro("MESH_OT_polybuild_extrude_at_cursor_move",
"Extrude at Cursor Move",
- "",
+ NULL,
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor");
otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_edges_indiv");
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 2109fe2a822..6251fb799c5 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -123,9 +123,14 @@ static const EnumPropertyItem *dt_layers_select_src_itemf(bContext *C,
RNA_enum_items_add_value(
&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC);
- if (data_type == DT_TYPE_MDEFORMVERT) {
- Object *ob_src = CTX_data_active_object(C);
+ Object *ob_src = CTX_data_active_object(C);
+ if (ob_src == NULL) {
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+ return item;
+ }
+ if (data_type == DT_TYPE_MDEFORMVERT && BKE_object_supports_vertex_groups(ob_src)) {
if (BKE_object_pose_armature_get(ob_src)) {
RNA_enum_items_add_value(
&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT);
@@ -133,67 +138,57 @@ static const EnumPropertyItem *dt_layers_select_src_itemf(bContext *C,
&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM);
}
- if (ob_src) {
- const bDeformGroup *dg;
- int i;
+ const bDeformGroup *dg;
+ int i;
- RNA_enum_item_add_separator(&item, &totitem);
+ RNA_enum_item_add_separator(&item, &totitem);
- const ListBase *defbase = BKE_object_defgroup_list(ob_src);
- for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) {
- tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = dg->name;
- RNA_enum_item_add(&item, &totitem, &tmp_item);
- }
+ const ListBase *defbase = BKE_object_defgroup_list(ob_src);
+ for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) {
+ tmp_item.value = i;
+ tmp_item.identifier = tmp_item.name = dg->name;
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
}
}
else if (data_type == DT_TYPE_SHAPEKEY) {
/* TODO */
}
else if (data_type == DT_TYPE_UV) {
- Object *ob_src = CTX_data_active_object(C);
-
- if (ob_src) {
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src);
- CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH;
- cddata_masks.lmask |= CD_MASK_MLOOPUV;
- Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks);
- int num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPUV);
+ CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH;
+ cddata_masks.lmask |= CD_MASK_MLOOPUV;
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks);
+ int num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPUV);
- RNA_enum_item_add_separator(&item, &totitem);
+ RNA_enum_item_add_separator(&item, &totitem);
- for (int i = 0; i < num_data; i++) {
- tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(
- &me_eval->ldata, CD_MLOOPUV, i);
- RNA_enum_item_add(&item, &totitem, &tmp_item);
- }
+ for (int i = 0; i < num_data; i++) {
+ tmp_item.value = i;
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(
+ &me_eval->ldata, CD_MLOOPUV, i);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
}
}
else if (data_type == DT_TYPE_VCOL) {
- Object *ob_src = CTX_data_active_object(C);
-
- if (ob_src) {
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src);
- CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH;
- cddata_masks.lmask |= CD_MASK_MLOOPCOL;
- Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks);
- int num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPCOL);
+ CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH;
+ cddata_masks.lmask |= CD_MASK_MLOOPCOL;
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks);
+ int num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPCOL);
- RNA_enum_item_add_separator(&item, &totitem);
+ RNA_enum_item_add_separator(&item, &totitem);
- for (int i = 0; i < num_data; i++) {
- tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(
- &me_eval->ldata, CD_MLOOPCOL, i);
- RNA_enum_item_add(&item, &totitem, &tmp_item);
- }
+ for (int i = 0; i < num_data; i++) {
+ tmp_item.value = i;
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(
+ &me_eval->ldata, CD_MLOOPCOL, i);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
}
}
diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c
index 3d4d3c8f622..92f3d28878c 100644
--- a/source/blender/editors/object/object_facemap_ops.c
+++ b/source/blender/editors/object/object_facemap_ops.c
@@ -176,6 +176,21 @@ static bool face_map_supported_edit_mode_poll(bContext *C)
return false;
}
+static bool face_map_supported_remove_poll(bContext *C)
+{
+ if (!face_map_supported_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
+ if (fmap) {
+ return true;
+ }
+
+ return false;
+}
+
static int face_map_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
@@ -225,7 +240,7 @@ void OBJECT_OT_face_map_remove(struct wmOperatorType *ot)
ot->description = "Remove a face map from the active object";
/* api callbacks */
- ot->poll = face_map_supported_poll;
+ ot->poll = face_map_supported_remove_poll;
ot->exec = face_map_remove_exec;
/* flags */
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 4ea599fd30e..f64f95c5322 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -3892,7 +3892,7 @@ static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
int fail = 0;
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
- if (obact != ob) {
+ if (obact != ob && BKE_object_supports_vertex_groups(ob)) {
if (ED_vgroup_array_copy(ob, obact)) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
DEG_relations_tag_update(CTX_data_main(C));
@@ -3909,8 +3909,8 @@ static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
if ((changed_tot == 0 && fail == 0) || fail) {
BKE_reportf(op->reports,
RPT_ERROR,
- "Copy vertex groups to selected: %d done, %d failed (object data must have "
- "matching indices)",
+ "Copy vertex groups to selected: %d done, %d failed (object data must support "
+ "vertex groups and have matching indices)",
changed_tot,
fail);
}
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index f2bbd6d5084..5a629058c81 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -368,7 +368,7 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o
else if (pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) {
if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
pset->flag |= PE_FADE_TIME;
- // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
+ /* Nice to have but doesn't work: `pset->brushtype = PE_BRUSH_COMB;`. */
PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL);
}
edit = pid->cache->edit;
@@ -377,7 +377,7 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o
else if (pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) {
if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
pset->flag |= PE_FADE_TIME;
- // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
+ /* Nice to have but doesn't work: `pset->brushtype = PE_BRUSH_COMB;`. */
PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL);
}
edit = pid->cache->edit;
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 9abf15d2198..702c8d052c5 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -234,7 +234,7 @@ static Scene *preview_get_scene(Main *pr_main)
return pr_main->scenes.first;
}
-static const char *preview_collection_name(const char pr_type)
+static const char *preview_collection_name(const ePreviewType pr_type)
{
switch (pr_type) {
case MA_FLAT:
@@ -265,10 +265,7 @@ static const char *preview_collection_name(const char pr_type)
}
}
-static void set_preview_visibility(Scene *scene,
- ViewLayer *view_layer,
- char pr_type,
- int pr_method)
+static void switch_preview_collection_visibilty(ViewLayer *view_layer, const ePreviewType pr_type)
{
/* Set appropriate layer as visible. */
LayerCollection *lc = view_layer->layer_collections.first;
@@ -282,7 +279,11 @@ static void set_preview_visibility(Scene *scene,
lc->collection->flag |= COLLECTION_RESTRICT_RENDER;
}
}
+}
+static void switch_preview_floor_visibility(ViewLayer *view_layer,
+ const ePreviewRenderMethod pr_method)
+{
/* Hide floor for icon renders. */
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (STREQ(base->object->id.name + 2, "Floor")) {
@@ -294,7 +295,15 @@ static void set_preview_visibility(Scene *scene,
}
}
}
+}
+static void set_preview_visibility(Scene *scene,
+ ViewLayer *view_layer,
+ const ePreviewType pr_type,
+ const ePreviewRenderMethod pr_method)
+{
+ switch_preview_collection_visibilty(view_layer, pr_type);
+ switch_preview_floor_visibility(view_layer, pr_method);
BKE_layer_collection_sync(scene, view_layer);
}
@@ -348,6 +357,38 @@ static ID *duplicate_ids(ID *id, const bool allow_failure)
}
}
+static World *preview_get_world(Main *pr_main)
+{
+ World *result = NULL;
+ const char *world_name = "World";
+ result = BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2);
+
+ /* No world found return first world. */
+ if (result == NULL) {
+ result = pr_main->worlds.first;
+ }
+
+ BLI_assert_msg(result, "Preview file has no world.");
+ return result;
+}
+
+static void preview_sync_exposure(World *dst, const World *src)
+{
+ BLI_assert(dst);
+ BLI_assert(src);
+ dst->exp = src->exp;
+ dst->range = src->range;
+}
+
+static World *preview_prepare_world(Main *pr_main, const World *world)
+{
+ World *result = preview_get_world(pr_main);
+ if (world) {
+ preview_sync_exposure(result, world);
+ }
+ return result;
+}
+
/* call this with a pointer to initialize preview scene */
/* call this with NULL to restore assigned ID pointers in preview scene */
static Scene *preview_prepare_scene(
@@ -368,13 +409,7 @@ static Scene *preview_prepare_scene(
/* this flag tells render to not execute depsgraph or ipos etc */
sce->r.scemode |= R_BUTS_PREVIEW;
- /* set world always back, is used now */
- sce->world = pr_main->worlds.first;
- /* now: exposure copy */
- if (scene->world) {
- sce->world->exp = scene->world->exp;
- sce->world->range = scene->world->range;
- }
+ BLI_strncpy(sce->r.engine, scene->r.engine, sizeof(sce->r.engine));
sce->r.color_mgt_flag = scene->r.color_mgt_flag;
BKE_color_managed_display_settings_copy(&sce->display_settings, &scene->display_settings);
@@ -400,13 +435,13 @@ static Scene *preview_prepare_scene(
sce->r.cfra = scene->r.cfra;
+ /* Setup the world. */
+ sce->world = preview_prepare_world(pr_main, scene->world);
+
if (id_type == ID_TE) {
/* Texture is not actually rendered with engine, just set dummy value. */
BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine));
}
- else {
- BLI_strncpy(sce->r.engine, scene->r.engine, sizeof(sce->r.engine));
- }
if (id_type == ID_MA) {
Material *mat = NULL, *origmat = (Material *)id;
@@ -432,14 +467,12 @@ static Scene *preview_prepare_scene(
sce->world->horb = 0.05f;
}
- if (sp->pr_method == PR_ICON_RENDER && sp->pr_main == G_pr_main_grease_pencil) {
- /* For grease pencil, always use sphere for icon renders. */
- set_preview_visibility(sce, view_layer, MA_SPHERE_A, sp->pr_method);
- }
- else {
- /* Use specified preview shape for both preview panel and icon previews. */
- set_preview_visibility(sce, view_layer, mat->pr_type, sp->pr_method);
- }
+ /* For grease pencil, always use sphere for icon renders. */
+ const ePreviewType preview_type = (sp->pr_method == PR_ICON_RENDER &&
+ sp->pr_main == G_pr_main_grease_pencil) ?
+ MA_SPHERE_A :
+ mat->pr_type;
+ set_preview_visibility(sce, view_layer, preview_type, sp->pr_method);
if (sp->pr_method != PR_ICON_RENDER) {
if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) {
@@ -691,8 +724,8 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
struct ObjectPreviewData {
/* The main for the preview, not of the current file. */
Main *pr_main;
- /* Copy of the object to create the preview for. The copy is for thread safety (and to insert it
- * into an own main). */
+ /* Copy of the object to create the preview for. The copy is for thread safety (and to insert
+ * it into an own main). */
Object *object;
int sizex;
int sizey;
@@ -861,9 +894,9 @@ static void action_preview_render_cleanup(IconPreview *preview, struct PoseBacku
DEG_id_tag_update(&preview->active_object->id, ID_RECALC_GEOMETRY);
}
-/* Render a pose. It is assumed that the pose has already been applied and that the scene camera is
- * capturing the pose. In other words, this function just renders from the scene camera without
- * evaluating the Action stored in preview->id. */
+/* Render a pose from the scene camera. It is assumed that the scene camera is
+ * capturing the pose. The pose is applied temporarily to the current object
+ * before rendering. */
static void action_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
{
char err_out[256] = "";
@@ -1308,8 +1341,9 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
scaledy = (float)h;
}
- ex = (short)scaledx;
- ey = (short)scaledy;
+ /* Scaling down must never assign zero width/height, see: T89868. */
+ ex = MAX2(1, (short)scaledx);
+ ey = MAX2(1, (short)scaledy);
dx = (w - ex) / 2;
dy = (h - ey) / 2;
@@ -1550,8 +1584,8 @@ static void icon_preview_startjob_all_sizes(void *customdata,
/* check_engine_supports_preview() checks whether the engine supports "preview mode" (think:
* Material Preview). This check is only relevant when the render function called below is
- * going to use such a mode. Object and Action render functions use Solid mode, though, so they
- * can skip this test. */
+ * going to use such a mode. Object and Action render functions use Solid mode, though, so
+ * they can skip this test. */
/* TODO: Decouple the ID-type-specific render functions from this function, so that it's not
* necessary to know here what happens inside lower-level functions. */
const bool use_solid_render_mode = (ip->id != NULL) && ELEM(GS(ip->id->name), ID_OB, ID_AC);
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index d2b1ebdad78..8a3d8f9636b 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -56,6 +56,7 @@
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -1043,6 +1044,10 @@ static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op))
engine = NULL;
}
+ if (scene->nodetree) {
+ ntreeCompositUpdateRLayers(scene->nodetree);
+ }
+
DEG_id_tag_update(&scene->id, 0);
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
@@ -1091,6 +1096,10 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
engine = NULL;
}
+ if (scene->nodetree) {
+ ntreeCompositUpdateRLayers(scene->nodetree);
+ }
+
DEG_id_tag_update(&scene->id, 0);
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 80b5623b9c3..fb9d11feb63 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -65,7 +65,7 @@
/***************************** Render Engines ********************************/
-/* Update 3D viewport render or draw engine on changes to the scene or view settings . */
+/* Update 3D viewport render or draw engine on changes to the scene or view settings. */
void ED_render_view3d_update(Depsgraph *depsgraph,
wmWindow *window,
ScrArea *area,
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 3ce2f326dca..8123d8bb104 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -1031,7 +1031,7 @@ static eContextResult screen_ctx_asset_library(const bContext *C, bContextDataRe
{
WorkSpace *workspace = CTX_wm_workspace(C);
CTX_data_pointer_set(
- result, &workspace->id, &RNA_AssetLibraryReference, &workspace->active_asset_library);
+ result, &workspace->id, &RNA_AssetLibraryReference, &workspace->asset_library);
return CTX_RESULT_OK;
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index ffeaf514642..3d0d856b1c5 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -71,7 +71,7 @@
#include "ED_armature.h"
#include "ED_clip.h"
#include "ED_image.h"
-#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index bd05d309421..19f72a66b9b 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -375,7 +375,7 @@ typedef struct ProjPaintState {
/* -------------------------------------------------------------------- */
/* Vars shared between multiple views (keep last) */
/**
- * This data is owned by ``ProjStrokeHandle.ps_views[0]``,
+ * This data is owned by `ProjStrokeHandle.ps_views[0]`,
* all other views re-use the data.
*/
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index de9511bab6f..4b49bf2cefb 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index c3977b28178..936ebb7e8f7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 0d5b197ae93..59d2063ea84 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -51,8 +51,8 @@
#include "ED_anim_api.h"
#include "ED_gpencil.h"
-#include "ED_keyframes_draw.h"
#include "ED_keyframes_edit.h"
+#include "ED_keyframes_keylist.h"
#include "ED_markers.h"
#include "ED_mask.h"
#include "ED_screen.h"
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index a314a85491d..37a56816677 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -185,9 +185,8 @@ static void file_draw_icon(const SpaceFile *sfile,
BLI_assert(asset_params != NULL);
UI_but_drag_set_asset(but,
- file->name,
+ &(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
- file->blentype,
asset_params->import_type,
icon,
preview_image,
@@ -500,9 +499,8 @@ static void file_draw_preview(const SpaceFile *sfile,
BLI_assert(asset_params != NULL);
UI_but_drag_set_asset(but,
- file->name,
+ &(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
- file->blentype,
asset_params->import_type,
icon,
imb,
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 995383d9d0e..4d25524cd19 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -2340,7 +2340,9 @@ static int file_directory_new_exec(bContext *C, wmOperator *op)
/* If we don't enter the directory directly, remember file to jump into editing. */
if (do_diropen == false) {
- BLI_assert(params->rename_id == NULL || !"File rename handling should immediately clear rename_id when done, because otherwise it will keep taking precedence over renamefile.");
+ BLI_assert_msg(params->rename_id == NULL,
+ "File rename handling should immediately clear rename_id when done, "
+ "because otherwise it will keep taking precedence over renamefile.");
BLI_strncpy(params->renamefile, name, FILE_MAXFILE);
rename_flag = FILE_PARAMS_RENAME_PENDING;
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 492a189fc81..6ac67a126cd 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -382,7 +382,7 @@ typedef struct FileList {
eFileSelectType type;
/* The library this list was created for. Stored here so we know when to re-read. */
- FileSelectAssetLibraryUID *asset_library;
+ AssetLibraryReference *asset_library;
short flags;
@@ -1045,8 +1045,8 @@ void filelist_setfilter_options(FileList *filelist,
* Checks two libraries for equality.
* \return True if the libraries match.
*/
-static bool filelist_compare_asset_libraries(const FileSelectAssetLibraryUID *library_a,
- const FileSelectAssetLibraryUID *library_b)
+static bool filelist_compare_asset_libraries(const AssetLibraryReference *library_a,
+ const AssetLibraryReference *library_b)
{
if (library_a->type != library_b->type) {
return false;
@@ -1065,7 +1065,7 @@ static bool filelist_compare_asset_libraries(const FileSelectAssetLibraryUID *li
/**
* \param asset_library: May be NULL to unset the library.
*/
-void filelist_setlibrary(FileList *filelist, const FileSelectAssetLibraryUID *asset_library)
+void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library)
{
/* Unset if needed. */
if (!asset_library) {
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index cb98cf6e74a..6915e853681 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -29,7 +29,7 @@ extern "C" {
struct BlendHandle;
struct FileList;
-struct FileSelectAssetLibraryUID;
+struct AssetLibraryReference;
struct FileSelection;
struct wmWindowManager;
@@ -73,7 +73,7 @@ void filelist_setfilter_options(struct FileList *filelist,
const char *filter_search);
void filelist_filter(struct FileList *filelist);
void filelist_setlibrary(struct FileList *filelist,
- const struct FileSelectAssetLibraryUID *asset_library);
+ const struct AssetLibraryReference *asset_library);
void filelist_init_icons(void);
void filelist_free_icons(void);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 7bc83e8fc79..68dd1e28f99 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -415,7 +415,7 @@ FileAssetSelectParams *ED_fileselect_get_asset_params(const SpaceFile *sfile)
static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params)
{
- FileSelectAssetLibraryUID *library = &asset_params->asset_library;
+ AssetLibraryReference *library = &asset_params->asset_library;
FileSelectParams *base_params = &asset_params->base_params;
bUserAssetLibrary *user_library = NULL;
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 31c7dee294b..274b21f7043 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -910,13 +910,6 @@ static int /*eContextResult*/ file_context(const bContext *C,
return CTX_RESULT_NO_DATA;
}
- BLI_STATIC_ASSERT(offsetof(FileSelectAssetLibraryUID, type) ==
- offsetof(AssetLibraryReference, type),
- "Expected FileSelectAssetLibraryUID to match AssetLibraryReference");
- BLI_STATIC_ASSERT(offsetof(FileSelectAssetLibraryUID, custom_library_index) ==
- offsetof(AssetLibraryReference, custom_library_index),
- "Expected FileSelectAssetLibraryUID to match AssetLibraryReference");
-
CTX_data_pointer_set(
result, &screen->id, &RNA_AssetLibraryReference, &asset_params->asset_library);
return CTX_RESULT_OK;
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 6f1b0bb0d7d..9f9869a854c 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -261,7 +261,7 @@ static int graphkeys_insertkey_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* Which channels to affect?. */
+ /* Which channels to affect? */
mode = RNA_enum_get(op->ptr, "type");
/* Insert keyframes. */
@@ -2814,7 +2814,7 @@ static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
}
ANIM_animdata_freelist(&anim_data);
- /* Successful or not?. */
+ /* Successful or not? */
if (ok) {
/* Set notifier that keyframes have changed. */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -2873,7 +2873,7 @@ static int graph_driver_vars_copy_exec(bContext *C, wmOperator *op)
ok = ANIM_driver_vars_copy(op->reports, fcu);
}
- /* Successful or not?. */
+ /* Successful or not? */
if (ok) {
return OPERATOR_FINISHED;
}
@@ -2915,7 +2915,7 @@ static int graph_driver_vars_paste_exec(bContext *C, wmOperator *op)
ok = ANIM_driver_vars_paste(op->reports, fcu, replace);
}
- /* Successful or not?. */
+ /* Successful or not? */
if (ok) {
/* Rebuild depsgraph, now that there are extra deps here. */
DEG_relations_tag_update(CTX_data_main(C));
diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c
index 31c53cde62c..036fd354c18 100644
--- a/source/blender/editors/space_graph/graph_view.c
+++ b/source/blender/editors/space_graph/graph_view.c
@@ -398,7 +398,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- /* Loop through filtered data and add keys between selected keyframes on every frame . */
+ /* Loop through filtered data and add keys between selected keyframes on every frame. */
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
FCurve *gcu = BKE_fcurve_create();
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 4779a82948d..86349a64681 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -1189,7 +1189,7 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser
const int menus_width = 160 * dpi_fac;
const bool is_render_result = (ima->type == IMA_TYPE_R_RESULT);
- /* use BKE_image_acquire_renderresult so we get the correct slot in the menu */
+ /* Use BKE_image_acquire_renderresult so we get the correct slot in the menu. */
rr = BKE_image_acquire_renderresult(scene, ima);
uiblock_layer_pass_buttons(
layout, ima, rr, iuser, menus_width, is_render_result ? &ima->render_slot : NULL);
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index f9fb386095d..c96047da0c8 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -44,6 +44,7 @@
#include "ED_anim_api.h"
#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index af9c888cbf7..cbf03f553f6 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -613,9 +613,8 @@ void snode_set_context(const bContext *C)
/* check the tree type */
if (!treetype || (treetype->poll && !treetype->poll(C, treetype))) {
/* invalid tree type, skip
- * NB: not resetting the node path here, invalid bNodeTreeType
- * may still be registered at a later point.
- */
+ * NOTE: not resetting the node path here, invalid #bNodeTreeType
+ * may still be registered at a later point. */
return;
}
@@ -1303,9 +1302,8 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
}
}
- /* copy links between selected nodes
- * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy!
- */
+ /* Copy links between selected nodes.
+ * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */
bNodeLink *lastlink = (bNodeLink *)ntree->links.last;
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
/* This creates new links between copied nodes.
@@ -2163,9 +2161,9 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- /* copy links between selected nodes
- * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy!
- */
+ /* Copy links between selected nodes.
+ * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */
+
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
/* This creates new links between copied nodes. */
if (link->tonode && (link->tonode->flag & NODE_SELECT) && link->fromnode &&
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index 725c872e98f..61a874b2b2d 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -299,7 +299,7 @@ static void pick_input_link_by_link_intersect(const bContext *C,
/* If no linked was picked in this call, try using the one picked in the previous call.
* Not essential for the basic behavior, but can make interaction feel a bit better if
- * the mouse moves to the right and loses the "selection." */
+ * the mouse moves to the right and loses the "selection." */
if (!link_to_pick) {
bNodeLink *last_picked_link = nldrag->last_picked_multi_input_socket_link;
if (last_picked_link) {
diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc
index a081cc83481..6c07c41f451 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -1196,7 +1196,7 @@ static void node_find_create_label(const bNode *node, char *str, int maxlen)
}
}
-/* generic search invoke */
+/* Generic search invoke. */
static void node_find_update_fn(const struct bContext *C,
void *UNUSED(arg),
const char *str,
diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc
index cbe33fab64e..648ede7abd5 100644
--- a/source/blender/editors/space_node/node_templates.cc
+++ b/source/blender/editors/space_node/node_templates.cc
@@ -848,7 +848,10 @@ static void ui_node_draw_input(
break;
case SOCK_STRING: {
const bNodeTree *node_tree = (const bNodeTree *)nodeptr.owner_id;
- if (node_tree->type == NTREE_GEOMETRY) {
+ SpaceNode *snode = CTX_wm_space_node(C);
+ if (node_tree->type == NTREE_GEOMETRY && snode != nullptr) {
+ /* Only add the attribute search in the node editor, in other places there is not
+ * enough context. */
node_geometry_add_attribute_search_button(C, node_tree, node, &inputptr, row);
}
else {
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 35015356f0b..aaa52f6b649 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -697,7 +697,9 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED
{
Editing *ed = SEQ_editing_get(scene, false);
- /* XXX select_single_seq(seq, 1); */
+#if 0
+ select_single_seq(seq, 1);
+#endif
Sequence *p = ed->seqbasep->first;
while (p) {
if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) {
@@ -705,8 +707,11 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED
continue;
}
- /* XXX: if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) select_single_seq(p,
- * 0); */
+#if 0
+ if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) {
+ select_single_seq(p, 0);
+ }
+#endif
p = p->next;
}
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
index 1ac2075e281..c38e765caee 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
@@ -489,7 +489,7 @@ bool ED_spreadsheet_context_path_is_active(const bContext *C, SpaceSpreadsheet *
break;
}
SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)node_context_path[i];
- if (!STREQ(node_context->node_name, tree_path[i]->node_name)) {
+ if (!STREQ(node_context->node_name, tree_path[i + 1]->node_name)) {
break;
}
valid_count++;
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 54f10e259f9..5baa12f7367 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -53,6 +53,7 @@
#include "BKE_screen.h"
#include "BKE_workspace.h"
+#include "ED_asset.h"
#include "ED_render.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -495,7 +496,7 @@ static ID_Type view3d_drop_id_in_main_region_poll_get_id_type(bContext *C,
wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0);
if (asset_drag) {
- return asset_drag->id_type;
+ return ED_asset_handle_get_id_type(asset_drag->asset_handle);
}
return 0;
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index 638c8a49ffd..8380c87b999 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -24,7 +24,7 @@
* Typical view-control usage:
*
* - Acquire a view-control (#ED_view3d_cameracontrol_acquire).
- * - Modify ``rv3d->ofs``, ``rv3d->viewquat``.
+ * - Modify `rv3d->ofs`, `rv3d->viewquat`.
* - Update the view data (#ED_view3d_cameracontrol_acquire) -
* within a loop which draws the viewport.
* - Finish and release the view-control (#ED_view3d_cameracontrol_release),
@@ -32,8 +32,8 @@
*
* Notes:
*
- * - when acquiring ``rv3d->dist`` is set to zero
- * (so ``rv3d->ofs`` is always the view-point)
+ * - when acquiring `rv3d->dist` is set to zero
+ * (so `rv3d->ofs` is always the view-point)
* - updating can optionally keyframe the camera object.
*/
@@ -244,7 +244,7 @@ static bool object_apply_mat4_with_protect(Object *ob,
}
/**
- * Updates cameras from the ``rv3d`` values, optionally auto-keyframing.
+ * Updates cameras from the `rv3d` values, optionally auto-keyframing.
*/
void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl,
/* args for keyframing */
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index c7a4030c402..20e00356152 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -439,7 +439,7 @@ void mesh_foreachScreenEdge(ViewContext *vc,
}
BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE);
- BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data);
+ BKE_mesh_foreach_mapped_edge(me, vc->em->bm->totedge, mesh_foreachScreenEdge__mapFunc, &data);
}
/** \} */
@@ -529,10 +529,11 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
if ((clip_flag & V3D_PROJ_TEST_CLIP_BB) && (vc->rv3d->clipbb != NULL)) {
ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups. */
- BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge_clip_bb_segment__mapFunc, &data);
+ BKE_mesh_foreach_mapped_edge(
+ me, vc->em->bm->totedge, mesh_foreachScreenEdge_clip_bb_segment__mapFunc, &data);
}
else {
- BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data);
+ BKE_mesh_foreach_mapped_edge(me, vc->em->bm->totedge, mesh_foreachScreenEdge__mapFunc, &data);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 8bcc05c1e55..e09453b9957 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -506,8 +506,8 @@ void ED_view3d_lock_clear(View3D *v3d)
/**
* For viewport operators that exit camera perspective.
*
- * \note This differs from simply setting ``rv3d->persp = persp`` because it
- * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera,
+ * \note This differs from simply setting `rv3d->persp = persp` because it
+ * sets the `ofs` and `dist` values of the viewport so it matches the camera,
* otherwise switching out of camera view may jump to a different part of the scene.
*/
void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph,
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 383f9870714..7377e47da3d 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1981,7 +1981,7 @@ static void tc_mesh_partial_update(TransInfo *t,
/* Promote the partial update types based on the previous state
* so the values that no longer modified are reset before being left as-is.
- * Needed for translation which can toggle snap-to-normal during transform. */
+ * Needed for translation which can toggle snap-to-normal during transform. */
const enum ePartialType partial_for_looptri = MAX2(partial_state->for_looptri,
partial_state_prev->for_looptri);
const enum ePartialType partial_for_normals = MAX2(partial_state->for_normals,
@@ -2067,27 +2067,6 @@ static void tc_mesh_transdata_mirror_apply(TransDataContainer *tc)
}
}
-static bool tc_mesh_is_deform_only_update(TransInfo *t, TransDataContainer *tc)
-{
- if (tc->custom.type.data &&
- ((struct TransCustomDataMesh *)tc->custom.type.data)->cd_layer_correct) {
- return false;
- }
-
- Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(t->depsgraph, (ID *)tc->obedit->data);
- Mesh *mesh_eval_cage = me_eval->edit_mesh->mesh_eval_cage;
- Mesh *mesh_eval_final = me_eval->edit_mesh->mesh_eval_final;
- if (mesh_eval_cage && !mesh_eval_cage->runtime.is_original) {
- return false;
- }
- if (mesh_eval_final && mesh_eval_final != mesh_eval_cage &&
- !mesh_eval_final->runtime.is_original) {
- return false;
- }
-
- return me_eval->runtime.deformed_only;
-}
-
void recalcData_mesh(TransInfo *t)
{
bool is_canceling = t->state == TRANS_CANCEL;
@@ -2115,10 +2094,7 @@ void recalcData_mesh(TransInfo *t)
tc_mesh_partial_types_calc(t, &partial_state);
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- const bool is_deform_only = tc_mesh_is_deform_only_update(t, tc);
-
- DEG_id_tag_update(tc->obedit->data,
- is_deform_only ? ID_RECALC_GEOMETRY_DEFORM : ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY);
tc_mesh_partial_update(t, tc, &partial_state);
}
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index a6f5aba5a1d..17512c79d03 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -262,8 +262,16 @@ static void free_transform_custom_data(TransCustomData *custom_data)
/* Canceled, need to update the strips display. */
static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips)
{
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene, false));
+
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ /* Handle pre-existing overlapping strips even when operator is canceled.
+ * This is necessary for SEQUENCER_OT_duplicate_move macro for example. */
+ if (SEQ_transform_test_overlap(seqbase, seq)) {
+ SEQ_transform_seqbase_shuffle(seqbase, seq, t->scene);
+ }
+
SEQ_time_update_sequence_bounds(t->scene, seq);
}
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index aaac8e21cb9..e89ab6729d2 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -343,9 +343,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else {
if (region) {
- /* XXX for now, get View2D from the active region */
+ /* XXX: For now, get View2D from the active region. */
t->view = &region->v2d;
- /* XXX for now, the center point is the midpoint of the data */
+ /* XXX: For now, the center point is the midpoint of the data. */
}
else {
t->view = NULL;
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 2cbf52b6100..75744f26c15 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -266,7 +266,8 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
if (t->flag & T_AUTOIK) {
short chainlen = t->settings->autoik_chainlen;
if (chainlen) {
- ofs += BLI_snprintf_rlen(str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("AutoIK-Len: %d"), chainlen);
+ ofs += BLI_snprintf_rlen(
+ str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Auto IK Length: %d"), chainlen);
ofs += BLI_strncpy_rlen(str + ofs, " ", UI_MAX_DRAW_STR - ofs);
}
}
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 155250261de..33f4b06eb0e 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -537,10 +537,10 @@ short ED_transform_calc_orientation_from_type_ex(const bContext *C,
case V3D_ORIENT_LOCAL: {
if (ob) {
if (ob->mode & OB_MODE_POSE) {
- /* each bone moves on its own local axis, but to avoid confusion,
+ /* Each bone moves on its own local axis, but to avoid confusion,
* use the active pones axis for display T33575, this works as expected on a single
* bone and users who select many bones will understand what's going on and what local
- * means when they start transforming */
+ * means when they start transforming. */
ED_getTransformOrientationMatrix(C, ob, obedit, pivot_point, r_mat);
}
else {
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 2d98d756dba..bb04f557074 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -1142,7 +1142,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
* \param r_loc: Hit location.
* \param r_no: Hit normal (optional).
* \param r_index: Hit index or -1 when no valid index is found.
- * (currently only set to the polygon index when using ``snap_to == SCE_SNAP_MODE_FACE``).
+ * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`).
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
* \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
@@ -1213,49 +1213,56 @@ static bool snap_bound_box_check_dist(const float min[3],
return true;
}
-static void cb_mvert_co_get(const int index, const float **co, const BVHTreeFromMesh *data)
+static void cb_mvert_co_get(const int index, const void *user_data, const float **r_co)
{
- *co = data->vert[index].co;
+ const BVHTreeFromMesh *data = user_data;
+ *r_co = data->vert[index].co;
}
-static void cb_bvert_co_get(const int index, const float **co, const BMEditMesh *data)
+static void cb_bvert_co_get(const int index, const void *user_data, const float **r_co)
{
+ const BMEditMesh *data = user_data;
BMVert *eve = BM_vert_at_index(data->bm, index);
- *co = eve->co;
+ *r_co = eve->co;
}
-static void cb_mvert_no_copy(const int index, float r_no[3], const BVHTreeFromMesh *data)
+static void cb_mvert_no_copy(const int index, const void *user_data, float r_no[3])
{
+ const BVHTreeFromMesh *data = user_data;
const MVert *vert = data->vert + index;
normal_short_to_float_v3(r_no, vert->no);
}
-static void cb_bvert_no_copy(const int index, float r_no[3], const BMEditMesh *data)
+static void cb_bvert_no_copy(const int index, const void *user_data, float r_no[3])
{
+ const BMEditMesh *data = user_data;
BMVert *eve = BM_vert_at_index(data->bm, index);
copy_v3_v3(r_no, eve->no);
}
-static void cb_medge_verts_get(const int index, int v_index[2], const BVHTreeFromMesh *data)
+static void cb_medge_verts_get(const int index, const void *user_data, int r_v_index[2])
{
+ const BVHTreeFromMesh *data = user_data;
const MEdge *edge = &data->edge[index];
- v_index[0] = edge->v1;
- v_index[1] = edge->v2;
+ r_v_index[0] = edge->v1;
+ r_v_index[1] = edge->v2;
}
-static void cb_bedge_verts_get(const int index, int v_index[2], const BMEditMesh *data)
+static void cb_bedge_verts_get(const int index, const void *user_data, int r_v_index[2])
{
+ const BMEditMesh *data = user_data;
BMEdge *eed = BM_edge_at_index(data->bm, index);
- v_index[0] = BM_elem_index_get(eed->v1);
- v_index[1] = BM_elem_index_get(eed->v2);
+ r_v_index[0] = BM_elem_index_get(eed->v1);
+ r_v_index[1] = BM_elem_index_get(eed->v2);
}
-static void cb_mlooptri_edges_get(const int index, int v_index[3], const BVHTreeFromMesh *data)
+static void cb_mlooptri_edges_get(const int index, const void *user_data, int r_v_index[3])
{
+ const BVHTreeFromMesh *data = user_data;
const MEdge *medge = data->edge;
const MLoop *mloop = data->loop;
const MLoopTri *lt = &data->looptri[index];
@@ -1264,22 +1271,23 @@ static void cb_mlooptri_edges_get(const int index, int v_index[3], const BVHTree
const uint tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
if (ELEM(ed->v1, tri_edge[0], tri_edge[1]) && ELEM(ed->v2, tri_edge[0], tri_edge[1])) {
// printf("real edge found\n");
- v_index[j] = mloop[lt->tri[j]].e;
+ r_v_index[j] = mloop[lt->tri[j]].e;
}
else {
- v_index[j] = -1;
+ r_v_index[j] = -1;
}
}
}
-static void cb_mlooptri_verts_get(const int index, int v_index[3], const BVHTreeFromMesh *data)
+static void cb_mlooptri_verts_get(const int index, const void *user_data, int r_v_index[3])
{
+ const BVHTreeFromMesh *data = user_data;
const MLoop *loop = data->loop;
const MLoopTri *looptri = &data->looptri[index];
- v_index[0] = loop[looptri->tri[0]].v;
- v_index[1] = loop[looptri->tri[1]].v;
- v_index[2] = loop[looptri->tri[2]].v;
+ r_v_index[0] = loop[looptri->tri[0]].v;
+ r_v_index[1] = loop[looptri->tri[1]].v;
+ r_v_index[2] = loop[looptri->tri[2]].v;
}
static bool test_projected_vert_dist(const struct DistProjectedAABBPrecalc *precalc,
@@ -1348,12 +1356,20 @@ static bool test_projected_edge_dist(const struct DistProjectedAABBPrecalc *prec
/** \name Walk DFS
* \{ */
-typedef void (*Nearest2DGetVertCoCallback)(const int index, const float **co, void *data);
-typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, const int v_index[2], void *data);
-typedef void (*Nearest2DGetTriVertsCallback)(const int index, const int v_index[3], void *data);
+typedef void (*Nearest2DGetVertCoCallback)(const int index,
+ const void *user_data,
+ const float **r_co);
+typedef void (*Nearest2DGetEdgeVertsCallback)(const int index,
+ const void *user_data,
+ int r_v_index[2]);
+typedef void (*Nearest2DGetTriVertsCallback)(const int index,
+ const void *user_data,
+ int r_v_index[3]);
/* Equal the previous one */
-typedef void (*Nearest2DGetTriEdgesCallback)(const int index, const int e_index[3], void *data);
-typedef void (*Nearest2DCopyVertNoCallback)(const int index, const float r_no[3], void *data);
+typedef void (*Nearest2DGetTriEdgesCallback)(const int index,
+ const void *user_data,
+ int r_e_index[3]);
+typedef void (*Nearest2DCopyVertNoCallback)(const int index, const void *user_data, float r_no[3]);
typedef struct Nearest2dUserData {
void *userdata;
@@ -1374,18 +1390,18 @@ static void nearest2d_data_init(SnapObjectData *sod,
{
if (sod->type == SNAP_MESH) {
r_nearest2d->userdata = &sod->treedata_mesh;
- r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
- r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
- r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
- r_nearest2d->get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get;
- r_nearest2d->get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get;
+ r_nearest2d->get_vert_co = cb_mvert_co_get;
+ r_nearest2d->get_edge_verts_index = cb_medge_verts_get;
+ r_nearest2d->copy_vert_no = cb_mvert_no_copy;
+ r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get;
+ r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get;
}
else {
BLI_assert(sod->type == SNAP_EDIT_MESH);
r_nearest2d->userdata = sod->treedata_editmesh.em;
- r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
- r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
- r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
+ r_nearest2d->get_vert_co = cb_bvert_co_get;
+ r_nearest2d->get_edge_verts_index = cb_bedge_verts_get;
+ r_nearest2d->copy_vert_no = cb_bvert_no_copy;
r_nearest2d->get_tri_verts_index = NULL;
r_nearest2d->get_tri_edges_index = NULL;
}
@@ -1404,7 +1420,7 @@ static void cb_snap_vert(void *userdata,
struct Nearest2dUserData *data = userdata;
const float *co;
- data->get_vert_co(index, &co, data->userdata);
+ data->get_vert_co(index, data->userdata, &co);
if (test_projected_vert_dist(precalc,
clip_plane,
@@ -1413,7 +1429,7 @@ static void cb_snap_vert(void *userdata,
co,
&nearest->dist_sq,
nearest->co)) {
- data->copy_vert_no(index, nearest->no, data->userdata);
+ data->copy_vert_no(index, data->userdata, nearest->no);
nearest->index = index;
}
}
@@ -1428,11 +1444,11 @@ static void cb_snap_edge(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[2];
- data->get_edge_verts_index(index, vindex, data->userdata);
+ data->get_edge_verts_index(index, data->userdata, vindex);
const float *v_pair[2];
- data->get_vert_co(vindex[0], &v_pair[0], data->userdata);
- data->get_vert_co(vindex[1], &v_pair[1], data->userdata);
+ data->get_vert_co(vindex[0], data->userdata, &v_pair[0]);
+ data->get_vert_co(vindex[1], data->userdata, &v_pair[1]);
if (test_projected_edge_dist(precalc,
clip_plane,
@@ -1457,7 +1473,7 @@ static void cb_snap_edge_verts(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[2];
- data->get_edge_verts_index(index, vindex, data->userdata);
+ data->get_edge_verts_index(index, data->userdata, vindex);
for (int i = 2; i--;) {
if (vindex[i] == nearest->index) {
@@ -1478,12 +1494,12 @@ static void cb_snap_tri_edges(void *userdata,
if (data->use_backface_culling) {
int vindex[3];
- data->get_tri_verts_index(index, vindex, data->userdata);
+ data->get_tri_verts_index(index, data->userdata, vindex);
const float *t0, *t1, *t2;
- data->get_vert_co(vindex[0], &t0, data->userdata);
- data->get_vert_co(vindex[1], &t1, data->userdata);
- data->get_vert_co(vindex[2], &t2, data->userdata);
+ data->get_vert_co(vindex[0], data->userdata, &t0);
+ data->get_vert_co(vindex[1], data->userdata, &t1);
+ data->get_vert_co(vindex[2], data->userdata, &t2);
float dummy[3];
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
return;
@@ -1491,7 +1507,7 @@ static void cb_snap_tri_edges(void *userdata,
}
int eindex[3];
- data->get_tri_edges_index(index, eindex, data->userdata);
+ data->get_tri_edges_index(index, data->userdata, eindex);
for (int i = 3; i--;) {
if (eindex[i] != -1) {
if (eindex[i] == nearest->index) {
@@ -1512,13 +1528,13 @@ static void cb_snap_tri_verts(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[3];
- data->get_tri_verts_index(index, vindex, data->userdata);
+ data->get_tri_verts_index(index, data->userdata, vindex);
if (data->use_backface_culling) {
const float *t0, *t1, *t2;
- data->get_vert_co(vindex[0], &t0, data->userdata);
- data->get_vert_co(vindex[1], &t1, data->userdata);
- data->get_vert_co(vindex[2], &t2, data->userdata);
+ data->get_vert_co(vindex[0], data->userdata, &t0);
+ data->get_vert_co(vindex[1], data->userdata, &t1);
+ data->get_vert_co(vindex[2], data->userdata, &t2);
float dummy[3];
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
return;
@@ -1693,11 +1709,11 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
int vindex[2];
- nearest2d.get_edge_verts_index(*r_index, vindex, nearest2d.userdata);
+ nearest2d.get_edge_verts_index(*r_index, nearest2d.userdata, vindex);
const float *v_pair[2];
- nearest2d.get_vert_co(vindex[0], &v_pair[0], nearest2d.userdata);
- nearest2d.get_vert_co(vindex[1], &v_pair[1], nearest2d.userdata);
+ nearest2d.get_vert_co(vindex[0], nearest2d.userdata, &v_pair[0]);
+ nearest2d.get_vert_co(vindex[1], nearest2d.userdata, &v_pair[1]);
struct DistProjectedAABBPrecalc neasrest_precalc;
{
@@ -1744,7 +1760,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
if (r_no) {
float imat[4][4];
invert_m4_m4(imat, obmat);
- nearest2d.copy_vert_no(vindex[v_id], r_no, nearest2d.userdata);
+ nearest2d.copy_vert_no(vindex[v_id], nearest2d.userdata, r_no);
mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}
@@ -2777,7 +2793,7 @@ static void snap_obj_fn(SnapObjectContext *sctx,
* \param r_loc: Hit location.
* \param r_no: Hit normal (optional).
* \param r_index: Hit index or -1 when no valid index is found.
- * (currently only set to the polygon index when using ``snap_to == SCE_SNAP_MODE_FACE``).
+ * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`).
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
*/
diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c
index 3b543cdf6ce..159d750da4e 100644
--- a/source/blender/editors/util/ed_draw.c
+++ b/source/blender/editors/util/ed_draw.c
@@ -33,6 +33,8 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_image.h"
@@ -56,6 +58,464 @@
#include "WM_api.h"
#include "WM_types.h"
+/* -------------------------------------------------------------------- */
+/** \name Generic Slider
+ *
+ * The generic slider is supposed to be called during modal operations. It calculates a factor
+ * value based on mouse position and draws a visual representation. In order to use it, you need to
+ * store a reference to a tSlider in your operator which you get by calling "ED_slider_create".
+ * Then you need to update it during modal operations by calling "ED_slider_modal", which will
+ * update tSlider->factor for you to use. To remove drawing and free the memory, call
+ * "ED_slider_destroy".
+ * \{ */
+
+#define SLIDE_PIXEL_DISTANCE (300.0f * U.dpi_fac)
+#define OVERSHOOT_RANGE_DELTA 0.2f
+
+typedef struct tSlider {
+ struct Scene *scene;
+ struct ScrArea *area;
+ /* Header of the region used for drawing the slider. */
+ struct ARegion *region_header;
+
+ /* Draw callback handler. */
+ void *draw_handle;
+
+ /* Accumulative, unclamped and unrounded factor. */
+ float raw_factor;
+
+ /** 0-1 value for determining the influence of whatever is relevant. */
+ float factor;
+
+ /* Last mouse cursor position used for mouse movement delta calculation. */
+ float last_cursor[2];
+
+ /* Enable range beyond 0-100%. */
+ bool allow_overshoot;
+
+ /* Allow overshoot or clamp between 0% and 100%. */
+ bool overshoot;
+
+ /* Move factor in 10% steps. */
+ bool increments;
+
+ /* Reduces factor delta from mouse movement. */
+ bool precision;
+} tSlider;
+
+static void draw_overshoot_triangle(const uint8_t color[4],
+ const bool facing_right,
+ const float x,
+ const float y)
+{
+ const uint shdr_pos_2d = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_blend(GPU_BLEND_ALPHA);
+ GPU_polygon_smooth(true);
+ immUniformColor3ubvAlpha(color, 225);
+ const float triangle_side_length = facing_right ? 6 * U.pixelsize : -6 * U.pixelsize;
+ const float triangle_offset = facing_right ? 2 * U.pixelsize : -2 * U.pixelsize;
+
+ immBegin(GPU_PRIM_TRIS, 3);
+ immVertex2f(shdr_pos_2d, x + triangle_offset + triangle_side_length, y);
+ immVertex2f(shdr_pos_2d, x + triangle_offset, y + triangle_side_length / 2);
+ immVertex2f(shdr_pos_2d, x + triangle_offset, y - triangle_side_length / 2);
+ immEnd();
+
+ GPU_polygon_smooth(false);
+ GPU_blend(GPU_BLEND_NONE);
+ immUnbindProgram();
+}
+
+static void draw_ticks(const float start_factor,
+ const float end_factor,
+ const float line_start[2],
+ const float base_tick_height,
+ const float line_width,
+ const uint8_t color_overshoot[4],
+ const uint8_t color_line[4])
+{
+ /* Use factor represented as 0-100 int to avoid floating point precision problems. */
+ const int tick_increment = 10;
+
+ /* Round initial_tick_factor up to the next tick_increment. */
+ int tick_percentage = ceil((start_factor * 100) / tick_increment) * tick_increment;
+
+ while (tick_percentage <= (int)(end_factor * 100)) {
+ float tick_height;
+ /* Different ticks have different heights. Multiples of 100% are the tallest, 50% is a bit
+ * smaller and the rest is the minimum size. */
+ if (tick_percentage % 100 == 0) {
+ tick_height = base_tick_height;
+ }
+ else if (tick_percentage % 50 == 0) {
+ tick_height = base_tick_height * 0.8;
+ }
+ else {
+ tick_height = base_tick_height * 0.5;
+ }
+
+ const float x = line_start[0] +
+ (((float)tick_percentage / 100) - start_factor) * SLIDE_PIXEL_DISTANCE;
+ const rctf tick_rect = {
+ .xmin = x - (line_width / 2),
+ .xmax = x + (line_width / 2),
+ .ymin = line_start[1] - (tick_height / 2),
+ .ymax = line_start[1] + (tick_height / 2),
+ };
+
+ if (tick_percentage < 0 || tick_percentage > 100) {
+ UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_overshoot, 255);
+ }
+ else {
+ UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_line, 255);
+ }
+ tick_percentage += tick_increment;
+ }
+}
+
+static void draw_main_line(const rctf *main_line_rect,
+ const float factor,
+ const bool overshoot,
+ const uint8_t color_overshoot[4],
+ const uint8_t color_line[4])
+{
+ if (overshoot) {
+ /* In overshoot mode, draw the 0-100% range differently to provide a visual reference. */
+ const float line_zero_percent = main_line_rect->xmin -
+ ((factor - 0.5f - OVERSHOOT_RANGE_DELTA) *
+ SLIDE_PIXEL_DISTANCE);
+
+ const float clamped_line_zero_percent = clamp_f(
+ line_zero_percent, main_line_rect->xmin, main_line_rect->xmax);
+ const float clamped_line_hundred_percent = clamp_f(
+ line_zero_percent + SLIDE_PIXEL_DISTANCE, main_line_rect->xmin, main_line_rect->xmax);
+
+ const rctf left_overshoot_line_rect = {
+ .xmin = main_line_rect->xmin,
+ .xmax = clamped_line_zero_percent,
+ .ymin = main_line_rect->ymin,
+ .ymax = main_line_rect->ymax,
+ };
+ const rctf right_overshoot_line_rect = {
+ .xmin = clamped_line_hundred_percent,
+ .xmax = main_line_rect->xmax,
+ .ymin = main_line_rect->ymin,
+ .ymax = main_line_rect->ymax,
+ };
+ UI_draw_roundbox_3ub_alpha(&left_overshoot_line_rect, true, 0, color_overshoot, 255);
+ UI_draw_roundbox_3ub_alpha(&right_overshoot_line_rect, true, 0, color_overshoot, 255);
+
+ const rctf non_overshoot_line_rect = {
+ .xmin = clamped_line_zero_percent,
+ .xmax = clamped_line_hundred_percent,
+ .ymin = main_line_rect->ymin,
+ .ymax = main_line_rect->ymax,
+ };
+ UI_draw_roundbox_3ub_alpha(&non_overshoot_line_rect, true, 0, color_line, 255);
+ }
+ else {
+ UI_draw_roundbox_3ub_alpha(main_line_rect, true, 0, color_line, 255);
+ }
+}
+
+static void draw_backdrop(const int fontid,
+ const rctf *main_line_rect,
+ const float color_bg[4],
+ const short region_y_size,
+ const float base_tick_height)
+{
+ float string_pixel_size[2];
+ const char *percentage_string_placeholder = "000%%";
+ BLF_width_and_height(fontid,
+ percentage_string_placeholder,
+ sizeof(percentage_string_placeholder),
+ &string_pixel_size[0],
+ &string_pixel_size[1]);
+ const float pad[2] = {(region_y_size - base_tick_height) / 2, 2.0f * U.pixelsize};
+ const rctf backdrop_rect = {
+ .xmin = main_line_rect->xmin - string_pixel_size[0] - pad[0],
+ .xmax = main_line_rect->xmax + pad[0],
+ .ymin = pad[1],
+ .ymax = region_y_size - pad[1],
+ };
+ UI_draw_roundbox_aa(&backdrop_rect, true, 4.0f, color_bg);
+}
+
+/* Draw an on screen Slider for a Pose Slide Operator. */
+static void slider_draw(const struct bContext *UNUSED(C), ARegion *region, void *arg)
+{
+ tSlider *slider = arg;
+
+ /* Only draw in region from which the Operator was started. */
+ if (region != slider->region_header) {
+ return;
+ }
+
+ uint8_t color_text[4];
+ uint8_t color_line[4];
+ uint8_t color_handle[4];
+ uint8_t color_overshoot[4];
+ float color_bg[4];
+
+ /* Get theme colors. */
+ UI_GetThemeColor4ubv(TH_TEXT, color_text);
+ UI_GetThemeColor4ubv(TH_TEXT, color_line);
+ UI_GetThemeColor4ubv(TH_TEXT, color_overshoot);
+ UI_GetThemeColor4ubv(TH_ACTIVE, color_handle);
+ UI_GetThemeColor3fv(TH_BACK, color_bg);
+
+ color_bg[3] = 0.5f;
+ color_overshoot[0] = color_overshoot[0] * 0.7;
+ color_overshoot[1] = color_overshoot[1] * 0.7;
+ color_overshoot[2] = color_overshoot[2] * 0.7;
+
+ /* Get the default font. */
+ const uiStyle *style = UI_style_get();
+ const uiFontStyle *fstyle = &style->widget;
+ const int fontid = fstyle->uifont_id;
+ BLF_color3ubv(fontid, color_text);
+ BLF_rotation(fontid, 0.0f);
+
+ const float line_width = 1.5 * U.pixelsize;
+ const float base_tick_height = 12.0 * U.pixelsize;
+ const float line_y = region->winy / 2;
+
+ rctf main_line_rect = {
+ .xmin = (region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2),
+ .xmax = (region->winx / 2) + (SLIDE_PIXEL_DISTANCE / 2),
+ .ymin = line_y - line_width / 2,
+ .ymax = line_y + line_width / 2,
+ };
+ float line_start_factor = 0;
+ int handle_pos_x = main_line_rect.xmin + SLIDE_PIXEL_DISTANCE * slider->factor;
+
+ if (slider->overshoot) {
+ main_line_rect.xmin = main_line_rect.xmin - SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA;
+ main_line_rect.xmax = main_line_rect.xmax + SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA;
+ line_start_factor = slider->factor - 0.5f - OVERSHOOT_RANGE_DELTA;
+ handle_pos_x = region->winx / 2;
+ }
+
+ draw_backdrop(fontid, &main_line_rect, color_bg, slider->region_header->winy, base_tick_height);
+
+ draw_main_line(&main_line_rect, slider->factor, slider->overshoot, color_overshoot, color_line);
+
+ const float factor_range = slider->overshoot ? 1 + OVERSHOOT_RANGE_DELTA * 2 : 1;
+ const float line_start_position[2] = {main_line_rect.xmin, line_y};
+ draw_ticks(line_start_factor,
+ line_start_factor + factor_range,
+ line_start_position,
+ base_tick_height,
+ line_width,
+ color_overshoot,
+ color_line);
+
+ /* Draw triangles at the ends of the line in overshoot mode to indicate direction of 0-100%
+ * range. */
+ if (slider->overshoot) {
+ if (slider->factor > 1 + OVERSHOOT_RANGE_DELTA + 0.5) {
+ draw_overshoot_triangle(color_line, false, main_line_rect.xmin, line_y);
+ }
+ if (slider->factor < 0 - OVERSHOOT_RANGE_DELTA - 0.5) {
+ draw_overshoot_triangle(color_line, true, main_line_rect.xmax, line_y);
+ }
+ }
+
+ char percentage_string[256];
+
+ /* Draw handle indicating current factor. */
+ const rctf handle_rect = {
+ .xmin = handle_pos_x - (line_width),
+ .xmax = handle_pos_x + (line_width),
+ .ymin = line_y - (base_tick_height / 2),
+ .ymax = line_y + (base_tick_height / 2),
+ };
+
+ UI_draw_roundbox_3ub_alpha(&handle_rect, true, 1, color_handle, 255);
+ BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", slider->factor * 100);
+
+ /* Draw percentage string. */
+ float percentage_string_pixel_size[2];
+ BLF_width_and_height(fontid,
+ percentage_string,
+ sizeof(percentage_string),
+ &percentage_string_pixel_size[0],
+ &percentage_string_pixel_size[1]);
+
+ BLF_position(fontid,
+ main_line_rect.xmin - 24.0 * U.pixelsize - percentage_string_pixel_size[0] / 2,
+ (region->winy / 2) - percentage_string_pixel_size[1] / 2,
+ 0.0f);
+ BLF_draw(fontid, percentage_string, sizeof(percentage_string));
+}
+
+static void slider_update_factor(tSlider *slider, const wmEvent *event)
+{
+ const float factor_delta = (event->x - slider->last_cursor[0]) / SLIDE_PIXEL_DISTANCE;
+ /* Reduced factor delta in precision mode (shift held). */
+ slider->raw_factor += slider->precision ? (factor_delta / 8) : factor_delta;
+ slider->factor = slider->raw_factor;
+ slider->last_cursor[0] = event->x;
+ slider->last_cursor[1] = event->y;
+
+ if (!slider->overshoot) {
+ slider->factor = clamp_f(slider->factor, 0, 1);
+ }
+
+ if (slider->increments) {
+ slider->factor = round(slider->factor * 10) / 10;
+ }
+}
+
+tSlider *ED_slider_create(struct bContext *C)
+{
+ tSlider *slider = MEM_callocN(sizeof(tSlider), "tSlider");
+ slider->scene = CTX_data_scene(C);
+ slider->area = CTX_wm_area(C);
+ slider->region_header = CTX_wm_region(C);
+
+ /* Default is true, caller needs to manually set to false. */
+ slider->allow_overshoot = true;
+
+ /* Set initial factor. */
+ slider->raw_factor = 0.5f;
+ slider->factor = 0.5;
+
+ /* Add draw callback. Always in header. */
+ LISTBASE_FOREACH (ARegion *, region, &slider->area->regionbase) {
+ if (region->regiontype == RGN_TYPE_HEADER) {
+ slider->region_header = region;
+ slider->draw_handle = ED_region_draw_cb_activate(
+ region->type, slider_draw, slider, REGION_DRAW_POST_PIXEL);
+ }
+ }
+
+ return slider;
+}
+
+/* For modal operations so the percentage doesn't pop on the first mouse movement. */
+void ED_slider_init(struct tSlider *slider, const wmEvent *event)
+{
+ slider->last_cursor[0] = event->x;
+ slider->last_cursor[1] = event->y;
+}
+
+/* Calculate slider factor based on mouse position. */
+bool ED_slider_modal(tSlider *slider, const wmEvent *event)
+{
+ bool event_handled = true;
+ /* Handle key presses. */
+ switch (event->type) {
+ case EVT_EKEY:
+ if (slider->allow_overshoot) {
+ slider->overshoot = event->val == KM_PRESS ? !slider->overshoot : slider->overshoot;
+ slider_update_factor(slider, event);
+ }
+ break;
+ case EVT_LEFTSHIFTKEY:
+ case EVT_RIGHTSHIFTKEY:
+ slider->precision = event->val == KM_PRESS;
+ break;
+ case EVT_LEFTCTRLKEY:
+ case EVT_RIGHTCTRLKEY:
+ slider->increments = event->val == KM_PRESS;
+ break;
+ case MOUSEMOVE:;
+ /* Update factor. */
+ slider_update_factor(slider, event);
+ break;
+ default:
+ event_handled = false;
+ break;
+ }
+
+ ED_region_tag_redraw(slider->region_header);
+
+ return event_handled;
+}
+
+/* Return string based on the current state of the slider. */
+void ED_slider_status_string_get(const struct tSlider *slider,
+ char *status_string,
+ const size_t size_of_status_string)
+{
+ /* 50 characters is enough to fit the individual setting strings. Extend if message is longer. */
+ char overshoot_str[50];
+ char precision_str[50];
+ char increments_str[50];
+
+ if (slider->allow_overshoot) {
+ if (slider->overshoot) {
+ STRNCPY(overshoot_str, TIP_("[E] - Disable overshoot"));
+ }
+ else {
+ STRNCPY(overshoot_str, TIP_("[E] - Enable overshoot"));
+ }
+ }
+ else {
+ STRNCPY(overshoot_str, TIP_("Overshoot disabled"));
+ }
+
+ if (slider->precision) {
+ STRNCPY(precision_str, TIP_("[Shift] - Precision active"));
+ }
+ else {
+ STRNCPY(precision_str, TIP_("Shift - Hold for precision"));
+ }
+
+ if (slider->increments) {
+ STRNCPY(increments_str, TIP_("[Ctrl] - Increments active"));
+ }
+ else {
+ STRNCPY(increments_str, TIP_("Ctrl - Hold for 10% increments"));
+ }
+
+ BLI_snprintf(status_string,
+ size_of_status_string,
+ "%s | %s | %s",
+ overshoot_str,
+ precision_str,
+ increments_str);
+}
+
+void ED_slider_destroy(struct bContext *C, tSlider *slider)
+{
+ /* Remove draw callback. */
+ ED_region_draw_cb_exit(slider->region_header->type, slider->draw_handle);
+ ED_area_status_text(slider->area, NULL);
+ ED_workspace_status_text(C, NULL);
+ MEM_freeN(slider);
+}
+
+/* Setters & Getters */
+
+float ED_slider_factor_get(struct tSlider *slider)
+{
+ return slider->factor;
+}
+
+void ED_slider_factor_set(struct tSlider *slider, const float factor)
+{
+ slider->factor = factor;
+ if (!slider->overshoot) {
+ slider->factor = clamp_f(slider->factor, 0, 1);
+ }
+}
+
+bool ED_slider_allow_overshoot_get(struct tSlider *slider)
+{
+ return slider->allow_overshoot;
+}
+
+void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value)
+{
+ slider->allow_overshoot = value;
+}
+
+/** \} */
+
/**
* Callback that draws a line between the mouse and a position given as the initial argument.
*/
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 7709b76290f..20aadb84b7b 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -1126,7 +1126,7 @@ static void uv_select_edgeloop_single_side_tag(const Scene *scene,
while (l_step != NULL) {
if (!uvedit_face_visible_test(scene, l_step->f) ||
- /* Check the boundary is still a boundary. */
+ /* Check the boundary is still a boundary. */
(uvedit_loop_find_other_radial_loop_with_visible_face(
scene, l_step, cd_loop_uv_offset) != NULL)) {
break;
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index b40e50851c3..535a0e00347 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1928,6 +1928,11 @@ static StitchState *stitch_init(bContext *C,
state->obedit = obedit;
state->em = em;
+ /* Workaround for sync-select & face-select mode which implies all selected faces are detached,
+ * for stitch this isn't useful behavior, see T86924. */
+ const int selectmode_orig = scene->toolsettings->selectmode;
+ scene->toolsettings->selectmode = SCE_SELECT_VERTEX;
+
/* in uv synch selection, all uv's are visible */
if (ts->uv_flag & UV_SYNC_SELECTION) {
state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, false, true, true);
@@ -1935,6 +1940,9 @@ static StitchState *stitch_init(bContext *C,
else {
state->element_map = BM_uv_element_map_create(state->em->bm, scene, true, false, true, true);
}
+
+ scene->toolsettings->selectmode = selectmode_orig;
+
if (!state->element_map) {
state_delete(state);
return NULL;
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index 9c675c93a2e..0d243a812fa 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -707,7 +707,7 @@ void Controller::ComputeSteerableViewMap()
for (unsigned int x = 0; x < img[i]->width(); ++x) {
//img[i]->setPixel(x, y, (float)qGray(qimg.pixel(x, y)) / 255.0f);
img[i]->setPixel(x, y, (float)qGray(qimg.pixel(x, y)));
- //float c = qGray(qimg.pixel(x, y));
+ // float c = qGray(qimg.pixel(x, y));
//img[i]->setPixel(x, y, qGray(qimg.pixel(x, y)));
}
}
diff --git a/source/blender/freestyle/intern/geometry/FastGrid.cpp b/source/blender/freestyle/intern/geometry/FastGrid.cpp
index 1e0ae06da19..0f1edd647c7 100644
--- a/source/blender/freestyle/intern/geometry/FastGrid.cpp
+++ b/source/blender/freestyle/intern/geometry/FastGrid.cpp
@@ -62,7 +62,7 @@ Cell *FastGrid::getCell(const Vec3u &p)
<< " " << _cells_size << endl;
}
#endif
- BLI_assert(_cells || ("_cells is a null pointer"));
+ BLI_assert_msg(_cells, "_cells is a null pointer");
BLI_assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]) < _cells_size);
BLI_assert(p[0] < _cells_nb[0]);
BLI_assert(p[1] < _cells_nb[1]);
@@ -72,7 +72,7 @@ Cell *FastGrid::getCell(const Vec3u &p)
void FastGrid::fillCell(const Vec3u &p, Cell &cell)
{
- BLI_assert(_cells || ("_cells is a null pointer"));
+ BLI_assert_msg(_cells, "_cells is a null pointer");
BLI_assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]) < _cells_size);
BLI_assert(p[0] < _cells_nb[0]);
BLI_assert(p[1] < _cells_nb[1]);
diff --git a/source/blender/freestyle/intern/view_map/Interface0D.h b/source/blender/freestyle/intern/view_map/Interface0D.h
index 065319578e5..d7b213706b5 100644
--- a/source/blender/freestyle/intern/view_map/Interface0D.h
+++ b/source/blender/freestyle/intern/view_map/Interface0D.h
@@ -311,13 +311,13 @@ class Interface0DIterator : public Iterator {
return result;
}
- /** operator == . */
+ /** operator `==`. */
bool operator==(const Interface0DIterator &it) const
{
return _iterator->operator==(*(it._iterator));
}
- /** operator != . */
+ /** operator `!=`. */
bool operator!=(const Interface0DIterator &it) const
{
return !(*this == it);
diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h
index 3709b0ae11a..479dbaeedc1 100644
--- a/source/blender/freestyle/intern/view_map/Silhouette.h
+++ b/source/blender/freestyle/intern/view_map/Silhouette.h
@@ -745,7 +745,7 @@ class FEdge : public Interface1D {
_VertexB = vB;
}
- /** Sets the FEdge Id . */
+ /** Sets the FEdge Id. */
inline void setId(const Id &id)
{
_Id = id;
@@ -1153,7 +1153,7 @@ class FEdgeSharp : public FEdge {
bool _bFaceMark;
public:
- /** Returns the string "FEdgeSharp" . */
+ /** Returns the string "FEdgeSharp". */
virtual string getExactTypeName() const
{
return "FEdgeSharp";
@@ -1305,7 +1305,7 @@ class FEdgeSmooth : public FEdge {
bool _FaceMark;
public:
- /** Returns the string "FEdgeSmooth" . */
+ /** Returns the string "FEdgeSmooth". */
virtual string getExactTypeName() const
{
return "FEdgeSmooth";
diff --git a/source/blender/freestyle/intern/view_map/ViewMap.h b/source/blender/freestyle/intern/view_map/ViewMap.h
index bd7edad7642..e7d57c9dfb4 100644
--- a/source/blender/freestyle/intern/view_map/ViewMap.h
+++ b/source/blender/freestyle/intern/view_map/ViewMap.h
@@ -477,10 +477,14 @@ class TVertex : public ViewVertex {
directedViewEdge _FrontEdgeB;
directedViewEdge _BackEdgeA;
directedViewEdge _BackEdgeB;
- Id _Id; // id to identify t vertices . these id will be negative in order not to be mixed with
- // NonTVertex ids.
- edge_pointers_container
- _sortedEdges; // the list of the four ViewEdges, ordered in CCW order (in the image plan)
+
+ /**
+ * ID to identify t vertices.
+ * these id will be negative in order not to be mixed with NonTVertex ids.
+ */
+ Id _Id;
+ /** The list of the four ViewEdges, ordered in CCW order (in the image plan). */
+ edge_pointers_container _sortedEdges;
public:
/** Default constructor. */
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
index 478e48de66c..f052f1af104 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
@@ -371,29 +371,29 @@ void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, V
}
e = *itE;
- /* since this vertex passed the tests in gts_vertex_mean_curvature_normal(), this should be
- * true. */
+ /* Since this vertex passed the tests in gts_vertex_mean_curvature_normal(),
+ this should be true. */
// g_assert(gts_edge_face_number (e, s) == 2);
- /* identify the two triangles bordering e in s */
+ /* Identify the two triangles bordering e in s. */
f1 = e->GetaFace();
f2 = e->GetbFace();
/* We are solving for the values of the curvature tensor
- * B = [ a b ; b c ].
- * The computations here are from section 5 of [Meyer et al 2002].
+ * `B = [ a b ; b c ]`.
+ * The computations here are from section 5 of [Meyer et al 2002].
*
- * The first step is to calculate the linear equations governing the values of (a,b,c). These
+ * The first step is to calculate the linear equations governing the values of (a,b,c). These
* can be computed by setting the derivatives of the error E to zero (section 5.3).
*
- * Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB:
- * [Meyer et al 2002] has the equation a + b = norm(Kh), but I'm almost positive this is
- * incorrect).
+ * Since a + c = norm(Kh), we only compute the linear equations for `dE/da` and `dE/db`.
+ * (NOTE: [Meyer et al 2002] has the equation `a + b = norm(Kh)`,
+ * but I'm almost positive this is incorrect).
*
- * Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this
+ * Note that the w_ij (defined in section 5.2) are all scaled by `(1/8*A_mixed)`. We drop this
* uniform scale factor because the solution of the linear equations doesn't rely on it.
*
- * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are
+ * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are
* also const_dy terms that are the constant factors in the equations.
*/
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
index a156fca5b7b..a79e212b9db 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
@@ -9,7 +9,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index fcc44aab583..bc6a9e53f11 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -432,6 +432,19 @@ static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel)
}
}
+static bool anything_showing_through(PointerRNA *ptr)
+{
+ const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels");
+ const int level_start = RNA_int_get(ptr, "level_start");
+ const int level_end = RNA_int_get(ptr, "level_end");
+ if (use_multiple_levels) {
+ return (MAX2(level_start, level_end) > 0);
+ }
+ else {
+ return (level_start > 0);
+ }
+}
+
static void material_mask_panel_draw_header(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -439,6 +452,7 @@ static void material_mask_panel_draw_header(const bContext *UNUSED(C), Panel *pa
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
uiLayoutSetEnabled(layout, !is_baked);
+ uiLayoutSetActive(layout, anything_showing_through(ptr));
uiItemR(layout, ptr, "use_material_mask", 0, IFACE_("Material Mask"), ICON_NONE);
}
@@ -450,24 +464,24 @@ static void material_mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
uiLayoutSetEnabled(layout, !is_baked);
+ uiLayoutSetActive(layout, anything_showing_through(ptr));
uiLayoutSetPropSep(layout, true);
uiLayoutSetEnabled(layout, RNA_boolean_get(ptr, "use_material_mask"));
- uiLayout *row = uiLayoutRow(layout, true);
- uiLayoutSetPropDecorate(row, false);
- uiLayout *sub = uiLayoutRowWithHeading(row, true, IFACE_("Masks"));
- char text[2] = "0";
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiLayout *sub = uiLayoutRowWithHeading(col, true, IFACE_("Masks"));
PropertyRNA *prop = RNA_struct_find_property(ptr, "use_material_mask_bits");
- for (int i = 0; i < 8; i++, text[0]++) {
- uiItemFullR(sub, ptr, prop, i, 0, UI_ITEM_R_TOGGLE, text, ICON_NONE);
+ for (int i = 0; i < 8; i++) {
+ uiItemFullR(sub, ptr, prop, i, 0, UI_ITEM_R_TOGGLE, " ", ICON_NONE);
+ if (i == 3) {
+ sub = uiLayoutRow(col, true);
+ }
}
- uiItemL(row, "", ICON_BLANK1); /* Space for decorator. */
- uiLayout *col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_material_mask_match", 0, IFACE_("Match All Masks"), ICON_NONE);
+ uiItemR(layout, ptr, "use_material_mask_match", 0, IFACE_("Exact Match"), ICON_NONE);
}
static void intersection_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -482,19 +496,18 @@ static void intersection_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_intersection"));
- uiLayout *row = uiLayoutRow(layout, true);
- uiLayoutSetPropDecorate(row, false);
- uiLayout *sub = uiLayoutRowWithHeading(row, true, IFACE_("Masks"));
- char text[2] = "0";
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiLayout *sub = uiLayoutRowWithHeading(col, true, IFACE_("Collection Masks"));
PropertyRNA *prop = RNA_struct_find_property(ptr, "use_intersection_mask");
- for (int i = 0; i < 8; i++, text[0]++) {
- uiItemFullR(sub, ptr, prop, i, 0, UI_ITEM_R_TOGGLE, text, ICON_NONE);
+ for (int i = 0; i < 8; i++) {
+ uiItemFullR(sub, ptr, prop, i, 0, UI_ITEM_R_TOGGLE, " ", ICON_NONE);
+ if (i == 3) {
+ sub = uiLayoutRow(col, true);
+ }
}
- uiItemL(row, "", ICON_BLANK1); /* Space for decorator. */
- uiLayout *col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_intersection_match", 0, IFACE_("Match All Masks"), ICON_NONE);
+ 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)
{
@@ -566,7 +579,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_fuzzy_all", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_loose_edge_chain", 0, IFACE_("Loose Edges"), ICON_NONE);
uiItemR(col, ptr, "use_loose_as_contour", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_geometry_space_chain", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_geometry_space_chain", 0, IFACE_("Geometry Space"), ICON_NONE);
uiItemR(layout,
ptr,
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 82fd85f5c65..83abac201d0 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -1803,10 +1803,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
tri->material_mask_bits |= ((mat && (mat->lineart.flags & LRT_MATERIAL_MASK_ENABLED)) ?
mat->lineart.material_mask_bits :
0);
- tri->mat_occlusion |= ((mat &&
- (mat->lineart.flags & LRT_MATERIAL_CUSTOM_OCCLUSION_EFFECTIVENESS)) ?
- mat->lineart.mat_occlusion :
- 1);
+ tri->mat_occlusion |= (mat ? mat->lineart.mat_occlusion : 1);
tri->intersection_mask = obi->override_intersection_mask;
@@ -2125,7 +2122,7 @@ static void lineart_main_load_geometries(
Object *use_ob = DEG_get_evaluated_object(depsgraph, ob);
/* Prepare the matrix used for transforming this specific object (instance). This has to be
- * done before mesh boundbox check because the function needs that. */
+ * done before mesh boundbox check because the function needs that. */
mul_m4db_m4db_m4fl_uniq(obi->model_view_proj, rb->view_projection, ob->obmat);
mul_m4db_m4db_m4fl_uniq(obi->model_view, rb->view, ob->obmat);
@@ -2156,7 +2153,7 @@ static void lineart_main_load_geometries(
obi->free_use_mesh = true;
}
- /* Make normal matrix. */
+ /* Make normal matrix. */
float imat[4][4];
invert_m4_m4(imat, ob->obmat);
transpose_m4(imat);
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
index e3a566e5f21..0d5388c6b82 100644
--- a/source/blender/gpu/GPU_vertex_format.h
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -127,7 +127,7 @@ BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format,
}
/* WARNING: Can only rename using a string with same character count.
- * WARNING: This removes all other aliases of this attrib */
+ * WARNING: This removes all other aliases of this attribute. */
void GPU_vertformat_attr_rename(GPUVertFormat *format, int attr, const char *new_name);
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len);
diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc
index 9dc24c59e22..677777132e6 100644
--- a/source/blender/gpu/intern/gpu_batch.cc
+++ b/source/blender/gpu/intern/gpu_batch.cc
@@ -184,7 +184,7 @@ int GPU_batch_instbuf_add_ex(GPUBatch *batch, GPUVertBuf *insts, bool own_vbo)
}
}
/* we only make it this far if there is no room for another GPUVertBuf */
- BLI_assert(0 && "Not enough Instance VBO slot in batch");
+ BLI_assert_msg(0, "Not enough Instance VBO slot in batch");
return -1;
}
@@ -207,7 +207,7 @@ int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
}
}
/* we only make it this far if there is no room for another GPUVertBuf */
- BLI_assert(0 && "Not enough VBO slot in batch");
+ BLI_assert_msg(0, "Not enough VBO slot in batch");
return -1;
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index d12cecd129e..bb1ebc0e85d 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -657,7 +657,7 @@ static const char *attr_prefix_get(CustomDataType type)
case CD_AUTO_FROM_NAME:
return "a";
default:
- BLI_assert(false && "GPUVertAttr Prefix type not found : This should not happen!");
+ BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!");
return "";
}
}
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index 1293cc0953d..a6f7d43e563 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -495,7 +495,7 @@ void GPU_framebuffer_py_reference_set(GPUFrameBuffer *gpu_fb, void **py_ref)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Frame-Buffer Stack
+/** \name Frame-Buffer Stack
*
* Keeps track of frame-buffer binding operation to restore previously bound frame-buffers.
* \{ */
@@ -609,7 +609,13 @@ GPUOffScreen *GPU_offscreen_create(
}
if ((depth && !ofs->depth) || !ofs->color) {
- BLI_snprintf(err_out, 256, "GPUTexture: Texture allocation failed.");
+ const char error[] = "GPUTexture: Texture allocation failed.";
+ if (err_out) {
+ BLI_snprintf(err_out, 256, error);
+ }
+ else {
+ fprintf(stderr, error);
+ }
GPU_offscreen_free(ofs);
return nullptr;
}
diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh
index 2b8a5a5cc12..26be6f57312 100644
--- a/source/blender/gpu/intern/gpu_texture_private.hh
+++ b/source/blender/gpu/intern/gpu_texture_private.hh
@@ -316,7 +316,7 @@ inline size_t to_bytesize(eGPUTextureFormat format)
case GPU_RGBA8_DXT5:
return 1; /* Incorrect but actual size is fractional. */
default:
- BLI_assert(!"Texture format incorrect or unsupported\n");
+ BLI_assert_msg(0, "Texture format incorrect or unsupported");
return 0;
}
}
@@ -333,7 +333,7 @@ inline size_t to_block_size(eGPUTextureFormat data_type)
case GPU_RGBA8_DXT5:
return 16;
default:
- BLI_assert(!"Texture format is not a compressed format\n");
+ BLI_assert_msg(0, "Texture format is not a compressed format");
return 0;
}
}
@@ -407,7 +407,7 @@ inline size_t to_bytesize(eGPUDataFormat data_format)
case GPU_DATA_2_10_10_10_REV:
return 4;
default:
- BLI_assert(!"Data format incorrect or unsupported\n");
+ BLI_assert_msg(0, "Data format incorrect or unsupported");
return 0;
}
}
@@ -503,7 +503,7 @@ inline eGPUFrameBufferBits to_framebuffer_bits(eGPUTextureFormat tex_format)
static inline eGPUTextureFormat to_texture_format(const GPUVertFormat *format)
{
if (format->attr_len > 1 || format->attr_len == 0) {
- BLI_assert(!"Incorrect vertex format for buffer texture");
+ BLI_assert_msg(0, "Incorrect vertex format for buffer texture");
return GPU_DEPTH_COMPONENT24;
}
switch (format->attrs[0].comp_len) {
@@ -584,7 +584,7 @@ static inline eGPUTextureFormat to_texture_format(const GPUVertFormat *format)
default:
break;
}
- BLI_assert(!"Unsupported vertex format for buffer texture");
+ BLI_assert_msg(0, "Unsupported vertex format for buffer texture");
return GPU_DEPTH_COMPONENT24;
}
diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc
index 9cf072b2e8a..9900a4e0766 100644
--- a/source/blender/gpu/opengl/gl_shader_interface.cc
+++ b/source/blender/gpu/opengl/gl_shader_interface.cc
@@ -170,7 +170,7 @@ GLShaderInterface::GLShaderInterface(GLuint program)
program, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &max_ssbo_name_len);
}
- BLI_assert(ubo_len <= 16 && "enabled_ubo_mask_ is uint16_t");
+ BLI_assert_msg(ubo_len <= 16, "enabled_ubo_mask_ is uint16_t");
/* Work around driver bug with Intel HD 4600 on Windows 7/8, where
* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */
diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh
index dc048ea05c0..2a480e71017 100644
--- a/source/blender/gpu/opengl/gl_texture.hh
+++ b/source/blender/gpu/opengl/gl_texture.hh
@@ -192,7 +192,7 @@ inline GLenum to_gl_internal_format(eGPUTextureFormat format)
case GPU_DEPTH_COMPONENT16:
return GL_DEPTH_COMPONENT16;
default:
- BLI_assert(!"Texture format incorrect or unsupported\n");
+ BLI_assert_msg(0, "Texture format incorrect or unsupported");
return 0;
}
}
@@ -287,7 +287,7 @@ inline GLenum to_gl(eGPUDataFormat format)
case GPU_DATA_10_11_11_REV:
return GL_UNSIGNED_INT_10F_11F_11F_REV;
default:
- BLI_assert(!"Unhandled data format");
+ BLI_assert_msg(0, "Unhandled data format");
return GL_FLOAT;
}
}
@@ -359,7 +359,7 @@ inline GLenum to_gl_data_format(eGPUTextureFormat format)
case GPU_RGBA8_DXT5:
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
default:
- BLI_assert(!"Texture format incorrect or unsupported\n");
+ BLI_assert_msg(0, "Texture format incorrect or unsupported\n");
return 0;
}
}
@@ -377,7 +377,7 @@ inline GLenum channel_len_to_gl(int channel_len)
case 4:
return GL_RGBA;
default:
- BLI_assert(!"Wrong number of texture channels");
+ BLI_assert_msg(0, "Wrong number of texture channels");
return GL_RED;
}
}
diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc
index ea2770f099d..e324916b934 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.cc
+++ b/source/blender/gpu/opengl/gl_vertex_array.cc
@@ -108,7 +108,7 @@ static uint16_t vbo_bind(const ShaderInterface *interface,
return enabled_attrib;
}
-/* Update the Attrib Binding of the currently bound VAO. */
+/* Update the Attribute Binding of the currently bound VAO. */
void GLVertArray::update_bindings(const GLuint vao,
const GPUBatch *batch_, /* Should be GLBatch. */
const ShaderInterface *interface,
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index e62473fb8c7..59a17fcc600 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -39,7 +39,7 @@
#define IMAGIC 0732
typedef struct {
- ushort imagic; /* stuff saved on disk . . */
+ ushort imagic; /* Stuff saved on disk. */
ushort type;
ushort dim;
ushort xsize;
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
index 0941338160d..3ad902a241d 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
@@ -28,7 +28,7 @@
# define _USE_MATH_DEFINES
#endif
-// NOTE: Keep first, BLI_path_util conflicts with OIIO's format.
+/* NOTE: Keep first, #BLI_path_util conflicts with OIIO's format. */
#include "openimageio_api.h"
#include <OpenImageIO/imageio.h>
#include <memory>
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index ab578e25b94..d1fa26e1a3e 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1705,7 +1705,7 @@ static void exr_print_filecontents(MultiPartInputFile &file)
}
}
-/* for non-multilayer, map R G B A channel names to something that's in this file */
+/* For non-multi-layer, map R G B A channel names to something that's in this file. */
static const char *exr_rgba_channelname(MultiPartInputFile &file, const char *chan)
{
const ChannelList &channels = file.header(0).channels();
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
index 4a964c64917..1c4b7af6ef1 100644
--- a/source/blender/imbuf/intern/scaling.c
+++ b/source/blender/imbuf/intern/scaling.c
@@ -867,7 +867,7 @@ static void q_scale_float(
*
* only handles common cases when we either
*
- * scale both, x and y or
+ * scale both, x and y or
* shrink both, x and y
*
* but that is pretty fast:
@@ -1195,22 +1195,9 @@ static ImBuf *scaleupx(struct ImBuf *ibuf, int newx)
{
uchar *rect, *_newrect = NULL, *newrect;
float *rectf, *_newrectf = NULL, *newrectf;
- float sample, add;
- float val_a, nval_a, diff_a;
- float val_b, nval_b, diff_b;
- float val_g, nval_g, diff_g;
- float val_r, nval_r, diff_r;
- float val_af, nval_af, diff_af;
- float val_bf, nval_bf, diff_bf;
- float val_gf, nval_gf, diff_gf;
- float val_rf, nval_rf, diff_rf;
int x, y;
bool do_rect = false, do_float = false;
- val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0;
- val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0;
- val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0;
- val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0;
if (ibuf == NULL) {
return NULL;
}
@@ -1236,119 +1223,158 @@ static ImBuf *scaleupx(struct ImBuf *ibuf, int newx)
}
}
- add = (ibuf->x - 1.001) / (newx - 1.0);
-
rect = (uchar *)ibuf->rect;
rectf = (float *)ibuf->rect_float;
newrect = _newrect;
newrectf = _newrectf;
- for (y = ibuf->y; y > 0; y--) {
-
- sample = 0;
-
+ /* Special case, copy all columns, needed since the scaling logic assumes there is at least
+ * two rows to interpolate between causing out of bounds read for 1px images, see T70356. */
+ if (UNLIKELY(ibuf->x == 1)) {
if (do_rect) {
- val_a = rect[0];
- nval_a = rect[4];
- diff_a = nval_a - val_a;
- val_a += 0.5f;
-
- val_b = rect[1];
- nval_b = rect[5];
- diff_b = nval_b - val_b;
- val_b += 0.5f;
-
- val_g = rect[2];
- nval_g = rect[6];
- diff_g = nval_g - val_g;
- val_g += 0.5f;
-
- val_r = rect[3];
- nval_r = rect[7];
- diff_r = nval_r - val_r;
- val_r += 0.5f;
-
- rect += 8;
+ for (y = ibuf->y; y > 0; y--) {
+ for (x = newx; x > 0; x--) {
+ memcpy(newrect, rect, sizeof(char[4]));
+ newrect += 4;
+ }
+ rect += 4;
+ }
}
if (do_float) {
- val_af = rectf[0];
- nval_af = rectf[4];
- diff_af = nval_af - val_af;
+ for (y = ibuf->y; y > 0; y--) {
+ for (x = newx; x > 0; x--) {
+ memcpy(newrectf, rectf, sizeof(float[4]));
+ newrectf += 4;
+ }
+ rectf += 4;
+ }
+ }
+ }
+ else {
+ const float add = (ibuf->x - 1.001) / (newx - 1.0);
+ float sample;
- val_bf = rectf[1];
- nval_bf = rectf[5];
- diff_bf = nval_bf - val_bf;
+ float val_a, nval_a, diff_a;
+ float val_b, nval_b, diff_b;
+ float val_g, nval_g, diff_g;
+ float val_r, nval_r, diff_r;
+ float val_af, nval_af, diff_af;
+ float val_bf, nval_bf, diff_bf;
+ float val_gf, nval_gf, diff_gf;
+ float val_rf, nval_rf, diff_rf;
- val_gf = rectf[2];
- nval_gf = rectf[6];
- diff_gf = nval_gf - val_gf;
+ val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0;
+ val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0;
+ val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0;
+ val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0;
- val_rf = rectf[3];
- nval_rf = rectf[7];
- diff_rf = nval_rf - val_rf;
+ for (y = ibuf->y; y > 0; y--) {
- rectf += 8;
- }
- for (x = newx; x > 0; x--) {
- if (sample >= 1.0f) {
- sample -= 1.0f;
+ sample = 0;
- if (do_rect) {
- val_a = nval_a;
- nval_a = rect[0];
- diff_a = nval_a - val_a;
- val_a += 0.5f;
-
- val_b = nval_b;
- nval_b = rect[1];
- diff_b = nval_b - val_b;
- val_b += 0.5f;
-
- val_g = nval_g;
- nval_g = rect[2];
- diff_g = nval_g - val_g;
- val_g += 0.5f;
-
- val_r = nval_r;
- nval_r = rect[3];
- diff_r = nval_r - val_r;
- val_r += 0.5f;
- rect += 4;
- }
- if (do_float) {
- val_af = nval_af;
- nval_af = rectf[0];
- diff_af = nval_af - val_af;
+ if (do_rect) {
+ val_a = rect[0];
+ nval_a = rect[4];
+ diff_a = nval_a - val_a;
+ val_a += 0.5f;
+
+ val_b = rect[1];
+ nval_b = rect[5];
+ diff_b = nval_b - val_b;
+ val_b += 0.5f;
+
+ val_g = rect[2];
+ nval_g = rect[6];
+ diff_g = nval_g - val_g;
+ val_g += 0.5f;
+
+ val_r = rect[3];
+ nval_r = rect[7];
+ diff_r = nval_r - val_r;
+ val_r += 0.5f;
+
+ rect += 8;
+ }
+ if (do_float) {
+ val_af = rectf[0];
+ nval_af = rectf[4];
+ diff_af = nval_af - val_af;
- val_bf = nval_bf;
- nval_bf = rectf[1];
- diff_bf = nval_bf - val_bf;
+ val_bf = rectf[1];
+ nval_bf = rectf[5];
+ diff_bf = nval_bf - val_bf;
- val_gf = nval_gf;
- nval_gf = rectf[2];
- diff_gf = nval_gf - val_gf;
+ val_gf = rectf[2];
+ nval_gf = rectf[6];
+ diff_gf = nval_gf - val_gf;
- val_rf = nval_rf;
- nval_rf = rectf[3];
- diff_rf = nval_rf - val_rf;
- rectf += 4;
- }
- }
- if (do_rect) {
- newrect[0] = val_a + sample * diff_a;
- newrect[1] = val_b + sample * diff_b;
- newrect[2] = val_g + sample * diff_g;
- newrect[3] = val_r + sample * diff_r;
- newrect += 4;
+ val_rf = rectf[3];
+ nval_rf = rectf[7];
+ diff_rf = nval_rf - val_rf;
+
+ rectf += 8;
}
- if (do_float) {
- newrectf[0] = val_af + sample * diff_af;
- newrectf[1] = val_bf + sample * diff_bf;
- newrectf[2] = val_gf + sample * diff_gf;
- newrectf[3] = val_rf + sample * diff_rf;
- newrectf += 4;
+ for (x = newx; x > 0; x--) {
+ if (sample >= 1.0f) {
+ sample -= 1.0f;
+
+ if (do_rect) {
+ val_a = nval_a;
+ nval_a = rect[0];
+ diff_a = nval_a - val_a;
+ val_a += 0.5f;
+
+ val_b = nval_b;
+ nval_b = rect[1];
+ diff_b = nval_b - val_b;
+ val_b += 0.5f;
+
+ val_g = nval_g;
+ nval_g = rect[2];
+ diff_g = nval_g - val_g;
+ val_g += 0.5f;
+
+ val_r = nval_r;
+ nval_r = rect[3];
+ diff_r = nval_r - val_r;
+ val_r += 0.5f;
+ rect += 4;
+ }
+ if (do_float) {
+ val_af = nval_af;
+ nval_af = rectf[0];
+ diff_af = nval_af - val_af;
+
+ val_bf = nval_bf;
+ nval_bf = rectf[1];
+ diff_bf = nval_bf - val_bf;
+
+ val_gf = nval_gf;
+ nval_gf = rectf[2];
+ diff_gf = nval_gf - val_gf;
+
+ val_rf = nval_rf;
+ nval_rf = rectf[3];
+ diff_rf = nval_rf - val_rf;
+ rectf += 4;
+ }
+ }
+ if (do_rect) {
+ newrect[0] = val_a + sample * diff_a;
+ newrect[1] = val_b + sample * diff_b;
+ newrect[2] = val_g + sample * diff_g;
+ newrect[3] = val_r + sample * diff_r;
+ newrect += 4;
+ }
+ if (do_float) {
+ newrectf[0] = val_af + sample * diff_af;
+ newrectf[1] = val_bf + sample * diff_bf;
+ newrectf[2] = val_gf + sample * diff_gf;
+ newrectf[3] = val_rf + sample * diff_rf;
+ newrectf += 4;
+ }
+ sample += add;
}
- sample += add;
}
}
@@ -1371,22 +1397,9 @@ static ImBuf *scaleupy(struct ImBuf *ibuf, int newy)
{
uchar *rect, *_newrect = NULL, *newrect;
float *rectf, *_newrectf = NULL, *newrectf;
- float sample, add;
- float val_a, nval_a, diff_a;
- float val_b, nval_b, diff_b;
- float val_g, nval_g, diff_g;
- float val_r, nval_r, diff_r;
- float val_af, nval_af, diff_af;
- float val_bf, nval_bf, diff_bf;
- float val_gf, nval_gf, diff_gf;
- float val_rf, nval_rf, diff_rf;
int x, y, skipx;
bool do_rect = false, do_float = false;
- val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0;
- val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0;
- val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0;
- val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0;
if (ibuf == NULL) {
return NULL;
}
@@ -1412,126 +1425,159 @@ static ImBuf *scaleupy(struct ImBuf *ibuf, int newy)
}
}
- add = (ibuf->y - 1.001) / (newy - 1.0);
- skipx = 4 * ibuf->x;
-
rect = (uchar *)ibuf->rect;
rectf = (float *)ibuf->rect_float;
newrect = _newrect;
newrectf = _newrectf;
- for (x = ibuf->x; x > 0; x--) {
+ skipx = 4 * ibuf->x;
- sample = 0;
+ /* Special case, copy all rows, needed since the scaling logic assumes there is at least
+ * two rows to interpolate between causing out of bounds read for 1px images, see T70356. */
+ if (UNLIKELY(ibuf->y == 1)) {
if (do_rect) {
- rect = ((uchar *)ibuf->rect) + 4 * (x - 1);
- newrect = _newrect + 4 * (x - 1);
-
- val_a = rect[0];
- nval_a = rect[skipx];
- diff_a = nval_a - val_a;
- val_a += 0.5f;
-
- val_b = rect[1];
- nval_b = rect[skipx + 1];
- diff_b = nval_b - val_b;
- val_b += 0.5f;
-
- val_g = rect[2];
- nval_g = rect[skipx + 2];
- diff_g = nval_g - val_g;
- val_g += 0.5f;
-
- val_r = rect[3];
- nval_r = rect[skipx + 3];
- diff_r = nval_r - val_r;
- val_r += 0.5f;
-
- rect += 2 * skipx;
+ for (y = newy; y > 0; y--) {
+ memcpy(newrect, rect, sizeof(char) * skipx);
+ newrect += skipx;
+ }
}
if (do_float) {
- rectf = ibuf->rect_float + 4 * (x - 1);
- newrectf = _newrectf + 4 * (x - 1);
-
- val_af = rectf[0];
- nval_af = rectf[skipx];
- diff_af = nval_af - val_af;
+ for (y = newy; y > 0; y--) {
+ memcpy(newrectf, rectf, sizeof(float) * skipx);
+ newrectf += skipx;
+ }
+ }
+ }
+ else {
+ const float add = (ibuf->y - 1.001) / (newy - 1.0);
+ float sample;
+
+ float val_a, nval_a, diff_a;
+ float val_b, nval_b, diff_b;
+ float val_g, nval_g, diff_g;
+ float val_r, nval_r, diff_r;
+ float val_af, nval_af, diff_af;
+ float val_bf, nval_bf, diff_bf;
+ float val_gf, nval_gf, diff_gf;
+ float val_rf, nval_rf, diff_rf;
+
+ val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0;
+ val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0;
+ val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0;
+ val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0;
+
+ for (x = ibuf->x; x > 0; x--) {
+ sample = 0;
+ if (do_rect) {
+ rect = ((uchar *)ibuf->rect) + 4 * (x - 1);
+ newrect = _newrect + 4 * (x - 1);
+
+ val_a = rect[0];
+ nval_a = rect[skipx];
+ diff_a = nval_a - val_a;
+ val_a += 0.5f;
+
+ val_b = rect[1];
+ nval_b = rect[skipx + 1];
+ diff_b = nval_b - val_b;
+ val_b += 0.5f;
+
+ val_g = rect[2];
+ nval_g = rect[skipx + 2];
+ diff_g = nval_g - val_g;
+ val_g += 0.5f;
+
+ val_r = rect[3];
+ nval_r = rect[skipx + 3];
+ diff_r = nval_r - val_r;
+ val_r += 0.5f;
+
+ rect += 2 * skipx;
+ }
+ if (do_float) {
+ rectf = ibuf->rect_float + 4 * (x - 1);
+ newrectf = _newrectf + 4 * (x - 1);
- val_bf = rectf[1];
- nval_bf = rectf[skipx + 1];
- diff_bf = nval_bf - val_bf;
+ val_af = rectf[0];
+ nval_af = rectf[skipx];
+ diff_af = nval_af - val_af;
- val_gf = rectf[2];
- nval_gf = rectf[skipx + 2];
- diff_gf = nval_gf - val_gf;
+ val_bf = rectf[1];
+ nval_bf = rectf[skipx + 1];
+ diff_bf = nval_bf - val_bf;
- val_rf = rectf[3];
- nval_rf = rectf[skipx + 3];
- diff_rf = nval_rf - val_rf;
+ val_gf = rectf[2];
+ nval_gf = rectf[skipx + 2];
+ diff_gf = nval_gf - val_gf;
- rectf += 2 * skipx;
- }
+ val_rf = rectf[3];
+ nval_rf = rectf[skipx + 3];
+ diff_rf = nval_rf - val_rf;
- for (y = newy; y > 0; y--) {
- if (sample >= 1.0f) {
- sample -= 1.0f;
+ rectf += 2 * skipx;
+ }
+ for (y = newy; y > 0; y--) {
+ if (sample >= 1.0f) {
+ sample -= 1.0f;
+
+ if (do_rect) {
+ val_a = nval_a;
+ nval_a = rect[0];
+ diff_a = nval_a - val_a;
+ val_a += 0.5f;
+
+ val_b = nval_b;
+ nval_b = rect[1];
+ diff_b = nval_b - val_b;
+ val_b += 0.5f;
+
+ val_g = nval_g;
+ nval_g = rect[2];
+ diff_g = nval_g - val_g;
+ val_g += 0.5f;
+
+ val_r = nval_r;
+ nval_r = rect[3];
+ diff_r = nval_r - val_r;
+ val_r += 0.5f;
+ rect += skipx;
+ }
+ if (do_float) {
+ val_af = nval_af;
+ nval_af = rectf[0];
+ diff_af = nval_af - val_af;
+
+ val_bf = nval_bf;
+ nval_bf = rectf[1];
+ diff_bf = nval_bf - val_bf;
+
+ val_gf = nval_gf;
+ nval_gf = rectf[2];
+ diff_gf = nval_gf - val_gf;
+
+ val_rf = nval_rf;
+ nval_rf = rectf[3];
+ diff_rf = nval_rf - val_rf;
+ rectf += skipx;
+ }
+ }
if (do_rect) {
- val_a = nval_a;
- nval_a = rect[0];
- diff_a = nval_a - val_a;
- val_a += 0.5f;
-
- val_b = nval_b;
- nval_b = rect[1];
- diff_b = nval_b - val_b;
- val_b += 0.5f;
-
- val_g = nval_g;
- nval_g = rect[2];
- diff_g = nval_g - val_g;
- val_g += 0.5f;
-
- val_r = nval_r;
- nval_r = rect[3];
- diff_r = nval_r - val_r;
- val_r += 0.5f;
- rect += skipx;
+ newrect[0] = val_a + sample * diff_a;
+ newrect[1] = val_b + sample * diff_b;
+ newrect[2] = val_g + sample * diff_g;
+ newrect[3] = val_r + sample * diff_r;
+ newrect += skipx;
}
if (do_float) {
- val_af = nval_af;
- nval_af = rectf[0];
- diff_af = nval_af - val_af;
-
- val_bf = nval_bf;
- nval_bf = rectf[1];
- diff_bf = nval_bf - val_bf;
-
- val_gf = nval_gf;
- nval_gf = rectf[2];
- diff_gf = nval_gf - val_gf;
-
- val_rf = nval_rf;
- nval_rf = rectf[3];
- diff_rf = nval_rf - val_rf;
- rectf += skipx;
+ newrectf[0] = val_af + sample * diff_af;
+ newrectf[1] = val_bf + sample * diff_bf;
+ newrectf[2] = val_gf + sample * diff_gf;
+ newrectf[3] = val_rf + sample * diff_rf;
+ newrectf += skipx;
}
+ sample += add;
}
- if (do_rect) {
- newrect[0] = val_a + sample * diff_a;
- newrect[1] = val_b + sample * diff_b;
- newrect[2] = val_g + sample * diff_g;
- newrect[3] = val_r + sample * diff_r;
- newrect += skipx;
- }
- if (do_float) {
- newrectf[0] = val_af + sample * diff_af;
- newrectf[1] = val_bf + sample * diff_bf;
- newrectf[2] = val_gf + sample * diff_gf;
- newrectf[3] = val_rf + sample * diff_rf;
- newrectf += skipx;
- }
- sample += add;
}
}
@@ -1620,6 +1666,8 @@ static void scalefast_Z_ImBuf(ImBuf *ibuf, int newx, int newy)
*/
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
+ BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
+
if (ibuf == NULL) {
return false;
}
@@ -1666,6 +1714,8 @@ struct imbufRGBA {
*/
bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
+ BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
+
unsigned int *rect, *_newrect, *newrect;
struct imbufRGBA *rectf, *_newrectf, *newrectf;
int x, y;
@@ -1838,6 +1888,8 @@ static void *do_scale_thread(void *data_v)
void IMB_scaleImBuf_threaded(ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
+ BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
+
ScaleTreadInitData init_data = {NULL};
/* prepare initialization data */
diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
index 7ffb61e1d1b..131b60b90fb 100644
--- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
@@ -538,7 +538,7 @@ static void get_loop_normals(struct Mesh *mesh,
BKE_mesh_calc_normals_split(mesh);
const float(*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL));
- BLI_assert(lnors != nullptr || !"BKE_mesh_calc_normals_split() should have computed CD_NORMAL");
+ BLI_assert_msg(lnors != nullptr, "BKE_mesh_calc_normals_split() should have computed CD_NORMAL");
normals.resize(mesh->totloop);
diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp
index 626e4258239..e52bdca0d87 100644
--- a/source/blender/io/collada/AnimationImporter.cpp
+++ b/source/blender/io/collada/AnimationImporter.cpp
@@ -1090,7 +1090,7 @@ void AnimationImporter::translate_Animations(
apply_matrix_curves(ob, animcurves, root, node, transform);
}
else {
- /* calculate rnapaths and array index of fcurves according to transformation and
+ /* Calculate RNA-paths and array index of F-curves according to transformation and
* animation class */
Assign_transform_animations(transform, &bindings[j], &animcurves, is_joint, joint_path);
diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp
index 02a4e1f3167..d2bde193c0a 100644
--- a/source/blender/io/collada/BCAnimationSampler.cpp
+++ b/source/blender/io/collada/BCAnimationSampler.cpp
@@ -161,10 +161,12 @@ void BCAnimationSampler::update_animation_curves(BCAnimation &animation,
BCSample &BCAnimationSampler::sample_object(Object *ob, int frame_index, bool for_opensim)
{
BCSample &ob_sample = sample_data.add(ob, frame_index);
- // if (export_settings.get_apply_global_orientation()) {
- // const BCMatrix &global_transform = export_settings.get_global_transform();
- // ob_sample.get_matrix(global_transform);
- //}
+#if 0
+ if (export_settings.get_apply_global_orientation()) {
+ const BCMatrix &global_transform = export_settings.get_global_transform();
+ ob_sample.get_matrix(global_transform);
+ }
+#endif
if (ob->type == OB_ARMATURE) {
bPoseChannel *pchan;
diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp
index e61ed47adee..d768d2e44e8 100644
--- a/source/blender/io/collada/ControllerExporter.cpp
+++ b/source/blender/io/collada/ControllerExporter.cpp
@@ -231,7 +231,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
uint idx = vert->dw[j].def_nr;
if (idx >= joint_index_by_def_index.size()) {
/* XXX: Maybe better find out where and
- * why the Out Of Bound indexes get created ? */
+ * why the Out Of Bound indexes get created? */
oob_counter += 1;
}
else {
diff --git a/source/blender/io/collada/DocumentExporter.cpp b/source/blender/io/collada/DocumentExporter.cpp
index 46dfdda4ede..3c64591366c 100644
--- a/source/blender/io/collada/DocumentExporter.cpp
+++ b/source/blender/io/collada/DocumentExporter.cpp
@@ -180,7 +180,7 @@ int DocumentExporter::exportCurrentScene()
bContext *C = blender_context.get_context();
PointerRNA sceneptr, unit_settings;
- PropertyRNA *system; /* unused , *scale; */
+ PropertyRNA *system; /* unused, *scale; */
clear_global_id_map();
diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp
index 5aa57159328..ef486375ce3 100644
--- a/source/blender/io/collada/MeshImporter.cpp
+++ b/source/blender/io/collada/MeshImporter.cpp
@@ -708,7 +708,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
prim.totpoly++;
}
- /* Moving cursor to the next triangle fan. */
+ /* Moving cursor to the next triangle fan. */
if (mp_has_normals) {
normal_indices += 2;
}
diff --git a/source/blender/io/collada/TransformReader.cpp b/source/blender/io/collada/TransformReader.cpp
index 81b0ffc340a..d23f8da2570 100644
--- a/source/blender/io/collada/TransformReader.cpp
+++ b/source/blender/io/collada/TransformReader.cpp
@@ -103,9 +103,11 @@ void TransformReader::dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[
COLLADABU::Math::Vector3 &axis = ro->getRotationAxis();
const float angle = (float)DEG2RAD(ro->getRotationAngle());
const float ax[] = {(float)axis[0], (float)axis[1], (float)axis[2]};
- // float quat[4];
- // axis_angle_to_quat(quat, axis, angle);
- // quat_to_mat4(m, quat);
+#if 0
+ float quat[4];
+ axis_angle_to_quat(quat, axis, angle);
+ quat_to_mat4(m, quat);
+#endif
axis_angle_to_mat4(m, ax, angle);
}
diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp
index 9967a526971..60c4a9bad13 100644
--- a/source/blender/io/collada/collada_utils.cpp
+++ b/source/blender/io/collada/collada_utils.cpp
@@ -1216,8 +1216,10 @@ static bNodeSocket *bc_group_add_input_socket(bNodeTree *ntree,
{
bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
- //bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
- //return socket;
+# if 0
+ bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
+ return socket;
+# endif
bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
bNode *inputGroup = ntreeFindType(ntree, NODE_GROUP_INPUT);
@@ -1235,8 +1237,10 @@ static bNodeSocket *bc_group_add_output_socket(bNodeTree *ntree,
{
bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
- //bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
- //return socket;
+# if 0
+ bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
+ return socket;
+# endif
bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(ntree, from_node, from_socket);
bNode *outputGroup = ntreeFindType(ntree, NODE_GROUP_OUTPUT);
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
index 3b20ac9f110..82f8444d43e 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
@@ -91,19 +91,20 @@ bool GpencilExporterPDF::write()
{
/* Support unicode character paths on Windows. */
HPDF_STATUS res = 0;
- /* TODO: It looks libharu does not support unicode. */
- //#ifdef WIN32
- // char filename_cstr[FILE_MAX];
- // BLI_strncpy(filename_cstr, filename_, FILE_MAX);
- //
- // UTF16_ENCODE(filename_cstr);
- // std::wstring wstr(filename_cstr_16);
- // res = HPDF_SaveToFile(pdf_, wstr.c_str());
- //
- // UTF16_UN_ENCODE(filename_cstr);
- //#else
+
+ /* TODO: It looks `libharu` does not support unicode. */
+#if 0 /* `ifdef WIN32` */
+ char filename_cstr[FILE_MAX];
+ BLI_strncpy(filename_cstr, filename_, FILE_MAX);
+
+ UTF16_ENCODE(filename_cstr);
+ std::wstring wstr(filename_cstr_16);
+ res = HPDF_SaveToFile(pdf_, wstr.c_str());
+
+ UTF16_UN_ENCODE(filename_cstr);
+#else
res = HPDF_SaveToFile(pdf_, filename_);
- //#endif
+#endif
return (res == 0) ? true : false;
}
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 43969bf0768..c9d652ad03d 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -621,9 +621,9 @@ typedef enum IDRecalcFlag {
* When a collection gets tagged with this flag, all objects depending on the geometry and
* transforms on any of the objects in the collection are updated. */
ID_RECALC_GEOMETRY = (1 << 1),
- /* Same as #ID_RECALC_GEOMETRY, but instead of tagging the batch cache as `dirty_all`, just tags
- what matches the deform cache. */
- ID_RECALC_GEOMETRY_DEFORM = (1 << 2),
+
+ /* ** Animation or time changed and animation is to be re-evaluated. ** */
+ ID_RECALC_ANIMATION = (1 << 2),
/* ** Particle system changed. ** */
/* Only do pathcache etc. */
@@ -683,9 +683,6 @@ typedef enum IDRecalcFlag {
* have to be copied on every update. */
ID_RECALC_PARAMETERS = (1 << 21),
- /* ** Animation or time changed and animation is to be re-evaluated. ** */
- ID_RECALC_ANIMATION = (1 << 22),
-
/* Input has changed and datablock is to be reload from disk.
* Applies to movie clips to inform that copy-on-written version is to be refreshed for the new
* input file or for color space changes. */
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index aba6ccfd3ba..baed2aa2866 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -830,7 +830,7 @@ typedef struct SpaceAction {
/** The currently active context (when not showing action). */
bDopeSheet ads;
- /** For Time-Slide transform mode drawing - current frame?. */
+ /** For Time-Slide transform mode drawing - current frame? */
float timeslide;
short flag;
@@ -838,7 +838,7 @@ typedef struct SpaceAction {
char mode;
/* Storage for sub-space types. */
char mode_prev;
- /** Automatic keyframe snapping mode . */
+ /** Automatic keyframe snapping mode. */
char autosnap;
/** (eTimeline_Cache_Flag). */
char cache_display;
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index c02035be4ac..a49a76c3f26 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -51,7 +51,7 @@ typedef struct FModifier {
/** Pointer to modifier data. */
void *data;
- /** User-defined description for the modifier - MAX_ID_NAME-2. */
+ /** User-defined description for the modifier - `MAX_ID_NAME - 2`. */
char name[64];
/** Type of f-curve modifier. */
short type;
@@ -185,7 +185,7 @@ typedef enum eFMod_Generator_Functions {
/* envelope modifier - envelope data */
typedef struct FCM_EnvelopeData {
- /** Min/max values for envelope at this point (absolute values) . */
+ /** Min/max values for envelope at this point (absolute values). */
float min, max;
/** Time for that this sample-point occurs. */
float time;
@@ -198,7 +198,7 @@ typedef struct FCM_EnvelopeData {
/* envelope-like adjustment to values (for fade in/out) */
typedef struct FMod_Envelope {
- /** Data-points defining envelope to apply (array) . */
+ /** Data-points defining envelope to apply (array). */
FCM_EnvelopeData *data;
/** Number of envelope points. */
int totvert;
@@ -210,7 +210,7 @@ typedef struct FMod_Envelope {
} FMod_Envelope;
/* cycling/repetition modifier data */
-// TODO: we can only do complete cycles...
+/* TODO: we can only do complete cycles. */
typedef struct FMod_Cycles {
/** Extrapolation mode to use before first keyframe. */
short before_mode;
@@ -321,7 +321,7 @@ typedef struct DriverTarget {
/**
* Name of the posebone to use
- * (for vars where DTAR_FLAG_STRUCT_REF is used) - MAX_ID_NAME-2.
+ * (for vars where DTAR_FLAG_STRUCT_REF is used) - `MAX_ID_NAME - 2`.
*/
char pchan_name[64];
/** Transform channel index (for #DVAR_TYPE_TRANSFORM_CHAN). */
@@ -418,7 +418,7 @@ typedef struct DriverVar {
/**
* Name of the variable to use in py-expression
- * (must be valid python identifier) - MAX_ID_NAME-2.
+ * (must be valid python identifier) - `MAX_ID_NAME - 2`.
*/
char name[64];
@@ -734,7 +734,7 @@ typedef struct NlaStrip {
/** F-Curve modifiers to be applied to the entire strip's referenced F-Curves. */
ListBase modifiers;
- /** User-Visible Identifier for Strip - MAX_ID_NAME-2. */
+ /** User-Visible Identifier for Strip - `MAX_ID_NAME - 2`. */
char name[64];
/** Influence of strip. */
@@ -873,7 +873,7 @@ typedef struct NlaTrack {
* \note not really useful, but we need a '_pad' var anyways! */
int index;
- /** Short user-description of this track - MAX_ID_NAME-2. */
+ /** Short user-description of this track - `MAX_ID_NAME - 2`. */
char name[64];
} NlaTrack;
@@ -917,7 +917,7 @@ typedef struct KS_Path {
/** ID block that keyframes are for. */
ID *id;
- /** Name of the group to add to - MAX_ID_NAME-2. */
+ /** Name of the group to add to - `MAX_ID_NAME - 2`. */
char group[64];
/** ID-type that path can be used on. */
@@ -977,13 +977,13 @@ typedef struct KeyingSet {
/** (KS_Path) paths to keyframe to. */
ListBase paths;
- /** Unique name (for search, etc.) - MAX_ID_NAME-2 . */
+ /** Unique name (for search, etc.) - `MAX_ID_NAME - 2`. */
char idname[64];
- /** User-viewable name for KeyingSet (for menus, etc.) - MAX_ID_NAME-2. */
+ /** User-viewable name for KeyingSet (for menus, etc.) - `MAX_ID_NAME - 2`. */
char name[64];
/** (RNA_DYN_DESCR_MAX) short help text. */
char description[240];
- /** Name of the typeinfo data used for the relative paths - MAX_ID_NAME-2. */
+ /** Name of the typeinfo data used for the relative paths - `MAX_ID_NAME - 2`. */
char typeinfo[64];
/** Index of the active path. */
diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h
index 3907c158573..316f8631ece 100644
--- a/source/blender/makesdna/DNA_asset_types.h
+++ b/source/blender/makesdna/DNA_asset_types.h
@@ -89,7 +89,6 @@ typedef enum eAssetLibraryType {
ASSET_LIBRARY_CUSTOM = 100,
} eAssetLibraryType;
-/* TODO copy of FileSelectAssetLibraryUID */
/**
* Information to identify a asset library. May be either one of the predefined types (current
* 'Main', builtin library, project library), or a custom type as defined in the Preferences.
@@ -116,7 +115,7 @@ typedef struct AssetLibraryReference {
#
#
typedef struct AssetHandle {
- struct FileDirEntry *file_data;
+ const struct FileDirEntry *file_data;
} AssetHandle;
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 34f50b23c77..a77fbc9e45e 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -425,7 +425,7 @@ typedef struct bRigidBodyJointConstraint {
typedef struct bClampToConstraint {
/** 'target' must be a curve. */
struct Object *tar;
- /** Which axis/plane to compare owner's location on . */
+ /** Which axis/plane to compare owner's location on. */
int flag;
/** For legacy reasons, this is flag2. used for any extra settings. */
int flag2;
@@ -474,7 +474,7 @@ typedef struct bTransformConstraint {
float from_min[3];
/** To map on to to_min/max range. */
float from_max[3];
- /** Range of motion on owner caused by target . */
+ /** Range of motion on owner caused by target. */
float to_min[3];
float to_max[3];
@@ -482,7 +482,7 @@ typedef struct bTransformConstraint {
float from_min_rot[3];
/** To map on to to_min/max range. */
float from_max_rot[3];
- /** Range of motion on owner caused by target . */
+ /** Range of motion on owner caused by target. */
float to_min_rot[3];
float to_max_rot[3];
@@ -490,7 +490,7 @@ typedef struct bTransformConstraint {
float from_min_scale[3];
/** To map on to to_min/max range. */
float from_max_scale[3];
- /** Range of motion on owner caused by target . */
+ /** Range of motion on owner caused by target. */
float to_min_scale[3];
float to_max_scale[3];
} bTransformConstraint;
@@ -1102,7 +1102,7 @@ typedef enum eRotLimit_Flags {
/* distance limit constraint */
/* bDistLimitConstraint->flag */
typedef enum eDistLimit_Flag {
- /* "soft" cushion effect when reaching the limit sphere */ // NOT IMPLEMENTED!
+ /* "soft" cushion effect when reaching the limit sphere */ /* NOT IMPLEMENTED! */
LIMITDIST_USESOFT = (1 << 0),
/* as for all Limit constraints - allow to be used during transform? */
LIMITDIST_TRANSFORM = (1 << 1),
diff --git a/source/blender/makesdna/DNA_documentation.h b/source/blender/makesdna/DNA_documentation.h
index 0251625292c..85190d8a56d 100644
--- a/source/blender/makesdna/DNA_documentation.h
+++ b/source/blender/makesdna/DNA_documentation.h
@@ -56,7 +56,7 @@
*
* Ignored structs can only be referred to from non-ignored structs
* when referred to as a pointer (where they're usually allocated
- * and cleared in ``readfile.c``).
+ * and cleared in `readfile.c`).
*
* - %Path to the header files
*
diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h
index 0552c449819..4f71a257877 100644
--- a/source/blender/makesdna/DNA_ipo_types.h
+++ b/source/blender/makesdna/DNA_ipo_types.h
@@ -63,9 +63,9 @@ typedef struct IpoDriver {
typedef struct IpoCurve {
struct IpoCurve *next, *prev;
- /** Array of BPoints (sizeof(BPoint) * totvert) - i.e. baked/imported data. */
+ /** Array of #BPoints `(sizeof(BPoint) * totvert)` - i.e. baked/imported data. */
struct BPoint *bp;
- /** Array of BezTriples (sizeof(BezTriple) * totvert) - i.e. user-editable keyframes . */
+ /** Array of #BezTriples `(sizeof(BezTriple) * totvert)` - i.e. user-editable keyframes. */
struct BezTriple *bezt;
/** Bounding boxes. */
@@ -75,7 +75,7 @@ typedef struct IpoCurve {
short blocktype, adrcode, vartype;
/** Total number of BezTriples (i.e. keyframes) on curve. */
short totvert;
- /** Interpolation and extrapolation modes . */
+ /** Interpolation and extrapolation modes. */
short ipo, extrap;
/** Flag= settings. */
short flag;
@@ -102,7 +102,7 @@ typedef struct Ipo {
/** A list of IpoCurve structs in a linked list. */
ListBase curve;
- /** Rect defining extents of keyframes?. */
+ /** Rect defining extents of keyframes? */
rctf cur;
/** Blocktype: self-explanatory; showkey: either 0 or 1
diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h
index 82ff3c95834..5ec82a68a2d 100644
--- a/source/blender/makesdna/DNA_light_types.h
+++ b/source/blender/makesdna/DNA_light_types.h
@@ -134,7 +134,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 shadowbuffer flag, softlight */
/* 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_mask_types.h b/source/blender/makesdna/DNA_mask_types.h
index 8868ac1ea12..e6a7c004078 100644
--- a/source/blender/makesdna/DNA_mask_types.h
+++ b/source/blender/makesdna/DNA_mask_types.h
@@ -93,7 +93,7 @@ typedef struct MaskSplinePointUW {
} MaskSplinePointUW;
typedef struct MaskSplinePoint {
- /** Actual point coordinates and its handles . */
+ /** Actual point coordinates and its handles. */
BezTriple bezt;
char _pad[4];
/** Number of uv feather values. */
@@ -173,7 +173,7 @@ typedef struct MaskLayer {
/** For animation. */
char flag;
- /** Matching 'Object' flag of the same name - eventually use in the outliner . */
+ /** Matching 'Object' flag of the same name - eventually use in the outliner. */
char restrictflag;
} MaskLayer;
diff --git a/source/blender/makesdna/DNA_material_defaults.h b/source/blender/makesdna/DNA_material_defaults.h
index 3f4496ce735..3fa87800b2e 100644
--- a/source/blender/makesdna/DNA_material_defaults.h
+++ b/source/blender/makesdna/DNA_material_defaults.h
@@ -45,6 +45,8 @@
.alpha_threshold = 0.5f, \
\
.blend_shadow = MA_BS_SOLID, \
+ \
+ .lineart.mat_occlusion = 1, \
}
/** \} */
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index b7354aaa724..67cd68afb8a 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -160,6 +160,8 @@ typedef struct MaterialLineArt {
typedef enum eMaterialLineArtFlags {
LRT_MATERIAL_MASK_ENABLED = (1 << 0),
+
+ /* Deprecated, kept for versioning code. */
LRT_MATERIAL_CUSTOM_OCCLUSION_EFFECTIVENESS = (1 << 1),
} eMaterialLineArtFlags;
@@ -295,37 +297,21 @@ typedef struct Material {
#define MAP_COL (1 << 0)
#define MAP_ALPHA (1 << 7)
-/* pmapto */
-/* init */
-#define MAP_PA_INIT ((1 << 5) - 1)
-#define MAP_PA_TIME (1 << 0)
-#define MAP_PA_LIFE (1 << 1)
-#define MAP_PA_DENS (1 << 2)
-#define MAP_PA_SIZE (1 << 3)
-#define MAP_PA_LENGTH (1 << 4)
-/* reset */
-#define MAP_PA_IVEL (1 << 5)
-/* physics */
-#define MAP_PA_PVEL (1 << 6)
-/* path cache */
-#define MAP_PA_CLUMP (1 << 7)
-#define MAP_PA_KINK (1 << 8)
-#define MAP_PA_ROUGH (1 << 9)
-#define MAP_PA_FREQ (1 << 10)
-
/* pr_type */
-#define MA_FLAT 0
-#define MA_SPHERE 1
-#define MA_CUBE 2
-#define MA_SHADERBALL 3
-#define MA_SPHERE_A 4 /* Used for icon renders only. */
-#define MA_TEXTURE 5
-#define MA_LAMP 6
-#define MA_SKY 7
-#define MA_HAIR 10
-#define MA_ATMOS 11
-#define MA_CLOTH 12
-#define MA_FLUID 13
+typedef enum ePreviewType {
+ MA_FLAT = 0,
+ MA_SPHERE = 1,
+ MA_CUBE = 2,
+ MA_SHADERBALL = 3,
+ MA_SPHERE_A = 4, /* Used for icon renders only. */
+ MA_TEXTURE = 5,
+ MA_LAMP = 6,
+ MA_SKY = 7,
+ MA_HAIR = 10,
+ MA_ATMOS = 11,
+ MA_CLOTH = 12,
+ MA_FLUID = 13,
+} ePreviewType;
/* pr_flag */
#define MA_PREVIEW_WORLD (1 << 0)
diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h
index f6dac88051b..1b3dbd148df 100644
--- a/source/blender/makesdna/DNA_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_modifier_defaults.h
@@ -647,7 +647,8 @@
.target = NULL, \
.verts = NULL, \
.falloff = 4.0f, \
- .numverts = 0, \
+ .num_mesh_verts = 0, \
+ .num_bind_verts = 0, \
.numpoly = 0, \
.flags = 0, \
.mat = _DNA_DEFAULT_UNIT_M4, \
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 1c765d19ce2..99c346bf589 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -2023,6 +2023,7 @@ typedef struct WeldModifierData {
/* WeldModifierData->flag */
enum {
MOD_WELD_INVERT_VGROUP = (1 << 0),
+ MOD_WELD_LOOSE_EDGES = (1 << 1),
};
/* #WeldModifierData.mode */
@@ -2180,7 +2181,7 @@ typedef struct SDefBind {
typedef struct SDefVert {
SDefBind *binds;
unsigned int numbinds;
- char _pad[4];
+ unsigned int vertex_idx;
} SDefVert;
typedef struct SurfaceDeformModifierData {
@@ -2192,11 +2193,10 @@ typedef struct SurfaceDeformModifierData {
/** Vertex bind data. */
SDefVert *verts;
float falloff;
- unsigned int numverts, numpoly;
+ unsigned int num_mesh_verts, num_bind_verts, numpoly;
int flags;
float mat[4][4];
float strength;
- char _pad[4];
char defgrp_name[64];
} SurfaceDeformModifierData;
@@ -2204,10 +2204,9 @@ typedef struct SurfaceDeformModifierData {
enum {
/* This indicates "do bind on next modifier evaluation" as well as "is bound". */
MOD_SDEF_BIND = (1 << 0),
- MOD_SDEF_INVERT_VGROUP = (1 << 1)
-
- /* MOD_SDEF_USES_LOOPTRI = (1 << 1), */ /* UNUSED */
- /* MOD_SDEF_HAS_CONCAVE = (1 << 2), */ /* UNUSED */
+ MOD_SDEF_INVERT_VGROUP = (1 << 1),
+ /* Only store bind data for nonzero vgroup weights at the time of bind. */
+ MOD_SDEF_SPARSE_BIND = (1 << 2),
};
/* Surface Deform vertex bind modes */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index ac900bbee4f..5c3cf3f340a 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1360,6 +1360,13 @@ typedef struct NodeSwitch {
uint8_t input_type;
} NodeSwitch;
+typedef struct NodeGeometryCurveSetHandles {
+ /* GeometryNodeCurveHandleType. */
+ uint8_t handle_type;
+ /* GeometryNodeCurveHandleMode. */
+ uint8_t mode;
+} NodeGeometryCurveSetHandles;
+
typedef struct NodeGeometryCurvePrimitiveLine {
/* GeometryNodeCurvePrimitiveLineMode. */
uint8_t mode;
@@ -1390,6 +1397,11 @@ typedef struct NodeGeometryCurveSubdivide {
uint8_t cuts_type;
} NodeGeometryCurveSubdivide;
+typedef struct NodeGeometryCurveTrim {
+ /* GeometryNodeCurveInterpolateMode. */
+ uint8_t mode;
+} NodeGeometryCurveTrim;
+
typedef struct NodeGeometryCurveToPoints {
/* GeometryNodeCurveSampleMode. */
uint8_t mode;
@@ -1826,6 +1838,18 @@ typedef enum GeometryNodeCurvePrimitiveCircleMode {
GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS = 1
} GeometryNodeCurvePrimitiveCircleMode;
+typedef enum GeometryNodeCurveHandleType {
+ GEO_NODE_CURVE_HANDLE_FREE = 0,
+ GEO_NODE_CURVE_HANDLE_AUTO = 1,
+ GEO_NODE_CURVE_HANDLE_VECTOR = 2,
+ GEO_NODE_CURVE_HANDLE_ALIGN = 3
+} GeometryNodeCurveHandleType;
+
+typedef enum GeometryNodeCurveHandleMode {
+ GEO_NODE_CURVE_HANDLE_LEFT = (1 << 0),
+ GEO_NODE_CURVE_HANDLE_RIGHT = (1 << 1)
+} GeometryNodeCurveHandleMode;
+
typedef enum GeometryNodeTriangulateNGons {
GEO_NODE_TRIANGULATE_NGON_BEAUTY = 0,
GEO_NODE_TRIANGULATE_NGON_EARCLIP = 1,
@@ -1949,6 +1973,11 @@ typedef enum GeometryNodeCurveSampleMode {
GEO_NODE_CURVE_SAMPLE_EVALUATED = 2,
} GeometryNodeCurveSampleMode;
+typedef enum GeometryNodeCurveInterpolateMode {
+ GEO_NODE_CURVE_INTERPOLATE_FACTOR = 0,
+ GEO_NODE_CURVE_INTERPOLATE_LENGTH = 1,
+} GeometryNodeCurveInterpolateMode;
+
typedef enum GeometryNodeAttributeTransferMapMode {
GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED = 0,
GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST = 1,
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index dd31e85647d..60a34fef899 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -336,7 +336,7 @@ typedef struct Object {
/** Deprecated, use 'matbits'. */
short colbits DNA_DEPRECATED;
- /** Transformation settings and transform locks . */
+ /** Transformation settings and transform locks. */
short transflag, protectflag;
short trackflag, upflag;
/** Used for DopeSheet filtering settings (expanded/collapsed). */
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index 1d5e5eeed31..aa11e74e89d 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -125,7 +125,7 @@ typedef struct RigidBodyOb_Shared {
*/
typedef struct RigidBodyOb {
/* General Settings for this RigidBodyOb */
- /** (eRigidBodyOb_Type) role of RigidBody in sim . */
+ /** (eRigidBodyOb_Type) role of RigidBody in sim. */
short type;
/** (eRigidBody_Shape) collision shape to use. */
short shape;
@@ -243,7 +243,7 @@ typedef struct RigidBodyCon {
struct Object *ob2;
/* General Settings for this RigidBodyCon */
- /** (eRigidBodyCon_Type) role of RigidBody in sim . */
+ /** (eRigidBodyCon_Type) role of RigidBody in sim. */
short type;
/** Number of constraint solver iterations made per simulation step. */
short num_solver_iterations;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index cd752b220a3..31352b2c8f4 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1750,7 +1750,7 @@ typedef struct Scene {
/** (runtime) info/cache used for presenting playback framerate info to the user. */
void *fps_info;
- /* none of the dependency graph vars is mean to be saved */
+ /* None of the dependency graph vars is mean to be saved. */
struct GHash *depsgraph_hash;
char _pad7[4];
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 5bd9cc7a999..d5b7458ae7b 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -522,7 +522,7 @@ typedef struct ARegion {
/** Use this string to draw info. */
char *headerstr;
- /** XXX 2.50, need spacedata equivalent?. */
+ /** XXX 2.50, need spacedata equivalent? */
void *regiondata;
ARegion_Runtime runtime;
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 55dc51e0632..af524ff4866 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -201,6 +201,7 @@ typedef struct Sequence {
ListBase anims;
float effect_fader;
+ /* DEPRECATED, only used for versioning. */
float speed_fader;
/* pointers for effects: */
@@ -335,12 +336,28 @@ typedef struct SolidColorVars {
typedef struct SpeedControlVars {
float *frameMap;
+ /* DEPRECATED, only used for versioning. */
float globalSpeed;
+ /* DEPRECATED, only used for versioning. */
int flags;
+
int length;
int lastValidFrame;
+ int speed_control_type;
+
+ float speed_fader;
+ float speed_fader_length;
+ float speed_fader_frame_number;
} SpeedControlVars;
+/* SpeedControlVars.speed_control_type */
+enum {
+ SEQ_SPEED_STRETCH = 0,
+ SEQ_SPEED_MULTIPLY = 1,
+ SEQ_SPEED_LENGTH = 2,
+ SEQ_SPEED_FRAME_NUMBER = 3,
+};
+
typedef struct GaussianBlurVars {
float size_x;
float size_y;
@@ -485,9 +502,9 @@ typedef struct SequencerScopes {
#define SEQ_EDIT_PROXY_DIR_STORAGE 1
/* SpeedControlVars->flags */
-#define SEQ_SPEED_INTEGRATE (1 << 0)
+#define SEQ_SPEED_UNUSED_2 (1 << 0) /* cleared */
#define SEQ_SPEED_UNUSED_1 (1 << 1) /* cleared */
-#define SEQ_SPEED_COMPRESS_IPO_Y (1 << 2)
+#define SEQ_SPEED_UNUSED_3 (1 << 2) /* cleared */
#define SEQ_SPEED_USE_INTERPOLATION (1 << 3)
/* ***************** SEQUENCE ****************** */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index b990de29ff3..04c9eab33f1 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -24,6 +24,7 @@
#pragma once
+#include "DNA_asset_types.h"
#include "DNA_color_types.h" /* for Histogram */
#include "DNA_defs.h"
#include "DNA_image_types.h" /* ImageUser */
@@ -696,24 +697,6 @@ typedef enum eSpaceSeq_OverlayType {
/** \name File Selector
* \{ */
-/**
- * Information to identify a asset library. May be either one of the predefined types (current
- * 'Main', builtin library, project library), or a custom type as defined in the Preferences.
- *
- * If the type is set to #ASSET_LIBRARY_CUSTOM, idname must have the name to identify the
- * custom library. Otherwise idname is not used.
- */
-typedef struct FileSelectAssetLibraryUID {
- short type; /* eFileAssetLibrary_Type */
- char _pad[2];
- /**
- * If showing a custom asset library (#ASSET_LIBRARY_CUSTOM), this is the index of the
- * #bUserAssetLibrary within #UserDef.asset_libraries.
- * Should be ignored otherwise (but better set to -1 then, for sanity and debugging).
- */
- int custom_library_index;
-} FileSelectAssetLibraryUID;
-
/* Config and Input for File Selector */
typedef struct FileSelectParams {
/** Title, also used for the text of the execute button. */
@@ -785,7 +768,7 @@ typedef struct FileSelectParams {
typedef struct FileAssetSelectParams {
FileSelectParams base_params;
- FileSelectAssetLibraryUID asset_library;
+ AssetLibraryReference asset_library;
short import_type; /* eFileAssetImportType */
char _pad[6];
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index 2308f04c4c7..ee33e8666ec 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -54,11 +54,10 @@ typedef struct MTex {
float ofs[3], size[3], rot, random_angle;
char _pad0[2];
- short colormodel, pmapto, pmaptoneg;
+ short colormodel;
short normapspace, which_output;
float r, g, b, k;
float def_var;
- char _pad1[4];
/* common */
float colfac, varfac;
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 629aa191890..5f8a8c6230a 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -513,7 +513,7 @@ typedef struct bTheme {
typedef struct bAddon {
struct bAddon *next, *prev;
char module[64];
- /** User-Defined Properties on this Addon (for storing preferences). */
+ /** User-Defined Properties on this add-on (for storing preferences). */
IDProperty *prop;
} bAddon;
@@ -800,7 +800,7 @@ typedef struct UserDef {
short rvisize;
/** Rotating view icon brightness. */
short rvibright;
- /** Maximum number of recently used files to remember . */
+ /** Maximum number of recently used files to remember. */
short recent_files;
/** Milliseconds to spend spinning the view. */
short smooth_viewtx;
@@ -1291,7 +1291,7 @@ typedef enum eTimecodeStyles {
USER_TIMECODE_SECONDS_ONLY = 4,
/**
* Private (not exposed as generic choices) options.
- * milliseconds for sub-frames , SubRip format- HH:MM:SS,sss.
+ * milliseconds for sub-frames, SubRip format- HH:MM:SS,sss.
*/
USER_TIMECODE_SUBRIP = 100,
} eTimecodeStyles;
diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h
index 131772d49b4..c385ac04bd3 100644
--- a/source/blender/makesdna/DNA_view2d_types.h
+++ b/source/blender/makesdna/DNA_view2d_types.h
@@ -50,7 +50,7 @@ typedef struct View2D {
/** Scroll_ui - temp settings used for UI drawing of scrollers. */
short scroll_ui;
- /** Keeptot - 'cur' rect cannot move outside the 'tot' rect?. */
+ /** Keeptot - 'cur' rect cannot move outside the 'tot' rect? */
short keeptot;
/** Keepzoom - axes that zooming cannot occur on, and also clamp within zoom-limits. */
short keepzoom;
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 94e89944f08..a9016dd4edd 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -94,7 +94,7 @@ typedef struct Report {
/** ReportType. */
short type;
short flag;
- /** `strlen(message)`, saves some time calculating the word wrap . */
+ /** `strlen(message)`, saves some time calculating the word wrap. */
int len;
const char *typestr;
const char *message;
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index 9ed01a7dbcc..2bac040ea90 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -139,7 +139,7 @@ typedef struct WorkSpace {
/** Workspace-wide active asset library, for asset UIs to use (e.g. asset view UI template). The
* Asset Browser has its own and doesn't use this. */
- AssetLibraryReference active_asset_library;
+ AssetLibraryReference asset_library;
} WorkSpace;
/**
diff --git a/source/blender/makesdna/DNA_xr_types.h b/source/blender/makesdna/DNA_xr_types.h
index 8e63760fef7..fc00d5eb839 100644
--- a/source/blender/makesdna/DNA_xr_types.h
+++ b/source/blender/makesdna/DNA_xr_types.h
@@ -50,6 +50,7 @@ typedef struct XrSessionSettings {
typedef enum eXrSessionFlag {
XR_SESSION_USE_POSITION_TRACKING = (1 << 0),
+ XR_SESSION_USE_ABSOLUTE_TRACKING = (1 << 1),
} eXrSessionFlag;
typedef enum eXRSessionBasePoseType {
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index d23b9441822..24d0d39292e 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -84,8 +84,8 @@
* **Remember to read/write integer and short aligned!**
*
* While writing a file, the names of a struct is indicated with a type number,
- * to be found with: ``type = DNA_struct_find_nr(SDNA *, const char *)``
- * The value of ``type`` corresponds with the index within the structs array
+ * to be found with: `type = DNA_struct_find_nr(SDNA *, const char *)`
+ * The value of `type` corresponds with the index within the structs array
*
* For the moment: the complete DNA file is included in a .blend file. For
* the future we can think of smarter methods, like only included the used
@@ -101,7 +101,7 @@
* - Change of a pointer type: when the name doesn't change the contents is copied.
*
* NOT YET:
- * - array (``vec[3]``) to float struct (``vec3f``).
+ * - array (`vec[3]`) to float struct (`vec3f`).
*
* DONE:
* - Endian compatibility.
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index 735be0c10bf..d363e40e4f0 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -136,4 +136,5 @@ DNA_STRUCT_RENAME_ELEM(wmWindow, global_area_map, global_areas)
DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, line_types, edge_types)
DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_flags, mask_switches)
DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_mask, material_mask_bits)
+DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numverts, num_bind_verts)
DNA_STRUCT_RENAME_ELEM(MaterialLineArt, transparency_mask, material_mask_bits)
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index c2335b82fca..d880c892aa9 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -226,7 +226,7 @@ typedef enum PropertyFlag {
PROP_ICONS_CONSECUTIVE = (1 << 12),
PROP_ICONS_REVERSE = (1 << 8),
- /** Hidden in the user interface. */
+ /** Hidden in the user interface. */
PROP_HIDDEN = (1 << 19),
/** Do not write in presets. */
PROP_SKIP_SAVE = (1 << 28),
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 0285ef44e17..feacd47c98c 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -5031,7 +5031,7 @@ static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen, int
}
}
else {
- /* get data until . or [ */
+ /* Get data until `.` or `[`. */
p = *path;
while (*p && *p != '.' && *p != '[') {
@@ -5998,7 +5998,7 @@ static void rna_path_array_multi_string_from_flat_index(PointerRNA *ptr,
/**
* \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
- * \param index: The *flattened* index to use when \a ``index_dim > 0``,
+ * \param index: The *flattened* index to use when \a `index_dim > 0`,
* this is expanded when used with multi-dimensional arrays.
*/
char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c
index 0020d90ba1a..484b7593812 100644
--- a/source/blender/makesrna/intern/rna_asset.c
+++ b/source/blender/makesrna/intern/rna_asset.c
@@ -129,7 +129,17 @@ static void rna_AssetMetaData_active_tag_range(
static PointerRNA rna_AssetHandle_file_data_get(PointerRNA *ptr)
{
AssetHandle *asset_handle = ptr->data;
- return rna_pointer_inherit_refine(ptr, &RNA_FileSelectEntry, asset_handle->file_data);
+ /* Have to cast away const, but the file entry API doesn't allow modifications anyway. */
+ return rna_pointer_inherit_refine(
+ ptr, &RNA_FileSelectEntry, (FileDirEntry *)asset_handle->file_data);
+}
+
+static void rna_AssetHandle_file_data_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *UNUSED(reports))
+{
+ AssetHandle *asset_handle = ptr->data;
+ asset_handle->file_data = value.data;
}
static void rna_AssetHandle_get_full_library_path(
@@ -146,83 +156,22 @@ static void rna_AssetHandle_get_full_library_path(
static PointerRNA rna_AssetHandle_local_id_get(PointerRNA *ptr)
{
const AssetHandle *asset = ptr->data;
- ID *id = ED_assetlist_asset_local_id_get(asset);
+ ID *id = ED_asset_handle_get_local_id(asset);
return rna_pointer_inherit_refine(ptr, &RNA_ID, id);
}
-static void rna_AssetHandle_file_data_set(PointerRNA *ptr,
- PointerRNA value,
- struct ReportList *UNUSED(reports))
-{
- AssetHandle *asset_handle = ptr->data;
- asset_handle->file_data = value.data;
-}
-
-int rna_asset_library_reference_get(const AssetLibraryReference *library)
-{
- return ED_asset_library_reference_to_enum_value(library);
-}
-
-void rna_asset_library_reference_set(AssetLibraryReference *library, int value)
-{
- *library = ED_asset_library_reference_from_enum_value(value);
-}
-
const EnumPropertyItem *rna_asset_library_reference_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
- const EnumPropertyItem predefined_items[] = {
- /* For the future. */
- // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
- {ASSET_LIBRARY_LOCAL,
- "LOCAL",
- ICON_BLENDER,
- "Current File",
- "Show the assets currently available in this Blender session"},
- {0, NULL, 0, NULL, NULL},
- };
-
- EnumPropertyItem *item = NULL;
- int totitem = 0;
-
- /* Add separator if needed. */
- if (!BLI_listbase_is_empty(&U.asset_libraries)) {
- const EnumPropertyItem sepr = {0, "", 0, "Custom", NULL};
- RNA_enum_item_add(&item, &totitem, &sepr);
+ const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf();
+ if (!items) {
+ *r_free = false;
}
- int i = 0;
- for (bUserAssetLibrary *user_library = U.asset_libraries.first; user_library;
- user_library = user_library->next, i++) {
- /* Note that the path itself isn't checked for validity here. If an invalid library path is
- * used, the Asset Browser can give a nice hint on what's wrong. */
- const bool is_valid = (user_library->name[0] && user_library->path[0]);
- if (!is_valid) {
- continue;
- }
-
- /* Use library path as description, it's a nice hint for users. */
- EnumPropertyItem tmp = {ASSET_LIBRARY_CUSTOM + i,
- user_library->name,
- ICON_NONE,
- user_library->name,
- user_library->path};
- RNA_enum_item_add(&item, &totitem, &tmp);
- }
-
- if (totitem) {
- const EnumPropertyItem sepr = {0, "", 0, "Built-in", NULL};
- RNA_enum_item_add(&item, &totitem, &sepr);
- }
-
- /* Add predefined items. */
- RNA_enum_items_add(&item, &totitem, predefined_items);
-
- RNA_enum_item_end(&item, &totitem);
*r_free = true;
- return item;
+ return items;
}
#else
@@ -343,13 +292,16 @@ static void rna_def_asset_handle(BlenderRNA *brna)
srna = RNA_def_struct(brna, "AssetHandle", "PropertyGroup");
RNA_def_struct_ui_text(srna, "Asset Handle", "Reference to some asset");
- /* TODO why is this editable? There probably shouldn't be a setter. */
+ /* TODO It is super ugly to expose the file data here. We have to do it though so the asset view
+ * template can populate a RNA collection with asset-handles, which are just file entries
+ * currently. A proper design is being worked on. */
prop = RNA_def_property(srna, "file_data", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "FileSelectEntry");
RNA_def_property_pointer_funcs(
prop, "rna_AssetHandle_file_data_get", "rna_AssetHandle_file_data_set", NULL, NULL);
- RNA_def_property_ui_text(prop, "File Entry", "File data used to refer to the asset");
+ RNA_def_property_ui_text(
+ prop, "File Entry", "TEMPORARY, DO NOT USE - File data used to refer to the asset");
prop = RNA_def_property(srna, "local_id", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ID");
@@ -377,7 +329,7 @@ PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna,
const char *get,
const char *set)
{
- PropertyRNA *prop = RNA_def_property(srna, "active_asset_library", PROP_ENUM, PROP_NONE);
+ PropertyRNA *prop = RNA_def_property(srna, "asset_library", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, DummyRNA_NULL_items);
RNA_def_property_enum_funcs(prop, get, set, "rna_asset_library_reference_itemf");
diff --git a/source/blender/makesrna/intern/rna_collection.c b/source/blender/makesrna/intern/rna_collection.c
index 752c9495e50..608a8e51b09 100644
--- a/source/blender/makesrna/intern/rna_collection.c
+++ b/source/blender/makesrna/intern/rna_collection.c
@@ -170,7 +170,7 @@ static bool rna_Collection_objects_override_apply(Main *bmain,
Collection *coll_dst = (Collection *)ptr_dst->owner_id;
if (ptr_item_dst->type == NULL || ptr_item_src->type == NULL) {
- // BLI_assert(0 && "invalid source or destination object.");
+ // BLI_assert_msg(0, "invalid source or destination object.");
return false;
}
@@ -185,7 +185,7 @@ static bool rna_Collection_objects_override_apply(Main *bmain,
&coll_dst->gobject, ob_dst, offsetof(CollectionObject, ob));
if (cob_dst == NULL) {
- BLI_assert(0 && "Could not find destination object in destination collection!");
+ BLI_assert_msg(0, "Could not find destination object in destination collection!");
return false;
}
@@ -288,7 +288,7 @@ static bool rna_Collection_children_override_apply(Main *bmain,
&coll_dst->children, subcoll_dst, offsetof(CollectionChild, collection));
if (collchild_dst == NULL) {
- BLI_assert(0 && "Could not find destination sub-collection in destination collection!");
+ BLI_assert_msg(0, "Could not find destination sub-collection in destination collection!");
return false;
}
diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c
index 9da08de2168..70fb10c54b0 100644
--- a/source/blender/makesrna/intern/rna_context.c
+++ b/source/blender/makesrna/intern/rna_context.c
@@ -146,7 +146,9 @@ static PointerRNA rna_Context_asset_file_handle_get(PointerRNA *ptr)
}
PointerRNA newptr;
- RNA_pointer_create(NULL, &RNA_FileSelectEntry, asset_handle.file_data, &newptr);
+ /* Have to cast away const, but the file entry API doesn't allow modifications anyway. */
+ RNA_pointer_create(
+ NULL, &RNA_FileSelectEntry, (struct FileDirEntry *)asset_handle.file_data, &newptr);
return newptr;
}
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index f1c05079d9c..b5dea7b019f 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -656,6 +656,24 @@ static void rna_TextureGpencilModifier_material_set(PointerRNA *ptr,
rna_GpencilModifier_material_set(ptr, value, ma_target, reports);
}
+static void rna_Lineart_start_level_set(PointerRNA *ptr, int value)
+{
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)ptr->data;
+
+ CLAMP(value, 0, 128);
+ lmd->level_start = value;
+ lmd->level_end = MAX2(value, lmd->level_end);
+}
+
+static void rna_Lineart_end_level_set(PointerRNA *ptr, int value)
+{
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)ptr->data;
+
+ CLAMP(value, 0, 128);
+ lmd->level_end = value;
+ lmd->level_start = MIN2(value, lmd->level_start);
+}
+
#else
static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
@@ -3068,12 +3086,14 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Level Start", "Minimum number of occlusions for the generated strokes");
RNA_def_property_range(prop, 0, 128);
+ RNA_def_property_int_funcs(prop, NULL, "rna_Lineart_start_level_set", NULL);
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "level_end", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(
prop, "Level End", "Maximum number of occlusions for the generated strokes");
RNA_def_property_range(prop, 0, 128);
+ RNA_def_property_int_funcs(prop, NULL, "rna_Lineart_end_level_set", NULL);
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "target_material", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 9dc08430307..0bb76fd933a 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -270,8 +270,6 @@ void rna_def_view_layer_common(struct BlenderRNA *brna, struct StructRNA *srna,
PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna,
const char *get,
const char *set);
-int rna_asset_library_reference_get(const struct AssetLibraryReference *library);
-void rna_asset_library_reference_set(struct AssetLibraryReference *library, int value);
const EnumPropertyItem *rna_asset_library_reference_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index b662f54ed4c..d91c0bfaf29 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -702,14 +702,6 @@ static void rna_def_material_lineart(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mask", "");
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
- prop = RNA_def_property(srna, "use_mat_occlusion", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_default(prop, 0);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_MATERIAL_CUSTOM_OCCLUSION_EFFECTIVENESS);
- RNA_def_property_ui_text(prop,
- "Custom Occlusion Effectiveness",
- "Use custom occlusion effectiveness for this material");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
-
prop = RNA_def_property(srna, "mat_occlusion", PROP_INT, PROP_NONE);
RNA_def_property_int_default(prop, 1);
RNA_def_property_ui_range(prop, 0.0f, 5.0f, 1.0f, 1);
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index e64eaf8c363..388f587dfb4 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -6279,6 +6279,12 @@ static void rna_def_modifier_weld(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "loose_edges", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WELD_LOOSE_EDGES);
+ RNA_def_property_ui_text(
+ prop, "Only Loose Edges", "Collapse edges without faces, cloth sewing edges");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
RNA_define_lib_overridable(false);
}
@@ -6884,6 +6890,15 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "use_sparse_bind", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SDEF_SPARSE_BIND);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(
+ prop,
+ "Sparse Bind",
+ "Only record binding data for vertices matching the vertex group at the time of bind");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, -100, 100);
RNA_def_property_ui_range(prop, -100, 100, 10, 2);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 86e94690395..9696b05cf71 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -6638,10 +6638,9 @@ static void def_cmp_image(StructRNA *srna)
"Put node output buffer to straight alpha instead of premultiplied");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
- /* NB: image user properties used in the UI are redefined in def_node_image_user,
+ /* NOTE: Image user properties used in the UI are redefined in def_node_image_user,
* to trigger correct updates of the node editor. RNA design problem that prevents
- * updates from nested structs ...
- */
+ * updates from nested structs. */
RNA_def_struct_sdna_from(srna, "ImageUser", "storage");
def_node_image_user(srna);
}
@@ -6738,9 +6737,8 @@ static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna,
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket");
RNA_def_function_return(func, parm);
- /* NB: methods below can use the standard node socket API functions,
- * included here for completeness.
- */
+ /* NOTE: methods below can use the standard node socket API functions,
+ * included here for completeness. */
func = RNA_def_function(srna, "remove", "rna_Node_socket_remove");
RNA_def_function_ui_description(func, "Remove a file slot from this node");
@@ -9459,6 +9457,52 @@ static void def_geo_attribute_vector_rotate(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_curve_set_handles(StructRNA *srna)
+{
+ static const EnumPropertyItem type_items[] = {
+ {GEO_NODE_CURVE_HANDLE_FREE,
+ "FREE",
+ ICON_HANDLE_FREE,
+ "Free",
+ "The handle can be moved anywhere, and doesn't influence the point's other handle"},
+ {GEO_NODE_CURVE_HANDLE_AUTO,
+ "AUTO",
+ ICON_HANDLE_AUTO,
+ "Auto",
+ "The location is automatically calculated to be smooth"},
+ {GEO_NODE_CURVE_HANDLE_VECTOR,
+ "VECTOR",
+ ICON_HANDLE_VECTOR,
+ "Vector",
+ "The location is calculated to point to the next/previous control point"},
+ {GEO_NODE_CURVE_HANDLE_ALIGN,
+ "ALIGN",
+ ICON_HANDLE_ALIGNED,
+ "Align",
+ "The location is constrained to point in the opposite direction as the other handle"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem mode_items[] = {
+ {GEO_NODE_CURVE_HANDLE_LEFT, "LEFT", ICON_NONE, "Left", "Update the left handles"},
+ {GEO_NODE_CURVE_HANDLE_RIGHT, "RIGHT", ICON_NONE, "Right", "Update the right handles"},
+ {0, NULL, 0, NULL, NULL}};
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSetHandles", "storage");
+
+ prop = RNA_def_property(srna, "handle_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "handle_type");
+ RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "Whether to update left and right handles");
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_curve_primitive_circle(StructRNA *srna)
{
static const EnumPropertyItem mode_items[] = {
@@ -10055,6 +10099,32 @@ static void def_geo_curve_to_points(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_curve_trim(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem mode_items[] = {
+ {GEO_NODE_CURVE_INTERPOLATE_FACTOR,
+ "FACTOR",
+ 0,
+ "Factor",
+ "Find the endpoint positions using a factor of each spline's length"},
+ {GEO_NODE_CURVE_INTERPOLATE_LENGTH,
+ "LENGTH",
+ 0,
+ "Length",
+ "Find the endpoint positions using a length from the start of each spline"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryCurveTrim", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "How to find endpoint positions for the trimmed spline");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_attribute_transfer(StructRNA *srna)
{
static EnumPropertyItem mapping_items[] = {
@@ -10291,11 +10361,11 @@ static void rna_def_node_socket(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "Node", "Node owning this socket");
- /* NB: the type property is used by standard sockets.
+ /* NOTE: The type property is used by standard sockets.
* Ideally should be defined only for the registered subclass,
* but to use the existing DNA is added in the base type here.
- * Future socket types can ignore or override this if needed.
- */
+ * Future socket types can ignore or override this if needed. */
+
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, node_socket_type_items);
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index e110459eeea..ed681291e29 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -1997,16 +1997,25 @@ static void rna_Object_boundbox_get(PointerRNA *ptr, float *values)
}
}
+static bool check_object_vgroup_support_and_warn(const Object *ob,
+ const char *op_name,
+ ReportList *reports)
+{
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ const char *ob_type_name = "Unknown";
+ RNA_enum_name_from_value(rna_enum_object_type_items, ob->type, &ob_type_name);
+ BKE_reportf(reports, RPT_ERROR, "%s is not supported for '%s' objects", op_name, ob_type_name);
+ return false;
+ }
+ return true;
+}
+
static bDeformGroup *rna_Object_vgroup_new(Object *ob,
Main *bmain,
ReportList *reports,
const char *name)
{
- if (!OB_TYPE_SUPPORT_VGROUP(ob->type)) {
- const char *ob_type_name = "Unknown";
- RNA_enum_name_from_value(rna_enum_object_type_items, ob->type, &ob_type_name);
- BKE_reportf(
- reports, RPT_ERROR, "VertexGroups.new(): is not supported for '%s' objects", ob_type_name);
+ if (!check_object_vgroup_support_and_warn(ob, "VertexGroups.new()", reports)) {
return NULL;
}
@@ -2023,6 +2032,10 @@ static void rna_Object_vgroup_remove(Object *ob,
ReportList *reports,
PointerRNA *defgroup_ptr)
{
+ if (!check_object_vgroup_support_and_warn(ob, "VertexGroups.remove()", reports)) {
+ return;
+ }
+
bDeformGroup *defgroup = defgroup_ptr->data;
ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
@@ -2042,8 +2055,12 @@ static void rna_Object_vgroup_remove(Object *ob,
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
}
-static void rna_Object_vgroup_clear(Object *ob, Main *bmain)
+static void rna_Object_vgroup_clear(Object *ob, Main *bmain, ReportList *reports)
{
+ if (!check_object_vgroup_support_and_warn(ob, "VertexGroups.clear()", reports)) {
+ return;
+ }
+
BKE_object_defgroup_remove_all(ob);
DEG_relations_tag_update(bmain);
@@ -2777,7 +2794,7 @@ static void rna_def_object_vertex_groups(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "clear", "rna_Object_vgroup_clear");
- RNA_def_function_flag(func, FUNC_USE_MAIN);
+ RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Delete all vertex groups from object");
}
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 6008ef40b60..b080e572fa2 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -2089,7 +2089,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain),
switch (RNA_property_type(prop_local)) {
case PROP_BOOLEAN:
/* TODO: support boolean ops? Really doubt this would ever be useful though. */
- BLI_assert(0 && "Boolean properties support no override diff operation");
+ BLI_assert_msg(0, "Boolean properties support no override diff operation");
break;
case PROP_INT: {
int prop_min, prop_max;
@@ -2123,7 +2123,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain),
for (int j = len_local; j--;) {
array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]);
if (array_b[j] < prop_min || array_b[j] > prop_max) {
- /* We failed to find a suitable diff op,
+ /* We failed to find a suitable diff op,
* fall back to plain REPLACE one. */
opop->operation = IDOVERRIDE_LIBRARY_OP_REPLACE;
do_set = false;
@@ -2143,7 +2143,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain),
break;
}
default:
- BLI_assert(0 && "Unsupported RNA override diff operation on integer");
+ BLI_assert_msg(0, "Unsupported RNA override diff operation on integer");
break;
}
@@ -2175,7 +2175,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain),
break;
}
default:
- BLI_assert(0 && "Unsupported RNA override diff operation on integer");
+ BLI_assert_msg(0, "Unsupported RNA override diff operation on integer");
break;
}
}
@@ -2213,7 +2213,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain),
for (int j = len_local; j--;) {
array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]);
if (array_b[j] < prop_min || array_b[j] > prop_max) {
- /* We failed to find a suitable diff op,
+ /* We failed to find a suitable diff op,
* fall back to plain REPLACE one. */
opop->operation = IDOVERRIDE_LIBRARY_OP_REPLACE;
do_set = false;
@@ -2256,7 +2256,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain),
break;
}
default:
- BLI_assert(0 && "Unsupported RNA override diff operation on float");
+ BLI_assert_msg(0, "Unsupported RNA override diff operation on float");
break;
}
@@ -2299,7 +2299,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain),
break;
}
default:
- BLI_assert(0 && "Unsupported RNA override diff operation on float");
+ BLI_assert_msg(0, "Unsupported RNA override diff operation on float");
break;
}
}
@@ -2307,17 +2307,17 @@ bool rna_property_override_store_default(Main *UNUSED(bmain),
}
case PROP_ENUM:
/* TODO: support add/sub, for bitflags? */
- BLI_assert(0 && "Enum properties support no override diff operation");
+ BLI_assert_msg(0, "Enum properties support no override diff operation");
break;
case PROP_POINTER:
- BLI_assert(0 && "Pointer properties support no override diff operation");
+ BLI_assert_msg(0, "Pointer properties support no override diff operation");
break;
case PROP_STRING:
- BLI_assert(0 && "String properties support no override diff operation");
+ BLI_assert_msg(0, "String properties support no override diff operation");
break;
case PROP_COLLECTION:
/* XXX TODO: support this of course... */
- BLI_assert(0 && "Collection properties support no override diff operation");
+ BLI_assert_msg(0, "Collection properties support no override diff operation");
break;
default:
break;
@@ -2364,7 +2364,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
RNA_property_boolean_set_array(ptr_dst, prop_dst, array_a);
break;
default:
- BLI_assert(0 && "Unsupported RNA override operation on boolean");
+ BLI_assert_msg(0, "Unsupported RNA override operation on boolean");
return false;
}
@@ -2380,7 +2380,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
RNA_PROPERTY_SET_SINGLE(boolean, ptr_dst, prop_dst, index, value);
break;
default:
- BLI_assert(0 && "Unsupported RNA override operation on boolean");
+ BLI_assert_msg(0, "Unsupported RNA override operation on boolean");
return false;
}
}
@@ -2421,7 +2421,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
}
break;
default:
- BLI_assert(0 && "Unsupported RNA override operation on integer");
+ BLI_assert_msg(0, "Unsupported RNA override operation on integer");
return false;
}
@@ -2459,7 +2459,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
storage_value);
break;
default:
- BLI_assert(0 && "Unsupported RNA override operation on integer");
+ BLI_assert_msg(0, "Unsupported RNA override operation on integer");
return false;
}
}
@@ -2506,7 +2506,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
}
break;
default:
- BLI_assert(0 && "Unsupported RNA override operation on float");
+ BLI_assert_msg(0, "Unsupported RNA override operation on float");
return false;
}
@@ -2552,7 +2552,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
storage_value);
break;
default:
- BLI_assert(0 && "Unsupported RNA override operation on float");
+ BLI_assert_msg(0, "Unsupported RNA override operation on float");
return false;
}
}
@@ -2566,7 +2566,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
break;
/* TODO: support add/sub, for bitflags? */
default:
- BLI_assert(0 && "Unsupported RNA override operation on enum");
+ BLI_assert_msg(0, "Unsupported RNA override operation on enum");
return false;
}
return true;
@@ -2579,7 +2579,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
RNA_property_pointer_set(ptr_dst, prop_dst, value, NULL);
break;
default:
- BLI_assert(0 && "Unsupported RNA override operation on pointer");
+ BLI_assert_msg(0, "Unsupported RNA override operation on pointer");
return false;
}
return true;
@@ -2593,7 +2593,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
RNA_property_string_set(ptr_dst, prop_dst, value);
break;
default:
- BLI_assert(0 && "Unsupported RNA override operation on string");
+ BLI_assert_msg(0, "Unsupported RNA override operation on string");
return false;
}
@@ -2609,7 +2609,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
const bool is_dst_idprop = (prop_dst->magic != RNA_MAGIC) ||
(prop_dst->flag & PROP_IDPROPERTY) != 0;
if (!(is_src_idprop && is_dst_idprop)) {
- BLI_assert(0 && "You need to define a specific override apply callback for collections");
+ BLI_assert_msg(0, "You need to define a specific override apply callback for collections");
return false;
}
@@ -2668,7 +2668,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
return RNA_property_collection_move(ptr_dst, prop_dst, item_index_added, item_index_dst);
}
default:
- BLI_assert(0 && "Unsupported RNA override operation on collection");
+ BLI_assert_msg(0, "Unsupported RNA override operation on collection");
return false;
}
}
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index b1f0b0d760f..9939e17d258 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -1921,16 +1921,6 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
- prop = RNA_def_property(srna, "speed_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "speed_fader");
- RNA_def_property_ui_text(
- prop,
- "Speed Factor",
- "Multiply the current speed of the sequence with this number or remap current frame "
- "to this frame");
- RNA_def_property_update(
- prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
-
/* modifiers */
prop = RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "SequenceModifier");
@@ -2787,24 +2777,48 @@ static void rna_def_speed_control(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "SpeedControlVars", "effectdata");
- prop = RNA_def_property(srna, "multiply_speed", PROP_FLOAT, PROP_UNSIGNED);
- RNA_def_property_float_sdna(prop, NULL, "globalSpeed");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* seq->facf0 is used to animate this */
- RNA_def_property_ui_text(
- prop, "Multiply Speed", "Multiply the resulting speed after the speed factor");
- RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, -1);
+ static const EnumPropertyItem speed_control_items[] = {
+ {SEQ_SPEED_STRETCH,
+ "STRETCH",
+ 0,
+ "Stretch",
+ "Adjust input playback speed, so its duration fits strip length"},
+ {SEQ_SPEED_MULTIPLY, "MULTIPLY", 0, "Multiply", "Multiply with the speed factor"},
+ {SEQ_SPEED_FRAME_NUMBER,
+ "FRAME_NUMBER",
+ 0,
+ "Frame Number",
+ "Frame number of the input strip"},
+ {SEQ_SPEED_LENGTH, "LENGTH", 0, "Length", "Percentage of the input strip length"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ prop = RNA_def_property(srna, "speed_control", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "speed_control_type");
+ RNA_def_property_enum_items(prop, speed_control_items);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Speed Control", "Speed control method");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
- prop = RNA_def_property(srna, "use_as_speed", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_INTEGRATE);
+ prop = RNA_def_property(srna, "speed_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "speed_fader");
RNA_def_property_ui_text(
- prop, "Use as Speed", "Interpret the value as speed instead of a frame number");
+ prop,
+ "Multiply Factor",
+ "Multiply the current speed of the sequence with this number or remap current frame "
+ "to this frame");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
- prop = RNA_def_property(srna, "use_scale_to_length", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_COMPRESS_IPO_Y);
- RNA_def_property_ui_text(
- prop, "Scale to Length", "Scale values from 0.0 to 1.0 to target sequence length");
+ prop = RNA_def_property(srna, "speed_frame_number", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "speed_fader_frame_number");
+ RNA_def_property_ui_text(prop, "Frame Number", "Frame number of input strip");
+ RNA_def_property_ui_range(prop, 0.0, MAXFRAME, 1.0, -1);
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
+
+ prop = RNA_def_property(srna, "speed_length", PROP_FLOAT, PROP_PERCENTAGE);
+ RNA_def_property_float_sdna(prop, NULL, "speed_fader_length");
+ RNA_def_property_ui_text(prop, "Length", "Percentage of input strip length");
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "use_frame_interpolate", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 8aab0c079a3..4895ab11618 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -30,6 +30,8 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "SEQ_edit.h"
+
#include "rna_internal.h"
#ifdef RNA_RUNTIME
@@ -99,6 +101,24 @@ static void rna_Sequences_move_strip_to_meta(
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
}
+static Sequence *rna_Sequence_split(
+ ID *id, Sequence *seq, Main *bmain, int frame, int split_method)
+{
+ Scene *scene = (Scene *)id;
+ Editing *ed = SEQ_editing_get(scene, false);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+
+ Sequence *r_seq = SEQ_edit_strip_split(bmain, scene, seqbase, seq, frame, split_method);
+
+ /* Update depsgraph. */
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
+
+ WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
+
+ return r_seq;
+}
+
static Sequence *rna_Sequences_new_clip(ID *id,
ListBase *seqbase,
Main *bmain,
@@ -635,6 +655,12 @@ void RNA_api_sequence_strip(StructRNA *srna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem seq_split_method_items[] = {
+ {SEQ_SPLIT_SOFT, "SOFT", 0, "Soft", ""},
+ {SEQ_SPLIT_HARD, "HARD", 0, "Hard", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
func = RNA_def_function(srna, "update", "rna_Sequence_update_rnafunc");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Update the strip dimensions");
@@ -676,6 +702,18 @@ void RNA_api_sequence_strip(StructRNA *srna)
"Invalidate cached images for strip and all dependent strips");
parm = RNA_def_enum(func, "type", seq_cahce_type_items, 0, "Type", "Cache Type");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "split", "rna_Sequence_split");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Split Sequence");
+ parm = RNA_def_int(
+ func, "frame", 0, INT_MIN, INT_MAX, "", "Frame where to split the strip", INT_MIN, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum(func, "split_method", seq_split_method_items, 0, "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ /* Return type. */
+ parm = RNA_def_pointer(func, "sequence", "Sequence", "", "Right side Sequence");
+ RNA_def_function_return(func, parm);
}
void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index f2d2b190d87..a213b418e0e 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -359,7 +359,7 @@ static const EnumPropertyItem display_channels_items[] = {
"Color and Alpha",
"Display image with RGB colors and alpha transparency"},
{0, "COLOR", ICON_IMAGE_RGB, "Color", "Display image with RGB colors"},
- {SI_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Display alpha transparency channel"},
+ {SI_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Display alpha transparency channel"},
{SI_SHOW_ZBUF,
"Z_BUFFER",
ICON_IMAGE_ZDEPTH,
@@ -536,6 +536,7 @@ static const EnumPropertyItem rna_enum_curve_display_handle_items[] = {
# include "DEG_depsgraph_build.h"
# include "ED_anim_api.h"
+# include "ED_asset.h"
# include "ED_buttons.h"
# include "ED_clip.h"
# include "ED_fileselect.h"
@@ -2562,112 +2563,19 @@ static PointerRNA rna_FileSelectParams_filter_id_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_FileSelectIDFilter, ptr->data);
}
-/* TODO use rna_def_asset_library_reference_common() */
-
static int rna_FileAssetSelectParams_asset_library_get(PointerRNA *ptr)
{
FileAssetSelectParams *params = ptr->data;
/* Just an extra sanity check to ensure this isn't somehow called for RNA_FileSelectParams. */
BLI_assert(ptr->type == &RNA_FileAssetSelectParams);
- /* Simple case: Predefined repo, just set the value. */
- if (params->asset_library.type < ASSET_LIBRARY_CUSTOM) {
- return params->asset_library.type;
- }
-
- /* Note that the path isn't checked for validity here. If an invalid library path is used, the
- * Asset Browser can give a nice hint on what's wrong. */
- const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
- &U, params->asset_library.custom_library_index);
- if (user_library) {
- return ASSET_LIBRARY_CUSTOM + params->asset_library.custom_library_index;
- }
-
- BLI_assert(0);
- return ASSET_LIBRARY_LOCAL;
+ return ED_asset_library_reference_to_enum_value(&params->asset_library);
}
static void rna_FileAssetSelectParams_asset_library_set(PointerRNA *ptr, int value)
{
FileAssetSelectParams *params = ptr->data;
-
- /* Simple case: Predefined repo, just set the value. */
- if (value < ASSET_LIBRARY_CUSTOM) {
- params->asset_library.type = value;
- params->asset_library.custom_library_index = -1;
- BLI_assert(ELEM(value, ASSET_LIBRARY_LOCAL));
- return;
- }
-
- const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
- &U, value - ASSET_LIBRARY_CUSTOM);
-
- /* Note that the path isn't checked for validity here. If an invalid library path is used, the
- * Asset Browser can give a nice hint on what's wrong. */
- const bool is_valid = (user_library->name[0] && user_library->path[0]);
- if (!user_library) {
- params->asset_library.type = ASSET_LIBRARY_LOCAL;
- params->asset_library.custom_library_index = -1;
- }
- else if (user_library && is_valid) {
- params->asset_library.custom_library_index = value - ASSET_LIBRARY_CUSTOM;
- params->asset_library.type = ASSET_LIBRARY_CUSTOM;
- }
-}
-
-static const EnumPropertyItem *rna_FileAssetSelectParams_asset_library_itemf(
- bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- const EnumPropertyItem predefined_items[] = {
- /* For the future. */
- // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
- {ASSET_LIBRARY_LOCAL,
- "LOCAL",
- ICON_BLENDER,
- "Current File",
- "Show the assets currently available in this Blender session"},
- {0, NULL, 0, NULL, NULL},
- };
-
- EnumPropertyItem *item = NULL;
- int totitem = 0;
-
- /* Add separator if needed. */
- if (!BLI_listbase_is_empty(&U.asset_libraries)) {
- const EnumPropertyItem sepr = {0, "", 0, "Custom", NULL};
- RNA_enum_item_add(&item, &totitem, &sepr);
- }
-
- int i = 0;
- for (bUserAssetLibrary *user_library = U.asset_libraries.first; user_library;
- user_library = user_library->next, i++) {
- /* Note that the path itself isn't checked for validity here. If an invalid library path is
- * used, the Asset Browser can give a nice hint on what's wrong. */
- const bool is_valid = (user_library->name[0] && user_library->path[0]);
- if (!is_valid) {
- continue;
- }
-
- /* Use library path as description, it's a nice hint for users. */
- EnumPropertyItem tmp = {ASSET_LIBRARY_CUSTOM + i,
- user_library->name,
- ICON_NONE,
- user_library->name,
- user_library->path};
- RNA_enum_item_add(&item, &totitem, &tmp);
- }
-
- if (totitem) {
- const EnumPropertyItem sepr = {0, "", 0, "Built-in", NULL};
- RNA_enum_item_add(&item, &totitem, &sepr);
- }
-
- /* Add predefined items. */
- RNA_enum_items_add(&item, &totitem, predefined_items);
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
- return item;
+ params->asset_library = ED_asset_library_reference_from_enum_value(value);
}
static void rna_FileAssetSelectParams_asset_category_set(PointerRNA *ptr, uint64_t value)
@@ -6559,12 +6467,9 @@ static void rna_def_fileselect_asset_params(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "Asset Select Parameters", "Settings for the file selection in Asset Browser mode");
- prop = RNA_def_property(srna, "asset_library", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, DummyRNA_NULL_items);
- RNA_def_property_enum_funcs(prop,
- "rna_FileAssetSelectParams_asset_library_get",
- "rna_FileAssetSelectParams_asset_library_set",
- "rna_FileAssetSelectParams_asset_library_itemf");
+ prop = rna_def_asset_library_reference_common(srna,
+ "rna_FileAssetSelectParams_asset_library_get",
+ "rna_FileAssetSelectParams_asset_library_set");
RNA_def_property_ui_text(prop, "Asset Library", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c
index 76db6f3e325..8ed53c9f70f 100644
--- a/source/blender/makesrna/intern/rna_volume.c
+++ b/source/blender/makesrna/intern/rna_volume.c
@@ -495,7 +495,7 @@ static void rna_def_volume_render(BlenderRNA *brna)
prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, space_items);
RNA_def_property_ui_text(
- prop, "Space", "Specify volume density and step size in object or world space");
+ prop, "Space", "Specify volume density and step size in object or world space");
RNA_def_property_update(prop, 0, "rna_Volume_update_display");
prop = RNA_def_property(srna, "step_size", PROP_FLOAT, PROP_DISTANCE);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 2a4abac04f8..9b4089b272c 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -1825,7 +1825,7 @@ static void rna_KeyMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
#else /* RNA_RUNTIME */
/**
- * expose ``Operator.options`` as its own type so we can control each flags use
+ * expose `Operator.options` as its own type so we can control each flags use
* (some are read-only).
*/
static void rna_def_operator_options_runtime(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c
index b053bb0ff62..95f62d7de16 100644
--- a/source/blender/makesrna/intern/rna_workspace.c
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -45,6 +45,8 @@
# include "DNA_screen_types.h"
# include "DNA_space_types.h"
+# include "ED_asset.h"
+
# include "RNA_access.h"
# include "WM_toolsystem.h"
@@ -107,16 +109,16 @@ static void rna_WorkSpace_owner_ids_clear(WorkSpace *workspace)
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, workspace);
}
-static int rna_WorkSpace_active_asset_library_get(PointerRNA *ptr)
+static int rna_WorkSpace_asset_library_get(PointerRNA *ptr)
{
const WorkSpace *workspace = ptr->data;
- return rna_asset_library_reference_get(&workspace->active_asset_library);
+ return ED_asset_library_reference_to_enum_value(&workspace->asset_library);
}
-static void rna_WorkSpace_active_asset_library_set(PointerRNA *ptr, int value)
+static void rna_WorkSpace_asset_library_set(PointerRNA *ptr, int value)
{
WorkSpace *workspace = ptr->data;
- rna_asset_library_reference_set(&workspace->active_asset_library, value);
+ workspace->asset_library = ED_asset_library_reference_from_enum_value(value);
}
static bToolRef *rna_WorkSpace_tools_from_tkey(WorkSpace *workspace,
@@ -420,7 +422,7 @@ static void rna_def_workspace(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_window_update_all");
prop = rna_def_asset_library_reference_common(
- srna, "rna_WorkSpace_active_asset_library_get", "rna_WorkSpace_active_asset_library_set");
+ srna, "rna_WorkSpace_asset_library_get", "rna_WorkSpace_asset_library_set");
RNA_def_property_ui_text(prop,
"Asset Library",
"Active asset library to show in the UI, not used by the Asset Browser "
diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index 04a8500d136..56e8418972c 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -34,6 +34,63 @@
# include "WM_api.h"
+# ifdef WITH_XR_OPENXR
+static wmXrData *rna_XrSession_wm_xr_data_get(PointerRNA *ptr)
+{
+ /* Callers could also get XrSessionState pointer through ptr->data, but prefer if we just
+ * consistently pass wmXrData pointers to the WM_xr_xxx() API. */
+
+ BLI_assert((ptr->type == &RNA_XrSessionSettings) || (ptr->type == &RNA_XrSessionState));
+
+ wmWindowManager *wm = (wmWindowManager *)ptr->owner_id;
+ BLI_assert(wm && (GS(wm->id.name) == ID_WM));
+
+ return &wm->xr;
+}
+# endif
+
+static bool rna_XrSessionSettings_use_positional_tracking_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ return (xr->session_settings.flag & XR_SESSION_USE_POSITION_TRACKING) != 0;
+# else
+ UNUSED_VARS(ptr);
+ return false;
+# endif
+}
+
+static void rna_XrSessionSettings_use_positional_tracking_set(PointerRNA *ptr, bool value)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ SET_FLAG_FROM_TEST(xr->session_settings.flag, value, XR_SESSION_USE_POSITION_TRACKING);
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
+static bool rna_XrSessionSettings_use_absolute_tracking_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ return (xr->session_settings.flag & XR_SESSION_USE_ABSOLUTE_TRACKING) != 0;
+# else
+ UNUSED_VARS(ptr);
+ return false;
+# endif
+}
+
+static void rna_XrSessionSettings_use_absolute_tracking_set(PointerRNA *ptr, bool value)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ SET_FLAG_FROM_TEST(xr->session_settings.flag, value, XR_SESSION_USE_ABSOLUTE_TRACKING);
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
static bool rna_XrSessionState_is_running(bContext *C)
{
# ifdef WITH_XR_OPENXR
@@ -55,25 +112,10 @@ static void rna_XrSessionState_reset_to_base_pose(bContext *C)
# endif
}
-# ifdef WITH_XR_OPENXR
-static wmXrData *rna_XrSessionState_wm_xr_data_get(PointerRNA *ptr)
-{
- /* Callers could also get XrSessionState pointer through ptr->data, but prefer if we just
- * consistently pass wmXrData pointers to the WM_xr_xxx() API. */
-
- BLI_assert(ptr->type == &RNA_XrSessionState);
-
- wmWindowManager *wm = (wmWindowManager *)ptr->owner_id;
- BLI_assert(wm && (GS(wm->id.name) == ID_WM));
-
- return &wm->xr;
-}
-# endif
-
static void rna_XrSessionState_viewer_pose_location_get(PointerRNA *ptr, float *r_values)
{
# ifdef WITH_XR_OPENXR
- const wmXrData *xr = rna_XrSessionState_wm_xr_data_get(ptr);
+ const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
WM_xr_session_state_viewer_pose_location_get(xr, r_values);
# else
UNUSED_VARS(ptr);
@@ -84,7 +126,7 @@ static void rna_XrSessionState_viewer_pose_location_get(PointerRNA *ptr, float *
static void rna_XrSessionState_viewer_pose_rotation_get(PointerRNA *ptr, float *r_values)
{
# ifdef WITH_XR_OPENXR
- const wmXrData *xr = rna_XrSessionState_wm_xr_data_get(ptr);
+ const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
WM_xr_session_state_viewer_pose_rotation_get(xr, r_values);
# else
UNUSED_VARS(ptr);
@@ -181,12 +223,22 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
prop = RNA_def_property(srna, "use_positional_tracking", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", XR_SESSION_USE_POSITION_TRACKING);
+ RNA_def_property_boolean_funcs(prop,
+ "rna_XrSessionSettings_use_positional_tracking_get",
+ "rna_XrSessionSettings_use_positional_tracking_set");
RNA_def_property_ui_text(
prop,
"Positional Tracking",
"Allow VR headsets to affect the location in virtual space, in addition to the rotation");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+
+ prop = RNA_def_property(srna, "use_absolute_tracking", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop,
+ "rna_XrSessionSettings_use_absolute_tracking_get",
+ "rna_XrSessionSettings_use_absolute_tracking_set");
+ RNA_def_property_ui_text(
+ prop, "Absolute Tracking", "Use unadjusted location/rotation as defined by the XR runtime");
+ RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
}
static void rna_def_xr_session_state(BlenderRNA *brna)
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 722614c4831..6a9c9715994 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -194,8 +194,8 @@ static void dm_mvert_map_doubles(int *doubles_map,
i_target_low_bound = 0;
target_scan_completed = false;
- /* Scan source vertices, in SortVertsElem sorted array, */
- /* all the while maintaining the lower bound of possible doubles in target vertices */
+ /* Scan source vertices, in #SortVertsElem sorted array,
+ * all the while maintaining the lower bound of possible doubles in target vertices. */
for (i_source = 0, sve_source = sorted_verts_source; i_source < source_num_verts;
i_source++, sve_source++) {
int best_target_vertex = -1;
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 87fce26c45e..5fa11ffdd10 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 by the Blender Foundation.
@@ -1133,6 +1133,18 @@ static void panel_draw(const bContext *C, Panel *panel)
}
}
+ /* Draw node warnings. */
+ if (nmd->runtime_eval_log != nullptr) {
+ const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log);
+ log.foreach_node_log([layout](const geo_log::NodeLog &node_log) {
+ for (const geo_log::NodeWarning &warning : node_log.warnings()) {
+ if (warning.type != geo_log::NodeWarningType::Info) {
+ uiItemL(layout, warning.message.c_str(), ICON_ERROR);
+ }
+ }
+ });
+ }
+
modifier_panel_end(layout, ptr);
}
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 54bb68dc21a..e7750f0a0d1 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -257,10 +257,10 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
generate_vert_coordinates(mesh, ob, ob_target, enmd->offset, num_verts, cos, size);
/**
- * size gives us our spheroid coefficients ``(A, B, C)``.
+ * size gives us our spheroid coefficients `(A, B, C)`.
* Then, we want to find out for each vert its (a, b, c) triple (proportional to (A, B, C) one).
*
- * Ellipsoid basic equation: ``(x^2/a^2) + (y^2/b^2) + (z^2/c^2) = 1.``
+ * Ellipsoid basic equation: `(x^2/a^2) + (y^2/b^2) + (z^2/c^2) = 1`.
* Since we want to find (a, b, c) matching this equation and proportional to (A, B, C),
* we can do:
* <pre>
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index ef70f3fe6f4..71fc7f3e424 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -282,13 +282,13 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
if (ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB)) {
uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Instances Real"),
ICON_NONE,
"OBJECT_OT_duplicates_make_real");
}
else if (psys->part->ren_as == PART_DRAW_PATH) {
uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert to Mesh"),
ICON_NONE,
"OBJECT_OT_modifier_convert");
}
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index dd011a293ee..ec6de8f8387 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -94,6 +94,11 @@ typedef struct SDefBindCalcData {
float imat[4][4];
const float falloff;
int success;
+ /** Vertex group lookup data. */
+ const MDeformVert *const dvert;
+ int const defgrp_index;
+ bool const invert_vgroup;
+ bool const sparse_bind;
} SDefBindCalcData;
/**
@@ -218,7 +223,7 @@ static void freeData(ModifierData *md)
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
if (smd->verts) {
- for (int i = 0; i < smd->numverts; i++) {
+ for (int i = 0; i < smd->num_bind_verts; i++) {
if (smd->verts[i].binds) {
for (int j = 0; j < smd->verts[i].numbinds; j++) {
MEM_SAFE_FREE(smd->verts[i].binds[j].vert_inds);
@@ -243,7 +248,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
if (smd->verts) {
tsmd->verts = MEM_dupallocN(smd->verts);
- for (int i = 0; i < smd->numverts; i++) {
+ for (int i = 0; i < smd->num_bind_verts; i++) {
if (smd->verts[i].binds) {
tsmd->verts[i].binds = MEM_dupallocN(smd->verts[i].binds);
@@ -963,12 +968,32 @@ static void bindVert(void *__restrict userdata,
SDefBindPoly *bpoly;
SDefBind *sdbind;
+ sdvert->vertex_idx = index;
+
if (data->success != MOD_SDEF_BIND_RESULT_SUCCESS) {
sdvert->binds = NULL;
sdvert->numbinds = 0;
return;
}
+ if (data->sparse_bind) {
+ float weight = 0.0f;
+
+ if (data->dvert && data->defgrp_index != -1) {
+ weight = BKE_defvert_find_weight(&data->dvert[index], data->defgrp_index);
+ }
+
+ if (data->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight <= 0) {
+ sdvert->binds = NULL;
+ sdvert->numbinds = 0;
+ return;
+ }
+ }
+
copy_v3_v3(point_co, data->vertexCos[index]);
bwdata = computeBindWeights(data, point_co);
@@ -1135,6 +1160,21 @@ static void bindVert(void *__restrict userdata,
freeBindData(bwdata);
}
+/* Remove vertices without bind data from the bind array. */
+static void compactSparseBinds(SurfaceDeformModifierData *smd)
+{
+ smd->num_bind_verts = 0;
+
+ for (uint i = 0; i < smd->num_mesh_verts; i++) {
+ if (smd->verts[i].numbinds > 0) {
+ smd->verts[smd->num_bind_verts++] = smd->verts[i];
+ }
+ }
+
+ smd->verts = MEM_reallocN_id(
+ smd->verts, sizeof(*smd->verts) * smd->num_bind_verts, "SDefBindVerts (sparse)");
+}
+
static bool surfacedeformBind(Object *ob,
SurfaceDeformModifierData *smd_orig,
SurfaceDeformModifierData *smd_eval,
@@ -1142,7 +1182,8 @@ static bool surfacedeformBind(Object *ob,
uint numverts,
uint tnumpoly,
uint tnumverts,
- Mesh *target)
+ Mesh *target,
+ Mesh *mesh)
{
BVHTreeFromMesh treeData = {NULL};
const MVert *mvert = target->mvert;
@@ -1205,9 +1246,15 @@ static bool surfacedeformBind(Object *ob,
return false;
}
- smd_orig->numverts = numverts;
+ smd_orig->num_mesh_verts = numverts;
smd_orig->numpoly = tnumpoly;
+ int defgrp_index;
+ MDeformVert *dvert;
+ MOD_get_vgroup(ob, mesh, smd_orig->defgrp_name, &dvert, &defgrp_index);
+ const bool invert_vgroup = (smd_orig->flags & MOD_SDEF_INVERT_VGROUP) != 0;
+ const bool sparse_bind = (smd_orig->flags & MOD_SDEF_SPARSE_BIND) != 0;
+
SDefBindCalcData data = {
.treeData = &treeData,
.vert_edges = vert_edges,
@@ -1221,6 +1268,10 @@ static bool surfacedeformBind(Object *ob,
.vertexCos = vertexCos,
.falloff = smd_orig->falloff,
.success = MOD_SDEF_BIND_RESULT_SUCCESS,
+ .dvert = dvert,
+ .defgrp_index = defgrp_index,
+ .invert_vgroup = invert_vgroup,
+ .sparse_bind = sparse_bind,
};
if (data.targetCos == NULL) {
@@ -1242,6 +1293,13 @@ static bool surfacedeformBind(Object *ob,
MEM_freeN(data.targetCos);
+ if (sparse_bind) {
+ compactSparseBinds(smd_orig);
+ }
+ else {
+ smd_orig->num_bind_verts = numverts;
+ }
+
if (data.success == MOD_SDEF_BIND_RESULT_MEM_ERR) {
BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
freeData((ModifierData *)smd_orig);
@@ -1267,6 +1325,11 @@ static bool surfacedeformBind(Object *ob,
BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Target contains invalid polygons");
freeData((ModifierData *)smd_orig);
}
+ else if (smd_orig->num_bind_verts == 0 || !smd_orig->verts) {
+ data.success = MOD_SDEF_BIND_RESULT_GENERIC_ERR;
+ BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "No vertices were bound");
+ freeData((ModifierData *)smd_orig);
+ }
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
free_bvhtree_from_mesh(&treeData);
@@ -1281,14 +1344,15 @@ static void deformVert(void *__restrict userdata,
const SDefDeformData *const data = (SDefDeformData *)userdata;
const SDefBind *sdbind = data->bind_verts[index].binds;
const int num_binds = data->bind_verts[index].numbinds;
- float *const vertexCos = data->vertexCos[index];
+ const unsigned int vertex_idx = data->bind_verts[index].vertex_idx;
+ float *const vertexCos = data->vertexCos[vertex_idx];
float norm[3], temp[3], offset[3];
/* Retrieve the value of the weight vertex group if specified. */
float weight = 1.0f;
if (data->dvert && data->defgrp_index != -1) {
- weight = BKE_defvert_find_weight(&data->dvert[index], data->defgrp_index);
+ weight = BKE_defvert_find_weight(&data->dvert[vertex_idx], data->defgrp_index);
if (data->invert_vgroup) {
weight = 1.0f - weight;
@@ -1423,7 +1487,8 @@ static void surfacedeformModifier_do(ModifierData *md,
/* Avoid converting edit-mesh data, binding is an exception. */
BKE_mesh_wrapper_ensure_mdata(target);
- if (!surfacedeformBind(ob, smd_orig, smd, vertexCos, numverts, tnumpoly, tnumverts, target)) {
+ if (!surfacedeformBind(
+ ob, smd_orig, smd, vertexCos, numverts, tnumpoly, tnumverts, target, mesh)) {
smd->flags &= ~MOD_SDEF_BIND;
}
/* Early abort, this is binding 'call', no need to perform whole evaluation. */
@@ -1431,8 +1496,9 @@ static void surfacedeformModifier_do(ModifierData *md,
}
/* Poly count checks */
- if (smd->numverts != numverts) {
- BKE_modifier_set_error(ob, md, "Vertices changed from %u to %u", smd->numverts, numverts);
+ if (smd->num_mesh_verts != numverts) {
+ BKE_modifier_set_error(
+ ob, md, "Vertices changed from %u to %u", smd->num_mesh_verts, numverts);
return;
}
if (smd->numpoly != tnumpoly) {
@@ -1468,8 +1534,8 @@ static void surfacedeformModifier_do(ModifierData *md,
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (numverts > 10000);
- BLI_task_parallel_range(0, numverts, &data, deformVert, &settings);
+ settings.use_threading = (smd->num_bind_verts > 10000);
+ BLI_task_parallel_range(0, smd->num_bind_verts, &data, deformVert, &settings);
MEM_freeN(data.targetCos);
}
@@ -1554,6 +1620,11 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
+ col = uiLayoutColumn(layout, false);
+ uiLayoutSetEnabled(col, !is_bound);
+ uiLayoutSetActive(col, !is_bound && RNA_string_length(ptr, "vertex_group") != 0);
+ uiItemR(col, ptr, "use_sparse_bind", 0, NULL, ICON_NONE);
+
uiItemS(layout);
col = uiLayoutColumn(layout, false);
@@ -1576,10 +1647,10 @@ static void blendWrite(BlendWriter *writer, const ModifierData *md)
{
const SurfaceDeformModifierData *smd = (const SurfaceDeformModifierData *)md;
- BLO_write_struct_array(writer, SDefVert, smd->numverts, smd->verts);
+ BLO_write_struct_array(writer, SDefVert, smd->num_bind_verts, smd->verts);
if (smd->verts) {
- for (int i = 0; i < smd->numverts; i++) {
+ for (int i = 0; i < smd->num_bind_verts; i++) {
BLO_write_struct_array(writer, SDefBind, smd->verts[i].numbinds, smd->verts[i].binds);
if (smd->verts[i].binds) {
@@ -1607,7 +1678,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
BLO_read_data_address(reader, &smd->verts);
if (smd->verts) {
- for (int i = 0; i < smd->numverts; i++) {
+ for (int i = 0; i < smd->num_bind_verts; i++) {
BLO_read_data_address(reader, &smd->verts[i].binds);
if (smd->verts[i].binds) {
diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c
index 9245afdb096..6239ee45e59 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.c
+++ b/source/blender/modifiers/intern/MOD_ui_common.c
@@ -9,7 +9,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c
index bbdd7d0e647..3b147c69716 100644
--- a/source/blender/modifiers/intern/MOD_weighted_normal.c
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.c
@@ -623,7 +623,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
CustomData *ldata = &result->ldata;
clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
- /* Keep info whether we had clnors,
+ /* Keep info whether we had clnors,
* it helps when generating clnor spaces and default normals. */
const bool has_clnors = clnors != NULL;
if (!clnors) {
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index 696c4c855c7..e403051d1be 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -167,9 +167,9 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
const int numVerts = mesh->totvert;
/* Use new generic get_texture_coords, but do not modify our DNA struct for it...
- * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ?
- * What e.g. if a modifier wants to use several textures ?
- * Why use only v_co, and not MVert (or both) ?
+ * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters?
+ * What e.g. if a modifier wants to use several textures?
+ * Why use only v_co, and not MVert (or both)?
*/
t_map.texture = texture;
t_map.map_object = tex_map_object;
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
index fe2d699aea8..b1fa2a7d912 100644
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ b/source/blender/modifiers/intern/MOD_weld.c
@@ -1735,6 +1735,9 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
uint v1 = me->v1;
uint v2 = me->v2;
+ if (wmd->flag & MOD_WELD_LOOSE_EDGES && (me->flag & ME_LOOSEEDGE) == 0) {
+ continue;
+ }
while (v1 != vert_dest_map[v1]) {
v1 = vert_dest_map[v1];
}
@@ -2019,11 +2022,15 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+ int weld_mode = RNA_enum_get(ptr, "mode");
uiLayoutSetPropSep(layout, true);
uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE);
+ if (weld_mode == MOD_WELD_MODE_CONNECTED) {
+ uiItemR(layout, ptr, "loose_edges", 0, NULL, ICON_NONE);
+ }
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
modifier_panel_end(layout, ptr);
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index dc19508be04..36e5be6a292 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -175,9 +175,11 @@ set(SRC
geometry/nodes/node_geo_curve_primitive_star.cc
geometry/nodes/node_geo_curve_resample.cc
geometry/nodes/node_geo_curve_reverse.cc
+ geometry/nodes/node_geo_curve_set_handles.cc
geometry/nodes/node_geo_curve_subdivide.cc
geometry/nodes/node_geo_curve_to_mesh.cc
geometry/nodes/node_geo_curve_to_points.cc
+ geometry/nodes/node_geo_curve_trim.cc
geometry/nodes/node_geo_delete_geometry.cc
geometry/nodes/node_geo_edge_split.cc
geometry/nodes/node_geo_input_material.cc
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index ad3a838f4c0..868fcbb33af 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -62,9 +62,11 @@ void register_node_type_geo_curve_primitive_spiral(void);
void register_node_type_geo_curve_primitive_star(void);
void register_node_type_geo_curve_resample(void);
void register_node_type_geo_curve_reverse(void);
+void register_node_type_geo_curve_set_handles(void);
void register_node_type_geo_curve_subdivide(void);
void register_node_type_geo_curve_to_mesh(void);
void register_node_type_geo_curve_to_points(void);
+void register_node_type_geo_curve_trim(void);
void register_node_type_geo_delete_geometry(void);
void register_node_type_geo_edge_split(void);
void register_node_type_geo_input_material(void);
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index b85862a0176..00d97b24646 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -31,6 +31,7 @@
*/
#include "BLI_enumerable_thread_specific.hh"
+#include "BLI_function_ref.hh"
#include "BLI_linear_allocator.hh"
#include "BLI_map.hh"
@@ -267,6 +268,7 @@ class TreeLog {
const NodeLog *lookup_node_log(StringRef node_name) const;
const NodeLog *lookup_node_log(const bNode &node) const;
const TreeLog *lookup_child_log(StringRef node_name) const;
+ void foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const;
};
/** Contains information about an entire geometry nodes evaluation. */
@@ -296,6 +298,7 @@ class ModifierLog {
const bNodeSocket &socket);
static const NodeLog *find_node_by_spreadsheet_editor_context(
const SpaceSpreadsheet &sspreadsheet);
+ void foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const;
private:
using LogByTreeContext = Map<const DTreeContext *, TreeLog *>;
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 73d4a002991..1298acf475d 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -156,7 +156,7 @@ DefNode(CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SA
DefNode(CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" )
DefNode(CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" )
DefNode(CompositorNode, CMP_NODE_COMPOSITE, def_cmp_composite, "COMPOSITE", Composite, "Composite", "" )
-/* NB: OutputFile node has special rna setup function called in rna_nodetree.c */
+/* NOTE: #OutputFile node has special RNA setup function called in rna_nodetree.c */
DefNode(CompositorNode, CMP_NODE_OUTPUT_FILE, 0, "OUTPUT_FILE", OutputFile, "File Output", "" )
DefNode(CompositorNode, CMP_NODE_TEXTURE, def_texture, "TEXTURE", Texture, "Texture", "" )
DefNode(CompositorNode, CMP_NODE_TRANSLATE, def_cmp_translate, "TRANSLATE", Translate, "Translate", "" )
@@ -300,8 +300,10 @@ DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, 0, "CURVE_PRIMI
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "")
DefNode(GeometryNode, GEO_NODE_CURVE_RESAMPLE, def_geo_curve_resample, "CURVE_RESAMPLE", CurveResample, "Resample Curve", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SET_HANDLES, def_geo_curve_set_handles, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "")
DefNode(GeometryNode, GEO_NODE_CURVE_SUBDIVIDE, def_geo_curve_subdivide, "CURVE_SUBDIVIDE", CurveSubdivide, "Curve Subdivide", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_TRIM, def_geo_curve_trim, "CURVE_TRIM", CurveTrim, "Curve Trim", "")
DefNode(GeometryNode, GEO_NODE_CURVE_REVERSE, 0, "CURVE_REVERSE", CurveReverse, "Curve Reverse", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINTS, 0, "CURVE_ENDPOINTS", CurveEndpoints, "Curve Endpoints", "")
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c
index 013d196e1c8..d21e0938356 100644
--- a/source/blender/nodes/composite/node_composite_tree.c
+++ b/source/blender/nodes/composite/node_composite_tree.c
@@ -264,14 +264,15 @@ void ntreeCompositExecTree(Scene *scene,
/* *********************************************** */
-/* Update the outputs of the render layer nodes.
+/**
+ * Update the outputs of the render layer nodes.
* Since the outputs depend on the render engine, this part is a bit complex:
- * - ntreeCompositUpdateRLayers is called and loops over all render layer nodes.
+ * - #ntreeCompositUpdateRLayers is called and loops over all render layer nodes.
* - Each render layer node calls the update function of the
* render engine that's used for its scene.
* - The render engine calls RE_engine_register_pass for each pass.
- * - RE_engine_register_pass calls ntreeCompositRegisterPass,.
- * which calls node_cmp_rlayers_register_pass for every render layer node.
+ * - #RE_engine_register_pass calls #ntreeCompositRegisterPass,
+ * which calls #node_cmp_rlayers_register_pass for every render layer node.
*/
void ntreeCompositUpdateRLayers(bNodeTree *ntree)
{
diff --git a/source/blender/nodes/composite/nodes/node_composite_common.c b/source/blender/nodes/composite/nodes/node_composite_common.c
index f5eaaef8a31..61abc80fe93 100644
--- a/source/blender/nodes/composite/nodes/node_composite_common.c
+++ b/source/blender/nodes/composite/nodes/node_composite_common.c
@@ -36,9 +36,8 @@ void register_node_type_cmp_group(void)
{
static bNodeType ntype;
- /* NB: cannot use sh_node_type_base for node group, because it would map the node type
- * to the shared NODE_GROUP integer type id.
- */
+ /* NOTE: Cannot use sh_node_type_base for node group, because it would map the node type
+ * to the shared NODE_GROUP integer type id. */
node_type_base_custom(
&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
ntype.type = NODE_GROUP;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc
index 756f93f154f..6a23443d3ab 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc
@@ -370,10 +370,12 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry,
break;
}
case ATTR_DOMAIN_CORNER: {
- use_mesh = true;
- mesh_indices.reinitialize(tot_samples);
- mesh_distances_sq.reinitialize(tot_samples);
- get_closest_mesh_corners(*mesh, dst_positions, mesh_indices, mesh_distances_sq, {});
+ if (mesh->totloop > 0) {
+ use_mesh = true;
+ mesh_indices.reinitialize(tot_samples);
+ mesh_distances_sq.reinitialize(tot_samples);
+ get_closest_mesh_corners(*mesh, dst_positions, mesh_indices, mesh_distances_sq, {});
+ }
break;
}
default: {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
index e167219ea6b..78b5b109419 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
@@ -74,7 +74,7 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve(
if (mode == GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION) {
spline->add_point(start,
BezierSpline::HandleType::Align,
- start - (start_handle_right - start) * -1.0f,
+ 2.0f * start - start_handle_right,
BezierSpline::HandleType::Align,
start_handle_right,
1.0f,
@@ -83,7 +83,7 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve(
BezierSpline::HandleType::Align,
end_handle_left,
BezierSpline::HandleType::Align,
- end - (end_handle_left - end) * -1.0f,
+ 2.0f * end - end_handle_left,
1.0f,
0.0f);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
new file mode 100644
index 00000000000..72bd8ab188d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
@@ -0,0 +1,149 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_curve_set_handles_in[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {SOCK_STRING, N_("Selection")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_curve_set_handles_out[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {-1, ""},
+};
+
+static void geo_node_curve_set_handles_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
+}
+
+namespace blender::nodes {
+
+static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
+ sizeof(NodeGeometryCurveSetHandles), __func__);
+
+ data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
+ data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
+ node->storage = data;
+}
+
+static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHandleType type)
+{
+ switch (type) {
+ case GEO_NODE_CURVE_HANDLE_AUTO:
+ return BezierSpline::HandleType::Auto;
+ case GEO_NODE_CURVE_HANDLE_ALIGN:
+ return BezierSpline::HandleType::Align;
+ case GEO_NODE_CURVE_HANDLE_FREE:
+ return BezierSpline::HandleType::Free;
+ case GEO_NODE_CURVE_HANDLE_VECTOR:
+ return BezierSpline::HandleType::Vector;
+ }
+ BLI_assert_unreachable();
+ return BezierSpline::HandleType::Auto;
+}
+
+static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurveSetHandles *node_storage =
+ (NodeGeometryCurveSetHandles *)params.node().storage;
+ const GeometryNodeCurveHandleType type = (GeometryNodeCurveHandleType)node_storage->handle_type;
+ const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode;
+
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ if (!geometry_set.has_curve()) {
+ params.set_output("Curve", geometry_set);
+ return;
+ }
+
+ /* Retrieve data for write access so we can avoid new allocations for the handles data. */
+ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
+ CurveEval &curve = *curve_component.get_for_write();
+ MutableSpan<SplinePtr> splines = curve.splines();
+
+ const std::string selection_name = params.extract_input<std::string>("Selection");
+ GVArray_Typed<bool> selection = curve_component.attribute_get_for_read(
+ selection_name, ATTR_DOMAIN_POINT, true);
+
+ const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type);
+ int point_index = 0;
+ bool has_bezier_spline = false;
+ for (SplinePtr &spline : splines) {
+ if (spline->type() != Spline::Type::Bezier) {
+ point_index += spline->positions().size();
+ continue;
+ }
+
+ BezierSpline &bezier_spline = static_cast<BezierSpline &>(*spline);
+ if (ELEM(new_handle_type, BezierSpline::HandleType::Free, BezierSpline::HandleType::Align)) {
+ /* In this case the automatically calculated handle types need to be "baked", because
+ * they're possibly changing from a type that is calculated automatically to a type that
+ * is positioned manually. */
+ bezier_spline.ensure_auto_handles();
+ }
+ has_bezier_spline = true;
+ for (int i_point : IndexRange(bezier_spline.size())) {
+ if (selection[point_index]) {
+ if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
+ bezier_spline.handle_types_left()[i_point] = new_handle_type;
+ }
+ if (mode & GEO_NODE_CURVE_HANDLE_RIGHT) {
+ bezier_spline.handle_types_right()[i_point] = new_handle_type;
+ }
+ }
+ point_index++;
+ }
+ bezier_spline.mark_cache_invalid();
+ }
+
+ if (!has_bezier_spline) {
+ params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve"));
+ }
+
+ params.set_output("Curve", geometry_set);
+}
+} // namespace blender::nodes
+
+void register_node_type_geo_curve_set_handles()
+{
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_curve_set_handles_in, geo_node_curve_set_handles_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec;
+ node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init);
+ node_type_storage(&ntype,
+ "NodeGeometryCurveSetHandles",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ ntype.draw_buttons = geo_node_curve_set_handles_layout;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index f1bcb4ed47f..ae5ad4e350b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -47,27 +47,27 @@ static void vert_extrude_to_mesh_data(const Spline &spline,
const float3 profile_vert,
MutableSpan<MVert> r_verts,
MutableSpan<MEdge> r_edges,
- int vert_offset,
- int edge_offset)
+ const int vert_offset,
+ const int edge_offset)
{
Span<float3> positions = spline.evaluated_positions();
for (const int i : IndexRange(positions.size() - 1)) {
- MEdge &edge = r_edges[edge_offset++];
+ MEdge &edge = r_edges[edge_offset + i];
edge.v1 = vert_offset + i;
edge.v2 = vert_offset + i + 1;
edge.flag = ME_LOOSEEDGE;
}
if (spline.is_cyclic() && spline.evaluated_edges_size() > 1) {
- MEdge &edge = r_edges[edge_offset++];
+ MEdge &edge = r_edges[edge_offset + spline.evaluated_edges_size() - 1];
edge.v1 = vert_offset;
edge.v2 = vert_offset + positions.size() - 1;
edge.flag = ME_LOOSEEDGE;
}
for (const int i : positions.index_range()) {
- MVert &vert = r_verts[vert_offset++];
+ MVert &vert = r_verts[vert_offset + i];
copy_v3_v3(vert.co, positions[i] + profile_vert);
}
}
@@ -81,14 +81,14 @@ static void mark_edges_sharp(MutableSpan<MEdge> edges)
static void spline_extrude_to_mesh_data(const Spline &spline,
const Spline &profile_spline,
+ const int vert_offset,
+ const int edge_offset,
+ const int loop_offset,
+ const int poly_offset,
MutableSpan<MVert> r_verts,
MutableSpan<MEdge> r_edges,
MutableSpan<MLoop> r_loops,
- MutableSpan<MPoly> r_polys,
- int vert_offset,
- int edge_offset,
- int loop_offset,
- int poly_offset)
+ MutableSpan<MPoly> r_polys)
{
const int spline_vert_len = spline.evaluated_points_size();
const int spline_edge_len = spline.evaluated_edges_size();
@@ -111,13 +111,14 @@ static void spline_extrude_to_mesh_data(const Spline &spline,
/* Add the edges running along the length of the curve, starting at each profile vertex. */
const int spline_edges_start = edge_offset;
for (const int i_profile : IndexRange(profile_vert_len)) {
+ const int profile_edge_offset = spline_edges_start + i_profile * spline_edge_len;
for (const int i_ring : IndexRange(spline_edge_len)) {
const int i_next_ring = (i_ring == spline_vert_len - 1) ? 0 : i_ring + 1;
const int ring_vert_offset = vert_offset + profile_vert_len * i_ring;
const int next_ring_vert_offset = vert_offset + profile_vert_len * i_next_ring;
- MEdge &edge = r_edges[edge_offset++];
+ MEdge &edge = r_edges[profile_edge_offset + i_ring];
edge.v1 = ring_vert_offset + i_profile;
edge.v2 = next_ring_vert_offset + i_profile;
edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
@@ -125,14 +126,15 @@ static void spline_extrude_to_mesh_data(const Spline &spline,
}
/* Add the edges running along each profile ring. */
- const int profile_edges_start = edge_offset;
+ const int profile_edges_start = spline_edges_start + profile_vert_len * spline_edge_len;
for (const int i_ring : IndexRange(spline_vert_len)) {
const int ring_vert_offset = vert_offset + profile_vert_len * i_ring;
+ const int ring_edge_offset = profile_edges_start + i_ring * profile_edge_len;
for (const int i_profile : IndexRange(profile_edge_len)) {
const int i_next_profile = (i_profile == profile_vert_len - 1) ? 0 : i_profile + 1;
- MEdge &edge = r_edges[edge_offset++];
+ MEdge &edge = r_edges[ring_edge_offset + i_profile];
edge.v1 = ring_vert_offset + i_profile;
edge.v2 = ring_vert_offset + i_next_profile;
edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
@@ -149,29 +151,33 @@ static void spline_extrude_to_mesh_data(const Spline &spline,
const int ring_edge_start = profile_edges_start + profile_edge_len * i_ring;
const int next_ring_edge_offset = profile_edges_start + profile_edge_len * i_next_ring;
+ const int ring_poly_offset = poly_offset + i_ring * profile_edge_len;
+ const int ring_loop_offset = loop_offset + i_ring * profile_edge_len * 4;
+
for (const int i_profile : IndexRange(profile_edge_len)) {
+ const int ring_segment_loop_offset = ring_loop_offset + i_profile * 4;
const int i_next_profile = (i_profile == profile_vert_len - 1) ? 0 : i_profile + 1;
const int spline_edge_start = spline_edges_start + spline_edge_len * i_profile;
const int next_spline_edge_start = spline_edges_start + spline_edge_len * i_next_profile;
- MPoly &poly = r_polys[poly_offset++];
- poly.loopstart = loop_offset;
+ MPoly &poly = r_polys[ring_poly_offset + i_profile];
+ poly.loopstart = ring_segment_loop_offset;
poly.totloop = 4;
poly.flag = ME_SMOOTH;
- MLoop &loop_a = r_loops[loop_offset++];
+ MLoop &loop_a = r_loops[ring_segment_loop_offset];
loop_a.v = ring_vert_offset + i_profile;
- loop_a.e = ring_edge_start + i_profile;
- MLoop &loop_b = r_loops[loop_offset++];
- loop_b.v = ring_vert_offset + i_next_profile;
- loop_b.e = next_spline_edge_start + i_ring;
- MLoop &loop_c = r_loops[loop_offset++];
+ loop_a.e = spline_edge_start + i_ring;
+ MLoop &loop_b = r_loops[ring_segment_loop_offset + 1];
+ loop_b.v = next_ring_vert_offset + i_profile;
+ loop_b.e = next_ring_edge_offset + i_profile;
+ MLoop &loop_c = r_loops[ring_segment_loop_offset + 2];
loop_c.v = next_ring_vert_offset + i_next_profile;
- loop_c.e = next_ring_edge_offset + i_profile;
- MLoop &loop_d = r_loops[loop_offset++];
- loop_d.v = next_ring_vert_offset + i_profile;
- loop_d.e = spline_edge_start + i_ring;
+ loop_c.e = next_spline_edge_start + i_ring;
+ MLoop &loop_d = r_loops[ring_segment_loop_offset + 3];
+ loop_d.v = ring_vert_offset + i_next_profile;
+ loop_d.e = ring_edge_start + i_profile;
}
}
@@ -185,11 +191,11 @@ static void spline_extrude_to_mesh_data(const Spline &spline,
for (const int i_ring : IndexRange(spline_vert_len)) {
float4x4 point_matrix = float4x4::from_normalized_axis_data(
positions[i_ring], normals[i_ring], tangents[i_ring]);
-
point_matrix.apply_scale(radii[i_ring]);
+ const int ring_vert_start = vert_offset + i_ring * profile_vert_len;
for (const int i_profile : IndexRange(profile_vert_len)) {
- MVert &vert = r_verts[vert_offset++];
+ MVert &vert = r_verts[ring_vert_start + i_profile];
copy_v3_v3(vert.co, point_matrix * profile_positions[i_profile]);
}
}
@@ -275,7 +281,7 @@ static ResultOffsets calculate_result_offsets(Span<SplinePtr> profiles, Span<Spl
* Although it would be a sensible decision to use the better topology information available while
* generating the mesh to also generate the normals, that work may wasted if the output mesh is
* changed anyway in a way that affects the normals. So currently this code uses the safer /
- * simpler solution of not calculating normals.
+ * simpler solution of deferring normal calculation to the rest of Blender.
*/
static Mesh *curve_to_mesh_calculate(const CurveEval &curve, const CurveEval &profile)
{
@@ -303,14 +309,14 @@ static Mesh *curve_to_mesh_calculate(const CurveEval &curve, const CurveEval &pr
const int i_mesh = spline_start_index + i_profile;
spline_extrude_to_mesh_data(*curves[i_spline],
*profiles[i_profile],
- {mesh->mvert, mesh->totvert},
- {mesh->medge, mesh->totedge},
- {mesh->mloop, mesh->totloop},
- {mesh->mpoly, mesh->totpoly},
offsets.vert[i_mesh],
offsets.edge[i_mesh],
offsets.loop[i_mesh],
- offsets.poly[i_mesh]);
+ offsets.poly[i_mesh],
+ {mesh->mvert, mesh->totvert},
+ {mesh->medge, mesh->totedge},
+ {mesh->mloop, mesh->totloop},
+ {mesh->mpoly, mesh->totpoly});
}
});
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
new file mode 100644
index 00000000000..f9415c6d27b
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -0,0 +1,410 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_spline.hh"
+#include "BLI_task.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+using blender::attribute_math::mix2;
+
+static bNodeSocketTemplate geo_node_curve_trim_in[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {SOCK_FLOAT, N_("Start"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_FLOAT, N_("End"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_FLOAT, N_("Start"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10000.0f, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("End"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_DISTANCE},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_curve_trim_out[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {-1, ""},
+};
+
+static void geo_node_curve_trim_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+}
+
+static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim),
+ __func__);
+
+ data->mode = GEO_NODE_CURVE_INTERPOLATE_FACTOR;
+ node->storage = data;
+}
+
+static void geo_node_curve_trim_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)node->storage;
+ const GeometryNodeCurveInterpolateMode mode = (GeometryNodeCurveInterpolateMode)
+ node_storage.mode;
+
+ bNodeSocket *start_fac = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *end_fac = start_fac->next;
+ bNodeSocket *start_len = end_fac->next;
+ bNodeSocket *end_len = start_len->next;
+
+ nodeSetSocketAvailability(start_fac, mode == GEO_NODE_CURVE_INTERPOLATE_FACTOR);
+ nodeSetSocketAvailability(end_fac, mode == GEO_NODE_CURVE_INTERPOLATE_FACTOR);
+ nodeSetSocketAvailability(start_len, mode == GEO_NODE_CURVE_INTERPOLATE_LENGTH);
+ nodeSetSocketAvailability(end_len, mode == GEO_NODE_CURVE_INTERPOLATE_LENGTH);
+}
+
+namespace blender::nodes {
+
+struct TrimLocation {
+ /* Control point index at the start side of the trim location. */
+ int left_index;
+ /* Control point index at the end of the trim location's segment. */
+ int right_index;
+ /* The factor between the left and right indices. */
+ float factor;
+};
+
+template<typename T>
+static void shift_slice_to_start(MutableSpan<T> data, const int start_index, const int size)
+{
+ BLI_assert(start_index + size - 1 <= data.size());
+ memmove(data.data(), &data[start_index], sizeof(T) * size);
+}
+
+/* Shift slice to start of span and modifies start and end data. */
+template<typename T>
+static void linear_trim_data(const TrimLocation &start,
+ const TrimLocation &end,
+ MutableSpan<T> data)
+{
+ const int size = end.right_index - start.left_index + 1;
+
+ if (start.left_index > 0) {
+ shift_slice_to_start<T>(data, start.left_index, size);
+ }
+
+ const T start_data = mix2<T>(start.factor, data.first(), data[1]);
+ const T end_data = mix2<T>(end.factor, data[size - 2], data[size - 1]);
+
+ data.first() = start_data;
+ data[size - 1] = end_data;
+}
+
+/**
+ * Identical operation as #linear_trim_data, but copy data to a new #MutableSpan rather than
+ * modifying the original data.
+ */
+template<typename T>
+static void linear_trim_to_output_data(const TrimLocation &start,
+ const TrimLocation &end,
+ Span<T> src,
+ MutableSpan<T> dst)
+{
+ const int size = end.right_index - start.left_index + 1;
+
+ const T start_data = mix2<T>(start.factor, src[start.left_index], src[start.right_index]);
+ const T end_data = mix2<T>(end.factor, src[end.left_index], src[end.right_index]);
+
+ dst.copy_from(src.slice(start.left_index, size));
+ dst.first() = start_data;
+ dst.last() = end_data;
+}
+
+/* Look up the control points to the left and right of factor, and get the factor between them. */
+static TrimLocation lookup_control_point_position(const Spline::LookupResult &lookup,
+ Span<int> control_point_offsets)
+{
+ const int *left_offset = std::lower_bound(
+ control_point_offsets.begin(), control_point_offsets.end(), lookup.evaluated_index);
+ const int index = left_offset - control_point_offsets.begin();
+ const int left = control_point_offsets[index] > lookup.evaluated_index ? index - 1 : index;
+ const int right = left + 1;
+
+ const float factor = std::clamp(
+ (lookup.evaluated_index + lookup.factor - control_point_offsets[left]) /
+ (control_point_offsets[right] - control_point_offsets[left]),
+ 0.0f,
+ 1.0f);
+
+ return {left, right, factor};
+}
+
+static void trim_poly_spline(Spline &spline,
+ const Spline::LookupResult &start_lookup,
+ const Spline::LookupResult &end_lookup)
+{
+ /* Poly splines have a 1 to 1 mapping between control points and evaluated points. */
+ const TrimLocation start = {
+ start_lookup.evaluated_index, start_lookup.next_evaluated_index, start_lookup.factor};
+ const TrimLocation end = {
+ end_lookup.evaluated_index, end_lookup.next_evaluated_index, end_lookup.factor};
+
+ const int size = end.right_index - start.left_index + 1;
+
+ linear_trim_data<float3>(start, end, spline.positions());
+ linear_trim_data<float>(start, end, spline.radii());
+ linear_trim_data<float>(start, end, spline.tilts());
+
+ spline.attributes.foreach_attribute(
+ [&](StringRefNull name, const AttributeMetaData &UNUSED(meta_data)) {
+ std::optional<GMutableSpan> src = spline.attributes.get_for_write(name);
+ BLI_assert(src);
+ attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ linear_trim_data<T>(start, end, src->typed<T>());
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+
+ spline.resize(size);
+}
+
+/**
+ * Trim NURB splines by converting to a poly spline.
+ */
+static PolySpline trim_nurbs_spline(const Spline &spline,
+ const Spline::LookupResult &start_lookup,
+ const Spline::LookupResult &end_lookup)
+{
+ /* Since this outputs a poly spline, the evaluated indices are the control point indices. */
+ const TrimLocation start = {
+ start_lookup.evaluated_index, start_lookup.next_evaluated_index, start_lookup.factor};
+ const TrimLocation end = {
+ end_lookup.evaluated_index, end_lookup.next_evaluated_index, end_lookup.factor};
+
+ const int size = end.right_index - start.left_index + 1;
+
+ /* Create poly spline and copy trimmed data to it. */
+ PolySpline new_spline;
+ new_spline.resize(size);
+
+ /* Copy generic attribute data. */
+ spline.attributes.foreach_attribute(
+ [&](StringRefNull name, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src = spline.attributes.get_for_read(name);
+ BLI_assert(src);
+ if (!new_spline.attributes.create(name, meta_data.data_type)) {
+ BLI_assert_unreachable();
+ return false;
+ }
+ std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(name);
+ BLI_assert(dst);
+
+ attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ GVArray_Typed<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>());
+ linear_trim_to_output_data<T>(
+ start, end, eval_data->get_internal_span(), dst->typed<T>());
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+
+ linear_trim_to_output_data<float3>(
+ start, end, spline.evaluated_positions(), new_spline.positions());
+
+ GVArray_Typed<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii());
+ linear_trim_to_output_data<float>(
+ start, end, evaluated_radii->get_internal_span(), new_spline.radii());
+
+ GVArray_Typed<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts());
+ linear_trim_to_output_data<float>(
+ start, end, evaluated_tilts->get_internal_span(), new_spline.tilts());
+
+ return new_spline;
+}
+
+/**
+ * Trim Bezier splines by adjusting the first and last handles
+ * and control points to maintain the original shape.
+ */
+static void trim_bezier_spline(Spline &spline,
+ const Spline::LookupResult &start_lookup,
+ const Spline::LookupResult &end_lookup)
+{
+ BezierSpline &bezier_spline = static_cast<BezierSpline &>(spline);
+ Span<int> control_offsets = bezier_spline.control_point_offsets();
+
+ const TrimLocation start = lookup_control_point_position(start_lookup, control_offsets);
+ TrimLocation end = lookup_control_point_position(end_lookup, control_offsets);
+
+ /* The number of control points in the resulting spline. */
+ const int size = end.right_index - start.left_index + 1;
+
+ /* Trim the spline attributes. Done before end.factor recalculation as it needs
+ * the original end.factor value. */
+ linear_trim_data<float>(start, end, bezier_spline.radii());
+ linear_trim_data<float>(start, end, bezier_spline.tilts());
+ spline.attributes.foreach_attribute(
+ [&](StringRefNull name, const AttributeMetaData &UNUSED(meta_data)) {
+ std::optional<GMutableSpan> src = spline.attributes.get_for_write(name);
+ BLI_assert(src);
+ attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ linear_trim_data<T>(start, end, src->typed<T>());
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+
+ /* Recalculate end.factor if the size is two, because the adjustment in the
+ * position of the control point of the spline to the left of the new end point will change the
+ * factor between them. */
+ if (size == 2) {
+ if (start_lookup.factor == 1.0f) {
+ end.factor = 0.0f;
+ }
+ else {
+ end.factor = (end_lookup.evaluated_index + end_lookup.factor -
+ (start_lookup.evaluated_index + start_lookup.factor)) /
+ (control_offsets[end.right_index] -
+ (start_lookup.evaluated_index + start_lookup.factor));
+ end.factor = std::clamp(end.factor, 0.0f, 1.0f);
+ }
+ }
+
+ BezierSpline::InsertResult start_point = bezier_spline.calculate_segment_insertion(
+ start.left_index, start.right_index, start.factor);
+
+ /* Update the start control point parameters so they are used calculating the new end point. */
+ bezier_spline.positions()[start.left_index] = start_point.position;
+ bezier_spline.handle_positions_right()[start.left_index] = start_point.right_handle;
+ bezier_spline.handle_positions_left()[start.right_index] = start_point.handle_next;
+
+ const BezierSpline::InsertResult end_point = bezier_spline.calculate_segment_insertion(
+ end.left_index, end.right_index, end.factor);
+
+ /* If size is two, then the start point right handle needs to change to reflect the end point
+ * previous handle update. */
+ if (size == 2) {
+ start_point.right_handle = end_point.handle_prev;
+ }
+
+ /* Shift control point position data to start at beginning of array. */
+ if (start.left_index > 0) {
+ shift_slice_to_start(bezier_spline.positions(), start.left_index, size);
+ shift_slice_to_start(bezier_spline.handle_positions_left(), start.left_index, size);
+ shift_slice_to_start(bezier_spline.handle_positions_right(), start.left_index, size);
+ }
+
+ bezier_spline.positions().first() = start_point.position;
+ bezier_spline.positions()[size - 1] = end_point.position;
+
+ bezier_spline.handle_positions_left().first() = start_point.left_handle;
+ bezier_spline.handle_positions_left()[size - 1] = end_point.left_handle;
+
+ bezier_spline.handle_positions_right().first() = start_point.right_handle;
+ bezier_spline.handle_positions_right()[size - 1] = end_point.right_handle;
+
+ /* If there is at least one control point between the endpoints, update the control
+ * point handle to the right of the start point and to the left of the end point. */
+ if (size > 2) {
+ bezier_spline.handle_positions_left()[start.right_index - start.left_index] =
+ start_point.handle_next;
+ bezier_spline.handle_positions_right()[end.left_index - start.left_index] =
+ end_point.handle_prev;
+ }
+
+ bezier_spline.resize(size);
+}
+
+static void geo_node_curve_trim_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage;
+ const GeometryNodeCurveInterpolateMode mode = (GeometryNodeCurveInterpolateMode)
+ node_storage.mode;
+
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ if (!geometry_set.has_curve()) {
+ params.set_output("Curve", std::move(geometry_set));
+ return;
+ }
+
+ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
+ CurveEval &curve = *curve_component.get_for_write();
+ MutableSpan<SplinePtr> splines = curve.splines();
+
+ const float start = mode == GEO_NODE_CURVE_INTERPOLATE_FACTOR ?
+ params.extract_input<float>("Start") :
+ params.extract_input<float>("Start_001");
+ const float end = mode == GEO_NODE_CURVE_INTERPOLATE_FACTOR ?
+ params.extract_input<float>("End") :
+ params.extract_input<float>("End_001");
+
+ threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ Spline &spline = *splines[i];
+
+ /* Currently this node doesn't support cyclic splines, it could in the future though. */
+ if (spline.is_cyclic()) {
+ continue;
+ }
+
+ /* Return a spline with one point instead of implicitly
+ * reversing the spline or switching the parameters. */
+ if (end < start) {
+ spline.resize(1);
+ continue;
+ }
+
+ const Spline::LookupResult start_lookup =
+ (mode == GEO_NODE_CURVE_INTERPOLATE_LENGTH) ?
+ spline.lookup_evaluated_length(std::clamp(start, 0.0f, spline.length())) :
+ spline.lookup_evaluated_factor(std::clamp(start, 0.0f, 1.0f));
+ const Spline::LookupResult end_lookup =
+ (mode == GEO_NODE_CURVE_INTERPOLATE_LENGTH) ?
+ spline.lookup_evaluated_length(std::clamp(end, 0.0f, spline.length())) :
+ spline.lookup_evaluated_factor(std::clamp(end, 0.0f, 1.0f));
+
+ switch (spline.type()) {
+ case Spline::Type::Bezier:
+ trim_bezier_spline(spline, start_lookup, end_lookup);
+ break;
+ case Spline::Type::Poly:
+ trim_poly_spline(spline, start_lookup, end_lookup);
+ break;
+ case Spline::Type::NURBS:
+ splines[i] = std::make_unique<PolySpline>(
+ trim_nurbs_spline(spline, start_lookup, end_lookup));
+ break;
+ }
+ splines[i]->mark_cache_invalid();
+ }
+ });
+
+ params.set_output("Curve", std::move(geometry_set));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_curve_trim()
+{
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_TRIM, "Curve Trim", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_curve_trim_in, geo_node_curve_trim_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_curve_trim_exec;
+ ntype.draw_buttons = geo_node_curve_trim_layout;
+ node_type_storage(
+ &ntype, "NodeGeometryCurveTrim", node_free_standard_storage, node_copy_standard_storage);
+ node_type_init(&ntype, geo_node_curve_trim_init);
+ node_type_update(&ntype, geo_node_curve_trim_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc
index 3d5557d4049..f7279cf7524 100644
--- a/source/blender/nodes/intern/derived_node_tree.cc
+++ b/source/blender/nodes/intern/derived_node_tree.cc
@@ -73,7 +73,9 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context)
context->~DTreeContext();
}
-/* Returns true if there are any cycles in the node tree. */
+/**
+ * \return True when there is a link cycle. Unavailable sockets are ignored.
+ */
bool DerivedNodeTree::has_link_cycles() const
{
for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index 3024cc51cad..7487f11d77d 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -99,6 +99,13 @@ SocketLog &ModifierLog::lookup_or_add_socket_log(LogByTreeContext &log_by_tree_c
return socket_log;
}
+void ModifierLog::foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const
+{
+ if (root_tree_logs_) {
+ root_tree_logs_->foreach_node_log(fn);
+ }
+}
+
const NodeLog *TreeLog::lookup_node_log(StringRef node_name) const
{
const destruct_ptr<NodeLog> *node_log = node_logs_.lookup_ptr_as(node_name);
@@ -122,6 +129,17 @@ const TreeLog *TreeLog::lookup_child_log(StringRef node_name) const
return tree_log->get();
}
+void TreeLog::foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const
+{
+ for (auto node_log : node_logs_.items()) {
+ fn(*node_log.value);
+ }
+
+ for (auto child : child_logs_.items()) {
+ child.value->foreach_node_log(fn);
+ }
+}
+
const SocketLog *NodeLog::lookup_socket_log(eNodeSocketInOut in_out, int index) const
{
BLI_assert(index >= 0);
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 9ce9d6fc273..641d02af902 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -423,7 +423,13 @@ static bool has_link_cycles_recursive(const NodeRef &node,
is_in_stack[node_id] = true;
for (const OutputSocketRef *from_socket : node.outputs()) {
+ if (!from_socket->is_available()) {
+ continue;
+ }
for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) {
+ if (!to_socket->is_available()) {
+ continue;
+ }
const NodeRef &to_node = to_socket->node();
if (has_link_cycles_recursive(to_node, visited, is_in_stack)) {
return true;
@@ -435,6 +441,9 @@ static bool has_link_cycles_recursive(const NodeRef &node,
return false;
}
+/**
+ * \return True when there is a link cycle. Unavailable sockets are ignored.
+ */
bool NodeTreeRef::has_link_cycles() const
{
const int node_amount = nodes_by_id_.size();
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
index a864bef60d9..4df5add7151 100644
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ b/source/blender/nodes/shader/nodes/node_shader_common.c
@@ -229,9 +229,9 @@ void register_node_type_sh_group(void)
{
static bNodeType ntype;
- /* NB: cannot use sh_node_type_base for node group, because it would map the node type
- * to the shared NODE_GROUP integer type id.
- */
+ /* NOTE: cannot use #sh_node_type_base for node group, because it would map the node type
+ * to the shared #NODE_GROUP integer type id. */
+
node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
ntype.type = NODE_GROUP;
ntype.poll = sh_node_poll_default;
diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c
index b87720be5b0..2de64779ea6 100644
--- a/source/blender/nodes/texture/nodes/node_texture_common.c
+++ b/source/blender/nodes/texture/nodes/node_texture_common.c
@@ -158,9 +158,9 @@ void register_node_type_tex_group(void)
{
static bNodeType ntype;
- /* NB: cannot use sh_node_type_base for node group, because it would map the node type
- * to the shared NODE_GROUP integer type id.
- */
+ /* NOTE: Cannot use #sh_node_type_base for node group, because it would map the node type
+ * to the shared #NODE_GROUP integer type id. */
+
node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
ntype.type = NODE_GROUP;
ntype.poll = tex_node_poll_default;
diff --git a/source/blender/nodes/texture/nodes/node_texture_rotate.c b/source/blender/nodes/texture/nodes/node_texture_rotate.c
index 06eb632378c..9985499772e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_rotate.c
+++ b/source/blender/nodes/texture/nodes/node_texture_rotate.c
@@ -47,7 +47,7 @@ static void rotate(float new_co[3], float a, const float ax[3], const float co[3
float cos_a = cosf(a * (float)(2 * M_PI));
float sin_a = sinf(a * (float)(2 * M_PI));
- // x' = xcosa + n(n.x)(1-cosa) + (x*n)sina
+ /* `x' = xcosa + n(n.x)(1-cosa) + (x*n)sina`. */
mul_v3_v3fl(perp, co, cos_a);
mul_v3_v3fl(para, ax, dot_v3v3(co, ax) * (1 - cos_a));
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 84d804f8bdf..43a73363c98 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -30,7 +30,7 @@ struct PathResolvedRNA;
struct Text; /* defined in DNA_text_types.h */
struct bConstraint; /* DNA_constraint_types.h */
struct bConstraintOb; /* DNA_constraint_types.h */
-struct bConstraintTarget; /* DNA_constraint_types.h*/
+struct bConstraintTarget; /* DNA_constraint_types.h */
struct bContext;
struct bContextDataResult;
struct bPythonConstraint; /* DNA_constraint_types.h */
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index a27ef30c849..68fefee4a61 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -525,7 +525,7 @@ PyObject *PyC_FrozenSetFromStrings(const char **strings)
*
* Implementation - we can't actually prepend the existing exception,
* because it could have _any_ arguments given to it, so instead we get its
- * ``__str__`` output and raise our own exception including it.
+ * `__str__` output and raise our own exception including it.
*/
PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...)
{
diff --git a/source/blender/python/gpu/gpu_py.c b/source/blender/python/gpu/gpu_py.c
index 7aea940da94..e6ba46b2b05 100644
--- a/source/blender/python/gpu/gpu_py.c
+++ b/source/blender/python/gpu/gpu_py.c
@@ -17,8 +17,8 @@
/** \file
* \ingroup bpygpu
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_api.c b/source/blender/python/gpu/gpu_py_api.c
index 5119b3612f8..db84e03adcb 100644
--- a/source/blender/python/gpu/gpu_py_api.c
+++ b/source/blender/python/gpu/gpu_py_api.c
@@ -20,8 +20,8 @@
* Experimental Python API, not considered public yet (called '_gpu'),
* we may re-expose as public later.
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c
index 5214d156adf..c0c0aa0028d 100644
--- a/source/blender/python/gpu/gpu_py_batch.c
+++ b/source/blender/python/gpu/gpu_py_batch.c
@@ -19,11 +19,11 @@
/** \file
* \ingroup bpygpu
*
- * This file defines the offscreen functionalities of the 'gpu' module
+ * This file defines the off-screen functionalities of the 'gpu' module
* used for off-screen OpenGL rendering.
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c
index 5c004459b44..a1fc89e772e 100644
--- a/source/blender/python/gpu/gpu_py_buffer.c
+++ b/source/blender/python/gpu/gpu_py_buffer.c
@@ -19,8 +19,8 @@
*
* This file defines the gpu.state API.
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_capabilities.c b/source/blender/python/gpu/gpu_py_capabilities.c
index cedce485253..f3fb93021b2 100644
--- a/source/blender/python/gpu/gpu_py_capabilities.c
+++ b/source/blender/python/gpu/gpu_py_capabilities.c
@@ -17,8 +17,8 @@
/** \file
* \ingroup bpygpu
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_element.c b/source/blender/python/gpu/gpu_py_element.c
index 0cb5e9a2785..2dd8d1c379e 100644
--- a/source/blender/python/gpu/gpu_py_element.c
+++ b/source/blender/python/gpu/gpu_py_element.c
@@ -17,8 +17,8 @@
/** \file
* \ingroup bpygpu
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_framebuffer.c b/source/blender/python/gpu/gpu_py_framebuffer.c
index 2f081fcfd8c..a9347b71723 100644
--- a/source/blender/python/gpu/gpu_py_framebuffer.c
+++ b/source/blender/python/gpu/gpu_py_framebuffer.c
@@ -20,8 +20,8 @@
* This file defines the framebuffer functionalities of the 'gpu' module
* used for off-screen OpenGL rendering.
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
@@ -489,7 +489,7 @@ static PyObject *pygpu_framebuffer_read_color(BPyGPUFrameBuffer *self,
static const char *_keywords[] = {
"x", "y", "xsize", "ysize", "channels", "slot", "format", "data", NULL};
- static _PyArg_Parser _parser = {"iiiiiIO&|$O!:GPUTexture.__new__", _keywords, 0};
+ static _PyArg_Parser _parser = {"iiiiiIO&|$O!:read_color", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kwds,
&_parser,
@@ -551,6 +551,57 @@ static PyObject *pygpu_framebuffer_read_color(BPyGPUFrameBuffer *self,
return (PyObject *)py_buffer;
}
+PyDoc_STRVAR(pygpu_framebuffer_read_depth_doc,
+ ".. function:: read_depth(x, y, xsize, ysize, data=data)\n"
+ "\n"
+ " Read a pixel depth block from the frame buffer.\n"
+ "\n"
+ " :param x, y: Lower left corner of a rectangular block of pixels.\n"
+ " :param xsize, ysize: Dimensions of the pixel rectangle.\n"
+ " :type x, y, xsize, ysize: int\n"
+ " :arg data: Optional Buffer object to fill with the pixels values.\n"
+ " :type data: :class:`gpu.types.Buffer`\n"
+ " :return: The Buffer with the read pixels.\n"
+ " :rtype: :class:`gpu.types.Buffer`\n");
+static PyObject *pygpu_framebuffer_read_depth(BPyGPUFrameBuffer *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ PYGPU_FRAMEBUFFER_CHECK_OBJ(self);
+ int x, y, w, h;
+ BPyGPUBuffer *py_buffer = NULL;
+
+ static const char *_keywords[] = {"x", "y", "xsize", "ysize", "data", NULL};
+ static _PyArg_Parser _parser = {"iiii|$O!:read_depth", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser, &x, &y, &w, &h, &BPyGPU_BufferType, &py_buffer)) {
+ return NULL;
+ }
+
+ if (py_buffer) {
+ if (py_buffer->format != GPU_DATA_FLOAT) {
+ PyErr_SetString(PyExc_AttributeError, "the format of the buffer must be 'GPU_DATA_FLOAT'");
+ return NULL;
+ }
+
+ size_t size_curr = bpygpu_Buffer_size(py_buffer);
+ size_t size_expected = w * h * GPU_texture_dataformat_size(GPU_DATA_FLOAT);
+ if (size_curr < size_expected) {
+ PyErr_SetString(PyExc_BufferError, "the buffer size is smaller than expected");
+ return NULL;
+ }
+ }
+ else {
+ py_buffer = BPyGPU_Buffer_CreatePyObject(GPU_DATA_FLOAT, (Py_ssize_t[]){h, w}, 2, NULL);
+ BLI_assert(bpygpu_Buffer_size(py_buffer) ==
+ w * h * GPU_texture_dataformat_size(GPU_DATA_FLOAT));
+ }
+
+ GPU_framebuffer_read_depth(self->fb, x, y, w, h, GPU_DATA_FLOAT, py_buffer->buf.as_void);
+
+ return (PyObject *)py_buffer;
+}
+
#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
PyDoc_STRVAR(pygpu_framebuffer_free_doc,
".. method:: free()\n"
@@ -598,6 +649,10 @@ static struct PyMethodDef pygpu_framebuffer__tp_methods[] = {
(PyCFunction)pygpu_framebuffer_read_color,
METH_VARARGS | METH_KEYWORDS,
pygpu_framebuffer_read_color_doc},
+ {"read_depth",
+ (PyCFunction)pygpu_framebuffer_read_depth,
+ METH_VARARGS | METH_KEYWORDS,
+ pygpu_framebuffer_read_depth_doc},
#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
{"free", (PyCFunction)pygpu_framebuffer_free, METH_NOARGS, pygpu_framebuffer_free_doc},
#endif
diff --git a/source/blender/python/gpu/gpu_py_matrix.c b/source/blender/python/gpu/gpu_py_matrix.c
index b379600d33c..cc9b3d702e2 100644
--- a/source/blender/python/gpu/gpu_py_matrix.c
+++ b/source/blender/python/gpu/gpu_py_matrix.c
@@ -22,8 +22,8 @@
* \warning While these functions attempt to ensure correct stack usage.
* Mixing Python and C functions may still crash on invalid use.
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index 0a8b294ea41..457f00b1267 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -22,8 +22,8 @@
* This file defines the offscreen functionalities of the 'gpu' module
* used for off-screen OpenGL rendering.
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c
index e49ad18dfd8..132052b6f1d 100644
--- a/source/blender/python/gpu/gpu_py_platform.c
+++ b/source/blender/python/gpu/gpu_py_platform.c
@@ -17,8 +17,8 @@
/** \file
* \ingroup bpygpu
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c
index b72aca6a792..4db102118f1 100644
--- a/source/blender/python/gpu/gpu_py_select.c
+++ b/source/blender/python/gpu/gpu_py_select.c
@@ -22,8 +22,8 @@
* \note Currently only used for gizmo selection,
* will need to add begin/end and a way to access the hits.
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index fc3a7d1360b..00e876aee7d 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -17,8 +17,8 @@
/** \file
* \ingroup bpygpu
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_state.c b/source/blender/python/gpu/gpu_py_state.c
index 173c5afba56..7b7a61cc338 100644
--- a/source/blender/python/gpu/gpu_py_state.c
+++ b/source/blender/python/gpu/gpu_py_state.c
@@ -19,8 +19,8 @@
*
* This file defines the gpu.state API.
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_texture.c b/source/blender/python/gpu/gpu_py_texture.c
index 2181c09b537..ca41662db9d 100644
--- a/source/blender/python/gpu/gpu_py_texture.c
+++ b/source/blender/python/gpu/gpu_py_texture.c
@@ -19,8 +19,8 @@
*
* This file defines the texture functionalities of the 'gpu' module
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_types.c b/source/blender/python/gpu/gpu_py_types.c
index fdd589d788e..a8787cf5c7f 100644
--- a/source/blender/python/gpu/gpu_py_types.c
+++ b/source/blender/python/gpu/gpu_py_types.c
@@ -17,8 +17,8 @@
/** \file
* \ingroup bpygpu
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_uniformbuffer.c b/source/blender/python/gpu/gpu_py_uniformbuffer.c
index cfef20e2e4d..616ef65a5d1 100644
--- a/source/blender/python/gpu/gpu_py_uniformbuffer.c
+++ b/source/blender/python/gpu/gpu_py_uniformbuffer.c
@@ -19,8 +19,8 @@
*
* This file defines the uniform buffer functionalities of the 'gpu' module
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c
index 3c7038186b9..949086378a8 100644
--- a/source/blender/python/gpu/gpu_py_vertex_buffer.c
+++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c
@@ -17,8 +17,8 @@
/** \file
* \ingroup bpygpu
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/gpu/gpu_py_vertex_format.c b/source/blender/python/gpu/gpu_py_vertex_format.c
index 39c91966cab..c344429576a 100644
--- a/source/blender/python/gpu/gpu_py_vertex_format.c
+++ b/source/blender/python/gpu/gpu_py_vertex_format.c
@@ -17,8 +17,8 @@
/** \file
* \ingroup bpygpu
*
- * - Use ``bpygpu_`` for local API.
- * - Use ``BPyGPU`` for public API.
+ * - Use `bpygpu_` for local API.
+ * - Use `BPyGPU` for public API.
*/
#include <Python.h>
diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c
index d2261ee7311..5f277b0ef07 100644
--- a/source/blender/python/intern/bpy_app_ffmpeg.c
+++ b/source/blender/python/intern/bpy_app_ffmpeg.c
@@ -36,7 +36,7 @@
static PyTypeObject BlenderAppFFmpegType;
#define DEF_FFMPEG_LIB_VERSION(lib) \
- {(#lib "_version"), ("The " #lib " version as a tuple of 3 numbers")}, \
+ {(#lib "_version"), ("The " #lib " version as a tuple of 3 numbers")}, \
{ \
(#lib "_version_string"), ("The " #lib " version formatted as a string") \
}
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index 9ee9f2e477f..d5afb2334f0 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -339,7 +339,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
return NULL;
}
- /* When calling bpy.ops.wm.read_factory_settings() bpy.data's main pointer
+ /* When calling `bpy.ops.wm.read_factory_settings()` `bpy.data's` main pointer
* is freed by clear_globals(), further access will crash blender.
* Setting context is not needed in this case, only calling because this
* function corrects bpy.data (internal Main pointer) */
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index e6f3e509469..7ecdbe4b4d9 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -4254,7 +4254,7 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA *self)
}
PyDoc_STRVAR(pyrna_struct_id_properties_ensure_doc,
- ".. method:: id_properties_ensure()\n"
+ ".. method:: id_properties_ensure()\n\n"
" :return: the parent group for an RNA struct's custom IDProperties.\n"
" :rtype: :class:`bpy.types.IDPropertyGroup`\n");
static PyObject *pyrna_struct_id_properties_ensure(BPy_StructRNA *self)
@@ -4282,7 +4282,7 @@ static PyObject *pyrna_struct_id_properties_ensure(BPy_StructRNA *self)
}
PyDoc_STRVAR(pyrna_struct_id_properties_clear_doc,
- ".. method:: id_properties_clear()\n"
+ ".. method:: id_properties_clear()\n\n"
" :return: Remove the parent group for an RNA struct's custom IDProperties.\n");
static PyObject *pyrna_struct_id_properties_clear(BPy_StructRNA *self)
{
@@ -7424,10 +7424,13 @@ static PyObject *pyrna_srna_Subtype(StructRNA *srna)
PyObject *metaclass;
const char *idname = RNA_struct_identifier(srna);
- /* Remove __doc__ for now. */
- // const char *descr = RNA_struct_ui_description(srna);
- // if (!descr) descr = "(no docs)";
- // "__doc__", descr
+ /* Remove `__doc__` for now because we don't need it to generate docs. */
+#if 0
+ const char *descr = RNA_struct_ui_description(srna);
+ if (!descr) {
+ descr = "(no docs)";
+ }
+#endif
if (RNA_struct_idprops_check(srna) &&
!PyObject_IsSubclass(py_base, (PyObject *)&pyrna_struct_meta_idprop_Type)) {
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 9745f39b6b8..a716f4ab9e5 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -605,7 +605,7 @@ PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args)
DEG_relations_tag_update(CTX_data_main(context));
}
else {
- /* XXX, should be handled by reports, */
+ /* XXX: should be handled by reports. */
PyErr_SetString(PyExc_TypeError,
"bpy_struct.driver_add(): failed because of an internal error");
return NULL;
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index 66044311321..1bb68babc3c 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -377,9 +377,16 @@ static PyObject *bpy_orphans_purge(PyObject *UNUSED(self), PyObject *args, PyObj
bool do_recursive_cleanup = false;
static const char *_keywords[] = {"do_local_ids", "do_linked_ids", "do_recursive", NULL};
- static _PyArg_Parser _parser = {"|$ppp:orphans_purge", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(
- args, kwds, &_parser, &do_local_ids, &do_linked_ids, &do_recursive_cleanup)) {
+ static _PyArg_Parser _parser = {"|O&O&O&:orphans_purge", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args,
+ kwds,
+ &_parser,
+ PyC_ParseBool,
+ &do_local_ids,
+ PyC_ParseBool,
+ &do_linked_ids,
+ PyC_ParseBool,
+ &do_recursive_cleanup)) {
return NULL;
}
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index e5ac1ba9a95..aa8cf8f2a9f 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -67,7 +67,7 @@ static const char *bpyunits_ucategorie_items[] = {
/**
* These fields are just empty placeholders, actual values get set in initializations functions.
* This allows us to avoid many handwriting, and above all,
- * to keep all systems/categories definition stuff in ``BKE_unit.h``.
+ * to keep all systems/categories definition stuff in `BKE_unit.h`.
*/
static PyStructSequence_Field bpyunits_systems_fields[ARRAY_SIZE(bpyunits_usystem_items)];
static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategorie_items)];
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 16bf7120606..5beca7bd71a 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -78,7 +78,7 @@ static int mathutils_array_parse_fast(float *array,
}
/**
- * helper function that returns a Python ``__hash__``.
+ * helper function that returns a Python `__hash__`.
*
* \note consistent with the equivalent tuple of floats (CPython's 'tuplehash')
*/
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 8b8130f3cc2..36b8b0b6d35 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -1174,7 +1174,7 @@ static void matrix_invert_with_det_n_internal(float *mat_dst,
}
/**
- * \param r_mat: can be from ``self->matrix`` or not.
+ * \param r_mat: can be from `self->matrix` or not.
*/
static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
{
@@ -1191,8 +1191,8 @@ static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
}
/**
- * Similar to ``matrix_invert_internal`` but should never error.
- * \param r_mat: can be from ``self->matrix`` or not.
+ * Similar to `matrix_invert_internal` but should never error.
+ * \param r_mat: can be from `self->matrix` or not.
*/
static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat)
{
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index 88b3bddddf6..c73dea79aac 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -1505,6 +1505,9 @@ static PyObject *list_of_lists_from_arrays(const int *array,
PyObject *ret, *sublist;
int i, j, sublist_len, sublist_start, val;
+ if (array == NULL) {
+ return PyList_New(0);
+ }
ret = PyList_New(toplevel_len);
for (i = 0; i < toplevel_len; i++) {
sublist_len = len_table[i];
@@ -1521,7 +1524,8 @@ static PyObject *list_of_lists_from_arrays(const int *array,
PyDoc_STRVAR(
M_Geometry_delaunay_2d_cdt_doc,
- ".. function:: delaunay_2d_cdt(vert_coords, edges, faces, output_type, epsilon)\n"
+ ".. function:: delaunay_2d_cdt(vert_coords, edges, faces, output_type, epsilon, "
+ "need_ids=True)\n"
"\n"
" Computes the Constrained Delaunay Triangulation of a set of vertices,\n"
" with edges and faces that must appear in the triangulation.\n"
@@ -1533,6 +1537,8 @@ PyDoc_STRVAR(
" input element indices corresponding to the positionally same output element.\n"
" For edges, the orig indices start with the input edges and then continue\n"
" with the edges implied by each of the faces (n of them for an n-gon).\n"
+ " If the need_ids argument is supplied, and False, then the code skips the preparation\n"
+ " of the orig arrays, which may save some time."
"\n"
" :arg vert_coords: Vertex coordinates (2d)\n"
" :type vert_coords: list of :class:`mathutils.Vector`\n"
@@ -1543,10 +1549,14 @@ PyDoc_STRVAR(
" :arg output_type: What output looks like. 0 => triangles with convex hull. "
"1 => triangles inside constraints. "
"2 => the input constraints, intersected. "
- "3 => like 2 but with extra edges to make valid BMesh faces.\n"
+ "3 => like 2 but detect holes and omit them from output. "
+ "4 => like 2 but with extra edges to make valid BMesh faces. "
+ "5 => like 4 but detect holes and omit them from output.\n"
" :type output_type: int\\n"
" :arg epsilon: For nearness tests; should not be zero\n"
" :type epsilon: float\n"
+ " :arg need_ids: are the orig output arrays needed?\n"
+ " :type need_args: bool\n"
" :return: Output tuple, (vert_coords, edges, faces, orig_verts, orig_edges, orig_faces)\n"
" :rtype: (list of `mathutils.Vector`, "
"list of (int, int), "
@@ -1561,6 +1571,7 @@ static PyObject *M_Geometry_delaunay_2d_cdt(PyObject *UNUSED(self), PyObject *ar
PyObject *vert_coords, *edges, *faces, *item;
int output_type;
float epsilon;
+ bool need_ids = true;
float(*in_coords)[2] = NULL;
int(*in_edges)[2] = NULL;
int *in_faces = NULL;
@@ -1578,8 +1589,14 @@ static PyObject *M_Geometry_delaunay_2d_cdt(PyObject *UNUSED(self), PyObject *ar
PyObject *ret_value = NULL;
int i;
- if (!PyArg_ParseTuple(
- args, "OOOif:delaunay_2d_cdt", &vert_coords, &edges, &faces, &output_type, &epsilon)) {
+ if (!PyArg_ParseTuple(args,
+ "OOOif|p:delaunay_2d_cdt",
+ &vert_coords,
+ &edges,
+ &faces,
+ &output_type,
+ &epsilon,
+ &need_ids)) {
return NULL;
}
@@ -1609,6 +1626,7 @@ static PyObject *M_Geometry_delaunay_2d_cdt(PyObject *UNUSED(self), PyObject *ar
in.faces_start_table = in_faces_start_table;
in.faces_len_table = in_faces_len_table;
in.epsilon = epsilon;
+ in.need_ids = need_ids;
res = BLI_delaunay_2d_cdt_calc(&in, output_type);
diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c
index 707fd40e9d0..69d37b345c6 100644
--- a/source/blender/python/mathutils/mathutils_noise.c
+++ b/source/blender/python/mathutils/mathutils_noise.c
@@ -131,8 +131,7 @@ static void next_state(void)
ulong *p = state;
int j;
- /* if init_genrand() has not been called, */
- /* a default initial seed is used */
+ /* If init_genrand() has not been called, a default initial seed is used. */
if (initf == 0) {
init_genrand(5489UL);
}
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index d5653f87c2b..74e57989f47 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -26,7 +26,7 @@
* The Bake API is fully implemented with Python rna functions.
* The operator expects/call a function:
*
- * ``def bake(scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result)``
+ * `def bake(scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result)`
* - scene: current scene (Python object)
* - object: object to render (Python object)
* - pass_type: pass to render (string, e.g., "COMBINED", "AO", "NORMAL", ...)
@@ -53,10 +53,10 @@
* \endcode
*
* In python you have access to:
- * - ``primitive_id``, ``object_id``, ``uv``, ``du_dx``, ``du_dy``, ``next``
- * - ``next()`` is a function that returns the next #BakePixel in the array.
+ * - `primitive_id`, `object_id`, `uv`, `du_dx`, `du_dy`, `next`.
+ * - `next()` is a function that returns the next #BakePixel in the array.
*
- * \note Pixels that should not be baked have ``primitive_id == -1``
+ * \note Pixels that should not be baked have `primitive_id == -1`.
*
* For a complete implementation example look at the Cycles Bake commit.
*/
diff --git a/source/blender/render/intern/texture_image.c b/source/blender/render/intern/texture_image.c
index c4ee16a0ecc..62aee564626 100644
--- a/source/blender/render/intern/texture_image.c
+++ b/source/blender/render/intern/texture_image.c
@@ -932,8 +932,8 @@ static void feline_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata
#endif
/* `const int out =` */ ibuf_get_color_clip_bilerp(
tc, ibuf, ibuf->x * u, ibuf->y * v, AFD->intpol, AFD->extflag);
- /* TXF alpha: clip |= out;
- * TXF alpha: cw += out ? 0.0f : wt; */
+ /* TXF alpha: `clip |= out;`
+ * TXF alpha: `cw += out ? 0.0f : wt;` */
texr->tr += tc[0] * wt;
texr->tg += tc[1] * wt;
texr->tb += tc[2] * wt;
diff --git a/source/blender/sequencer/SEQ_effects.h b/source/blender/sequencer/SEQ_effects.h
index 79a36be5a0b..4bd5b54b36b 100644
--- a/source/blender/sequencer/SEQ_effects.h
+++ b/source/blender/sequencer/SEQ_effects.h
@@ -70,9 +70,6 @@ struct SeqEffectHandle {
* 2: out = ibuf2 */
int (*early_out)(struct Sequence *seq, float facf0, float facf1);
- /* stores the y-range of the effect IPO */
- void (*store_icu_yrange)(struct Sequence *seq, short adrcode, float *ymin, float *ymax);
-
/* stores the default facf0 and facf1 if no IPO is present */
void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *facf0, float *facf1);
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index 0a8be3b33ae..7757271a2e5 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -1428,10 +1428,9 @@ static void do_mul_effect_byte(float facf0,
fac1 = (int)(256.0f * facf0);
fac3 = (int)(256.0f * facf1);
- /* formula:
- * fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s; //+centx
- * yaux = -s * px + c * py; //+centy
- */
+ /* Formula:
+ * `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s;` // + centx
+ * `yaux = -s * px + c * py;` // + centy */
while (y--) {
@@ -1483,9 +1482,8 @@ static void do_mul_effect_float(
fac1 = facf0;
fac3 = facf1;
- /* formula:
- * fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a
- */
+ /* Formula:
+ * `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a`. */
while (y--) {
x = xo;
@@ -3086,10 +3084,12 @@ static void init_speed_effect(Sequence *seq)
seq->effectdata = MEM_callocN(sizeof(SpeedControlVars), "speedcontrolvars");
v = (SpeedControlVars *)seq->effectdata;
- v->globalSpeed = 1.0;
v->frameMap = NULL;
- v->flags |= SEQ_SPEED_INTEGRATE; /* should be default behavior */
v->length = 0;
+ v->speed_control_type = SEQ_SPEED_STRETCH;
+ v->speed_fader = 1.0f;
+ v->speed_fader_length = 0.0f;
+ v->speed_fader_frame_number = 0.0f;
}
static void load_speed_effect(Sequence *seq)
@@ -3131,29 +3131,6 @@ static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNU
return EARLY_DO_EFFECT;
}
-static void store_icu_yrange_speed(Sequence *seq, short UNUSED(adrcode), float *ymin, float *ymax)
-{
- SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
-
- /* if not already done, load / initialize data */
- SEQ_effect_handle_get(seq);
-
- if ((v->flags & SEQ_SPEED_INTEGRATE) != 0) {
- *ymin = -100.0;
- *ymax = 100.0;
- }
- else {
- if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) {
- *ymin = 0.0;
- *ymax = 1.0;
- }
- else {
- *ymin = 0.0;
- *ymax = seq->len;
- }
- }
-}
-
/**
* Generator strips with zero inputs have their length set to 1 permanently. In some cases it is
* useful to use speed effect on these strips because they can be animated. This can be done by
@@ -3174,7 +3151,6 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force)
float fallback_fac = 1.0f;
SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
FCurve *fcu = NULL;
- int flags = v->flags;
/* if not already done, load / initialize data */
SEQ_effect_handle_get(seq);
@@ -3189,7 +3165,20 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force)
/* XXX(campbell): new in 2.5x. should we use the animation system this way?
* The fcurve is needed because many frames need evaluating at once. */
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
+ switch (v->speed_control_type) {
+ case SEQ_SPEED_MULTIPLY: {
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
+ break;
+ }
+ case SEQ_SPEED_FRAME_NUMBER: {
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_frame_number", 0, NULL);
+ break;
+ }
+ case SEQ_SPEED_LENGTH: {
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_length", 0, NULL);
+ break;
+ }
+ }
if (!v->frameMap || v->length != seq->len) {
if (v->frameMap) {
MEM_freeN(v->frameMap);
@@ -3204,21 +3193,33 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force)
const int target_strip_length = seq_effect_speed_get_strip_content_length(seq->seq1);
- if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
+ if (v->speed_control_type == SEQ_SPEED_STRETCH) {
if ((seq->seq1->enddisp != seq->seq1->start) && (target_strip_length != 0)) {
fallback_fac = (float)target_strip_length / (float)(seq->seq1->enddisp - seq->seq1->start);
- flags = SEQ_SPEED_INTEGRATE;
fcu = NULL;
}
}
else {
/* if there is no fcurve, use value as simple multiplier */
if (!fcu) {
- fallback_fac = seq->speed_fader; /* Same as speed_factor in RNA. */
+ switch (v->speed_control_type) {
+ case SEQ_SPEED_MULTIPLY: {
+ fallback_fac = v->speed_fader;
+ break;
+ }
+ case SEQ_SPEED_FRAME_NUMBER: {
+ fallback_fac = v->speed_fader_frame_number;
+ break;
+ }
+ case SEQ_SPEED_LENGTH: {
+ fallback_fac = v->speed_fader_length;
+ break;
+ }
+ }
}
}
- if (flags & SEQ_SPEED_INTEGRATE) {
+ if (ELEM(v->speed_control_type, SEQ_SPEED_MULTIPLY, SEQ_SPEED_STRETCH)) {
float cursor = 0;
float facf;
@@ -3232,7 +3233,6 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force)
else {
facf = fallback_fac;
}
- facf *= v->globalSpeed;
cursor += facf;
@@ -3258,10 +3258,10 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force)
facf = fallback_fac;
}
- if (flags & SEQ_SPEED_COMPRESS_IPO_Y) {
+ if (v->speed_control_type == SEQ_SPEED_LENGTH) {
facf *= target_strip_length;
+ facf /= 100.0f;
}
- facf *= v->globalSpeed;
if (facf >= target_strip_length) {
facf = target_strip_length - 1;
@@ -4083,14 +4083,6 @@ static int early_out_mul_input2(Sequence *UNUSED(seq), float facf0, float facf1)
return EARLY_DO_EFFECT;
}
-static void store_icu_yrange_noop(Sequence *UNUSED(seq),
- short UNUSED(adrcode),
- float *UNUSED(ymin),
- float *UNUSED(ymax))
-{
- /* defaults are fine */
-}
-
static void get_default_fac_noop(Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
float *facf0,
@@ -4130,7 +4122,6 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type)
rval.free = free_noop;
rval.early_out = early_out_noop;
rval.get_default_fac = get_default_fac_noop;
- rval.store_icu_yrange = store_icu_yrange_noop;
rval.execute = NULL;
rval.init_execution = init_execution;
rval.execute_slice = NULL;
@@ -4244,7 +4235,6 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type)
rval.copy = copy_speed_effect;
rval.execute = do_speed_effect;
rval.early_out = early_out_speed;
- rval.store_icu_yrange = store_icu_yrange_speed;
break;
case SEQ_TYPE_COLOR:
rval.init = init_solid_color;
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index b9278b9f971..e92afee08cd 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -112,8 +112,8 @@ static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, i
Sequence *seq;
int seqmute;
- /* for sound we go over full meta tree to update muted state,
- * since sound is played outside of evaluating the imbufs, */
+ /* For sound we go over full meta tree to update muted state,
+ * since sound is played outside of evaluating the imbufs. */
for (seq = seqbasep->first; seq; seq = seq->next) {
seqmute = (mute || (seq->flag & SEQ_MUTE));
@@ -407,6 +407,8 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
BLI_addtail(&left_strips, seq);
}
+ SEQ_collection_free(collection);
+
/* Sort list, so that no strip can depend on next strip in list.
* This is important for SEQ_time_update_sequence functionality. */
SEQ_sort(&left_strips);
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index 20e2421ea88..68128690773 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -111,8 +111,8 @@ static void seq_update_sound_bounds_recursive_impl(Scene *scene,
{
Sequence *seq;
- /* for sound we go over full meta tree to update bounds of the sound strips,
- * since sound is played outside of evaluating the imbufs, */
+ /* For sound we go over full meta tree to update bounds of the sound strips,
+ * since sound is played outside of evaluating the imbufs. */
for (seq = metaseq->seqbase.first; seq; seq = seq->next) {
if (seq->type == SEQ_TYPE_META) {
seq_update_sound_bounds_recursive_impl(
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index b7989349ebe..c9af2fced65 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -269,9 +269,9 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
}
test->machine += channel_delta;
- SEQ_time_update_sequence(
- evil_scene,
- test); // XXX: I don't think this is needed since were only moving vertically, Campbell.
+
+ /* XXX: I don't think this is needed since were only moving vertically, Campbell. */
+ SEQ_time_update_sequence(evil_scene, test);
}
if ((test->machine < 1) || (test->machine > MAXSEQ)) {
diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c
index 8a259c6aaff..8cb1ea6b66c 100644
--- a/source/blender/shader_fx/intern/FX_ui_common.c
+++ b/source/blender/shader_fx/intern/FX_ui_common.c
@@ -9,7 +9,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
diff --git a/source/blender/simulation/intern/SIM_mass_spring.cpp b/source/blender/simulation/intern/SIM_mass_spring.cpp
index ca01120eecb..f9a22276363 100644
--- a/source/blender/simulation/intern/SIM_mass_spring.cpp
+++ b/source/blender/simulation/intern/SIM_mass_spring.cpp
@@ -213,7 +213,8 @@ int SIM_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd)
return 1;
}
-void SIM_mass_spring_set_implicit_vertex_mass(Implicit_Data *data, int index, float mass){
+void SIM_mass_spring_set_implicit_vertex_mass(Implicit_Data *data, int index, float mass)
+{
SIM_mass_spring_set_vertex_mass(data, index, mass);
}
@@ -1051,18 +1052,22 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt)
SIM_hair_volume_grid_interpolate(grid, x, &gdensity, gvel, gvel_smooth, NULL, NULL);
- // BKE_sim_debug_data_add_circle(
- // clmd->debug_data, x, gdensity, 0.7, 0.3, 1,
- // "grid density", i, j, 3111);
+# if 0
+ BKE_sim_debug_data_add_circle(
+ clmd->debug_data, x, gdensity, 0.7, 0.3, 1,
+ "grid density", i, j, 3111);
+# endif
if (!is_zero_v3(gvel) || !is_zero_v3(gvel_smooth)) {
float dvel[3];
sub_v3_v3v3(dvel, gvel_smooth, gvel);
- // BKE_sim_debug_data_add_vector(
- // clmd->debug_data, x, gvel, 0.4, 0, 1,
- // "grid velocity", i, j, 3112);
- // BKE_sim_debug_data_add_vector(
- // clmd->debug_data, x, gvel_smooth, 0.6, 1, 1,
- // "grid velocity", i, j, 3113);
+# if 0
+ BKE_sim_debug_data_add_vector(
+ clmd->debug_data, x, gvel, 0.4, 0, 1,
+ "grid velocity", i, j, 3112);
+ BKE_sim_debug_data_add_vector(
+ clmd->debug_data, x, gvel_smooth, 0.6, 1, 1,
+ "grid velocity", i, j, 3113);
+# endif
BKE_sim_debug_data_add_vector(
clmd->debug_data, x, dvel, 0.4, 1, 0.7, "grid velocity", i, j, 3114);
# if 0
@@ -1073,12 +1078,14 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt)
interp_v3_v3v3(col, col0, col1,
CLAMPIS(gdensity * clmd->sim_parms->density_strength, 0.0, 1.0));
- // BKE_sim_debug_data_add_circle(
- // clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4,
- // "grid velocity", i, j, 3115);
- // BKE_sim_debug_data_add_dot(
- // clmd->debug_data, x, col[0], col[1], col[2],
- // "grid velocity", i, j, 3115);
+# if 0
+ BKE_sim_debug_data_add_circle(
+ clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4,
+ "grid velocity", i, j, 3115);
+ BKE_sim_debug_data_add_dot(
+ clmd->debug_data, x, col[0], col[1], col[2],
+ "grid velocity", i, j, 3115);
+# endif
BKE_sim_debug_data_add_circle(
clmd->debug_data, x, 0.01f, col[0], col[1], col[2], "grid velocity", i, j, 3115);
}
diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp
index 4966fa2510d..348c8683be9 100644
--- a/source/blender/simulation/intern/hair_volume.cpp
+++ b/source/blender/simulation/intern/hair_volume.cpp
@@ -112,9 +112,11 @@ BLI_INLINE int hair_grid_interp_weights(
uvw[1] = (vec[1] - gmin[1]) * scale - (float)j;
uvw[2] = (vec[2] - gmin[2]) * scale - (float)k;
- // BLI_assert(0.0f <= uvw[0] && uvw[0] <= 1.0001f);
- // BLI_assert(0.0f <= uvw[1] && uvw[1] <= 1.0001f);
- // BLI_assert(0.0f <= uvw[2] && uvw[2] <= 1.0001f);
+#if 0
+ BLI_assert(0.0f <= uvw[0] && uvw[0] <= 1.0001f);
+ BLI_assert(0.0f <= uvw[1] && uvw[1] <= 1.0001f);
+ BLI_assert(0.0f <= uvw[2] && uvw[2] <= 1.0001f);
+#endif
return offset;
}
@@ -350,7 +352,7 @@ BLI_INLINE int hair_grid_weights(
weights[6] = dist_tent_v3f3(uvw, (float)i, (float)(j + 1), (float)(k + 1));
weights[7] = dist_tent_v3f3(uvw, (float)(i + 1), (float)(j + 1), (float)(k + 1));
- // BLI_assert(fabsf(weights_sum(weights) - 1.0f) < 0.0001f);
+ // BLI_assert(fabsf(weights_sum(weights) - 1.0f) < 0.0001f);
return offset;
}
@@ -488,9 +490,10 @@ BLI_INLINE void hair_volume_add_segment_2D(HairGrid *grid,
BKE_sim_debug_data_add_dot(x2w, 0.1, 0.1, 0.7, "grid", 649, debug_i, j, k);
BKE_sim_debug_data_add_line(wloc, x2w, 0.3, 0.8, 0.3, "grid", 253, debug_i, j, k);
BKE_sim_debug_data_add_line(wloc, x3w, 0.8, 0.3, 0.3, "grid", 254, debug_i, j, k);
- // BKE_sim_debug_data_add_circle(
- // x2w, len_v3v3(wloc, x2w), 0.2, 0.7, 0.2,
- // "grid", 255, i, j, k);
+# if 0
+ BKE_sim_debug_data_add_circle(
+ x2w, len_v3v3(wloc, x2w), 0.2, 0.7, 0.2, "grid", 255, i, j, k);
+# endif
}
}
# endif
@@ -1003,9 +1006,10 @@ bool SIM_hair_volume_solve_divergence(HairGrid *grid,
if (!is_margin) {
float dvel[3];
sub_v3_v3v3(dvel, vert->velocity_smooth, vert->velocity);
- // BKE_sim_debug_data_add_vector(
- // grid->debug_data, wloc, dvel, 1, 1, 1,
- // "grid", 5566, i, j, k);
+# if 0
+ BKE_sim_debug_data_add_vector(
+ grid->debug_data, wloc, dvel, 1, 1, 1, "grid", 5566, i, j, k);
+# endif
}
if (!is_margin) {
@@ -1015,11 +1019,12 @@ bool SIM_hair_volume_solve_divergence(HairGrid *grid,
float col[3];
interp_v3_v3v3(col, col0, colp, d);
- // if (d > 0.05f) {
- // BKE_sim_debug_data_add_dot(
- // grid->debug_data, wloc, col[0], col[1], col[2],
- // "grid", 5544, i, j, k);
- // }
+# if 0
+ if (d > 0.05f) {
+ BKE_sim_debug_data_add_dot(
+ grid->debug_data, wloc, col[0], col[1], col[2], "grid", 5544, i, j, k);
+ }
+# endif
}
}
}
diff --git a/source/blender/simulation/intern/implicit_blender.c b/source/blender/simulation/intern/implicit_blender.c
index 8aa3774a3f2..10a5f153662 100644
--- a/source/blender/simulation/intern/implicit_blender.c
+++ b/source/blender/simulation/intern/implicit_blender.c
@@ -180,8 +180,8 @@ DO_INLINE void mul_lfvectorS(float (*to)[3],
mul_fvector_S(to[i], fLongVector[i], scalar);
}
}
-/* Multiply long vector with scalar. */
-/* A -= B * float */
+/* Multiply long vector with scalar.
+ * `A -= B * float` */
DO_INLINE void submul_lfvectorS(float (*to)[3],
float (*fLongVector)[3],
float scalar,
@@ -209,7 +209,7 @@ DO_INLINE float dot_lfvector(float (*fLongVectorA)[3],
}
return temp;
}
-/* A = B + C --> for big vector */
+/* `A = B + C` -> for big vector. */
DO_INLINE void add_lfvector_lfvector(float (*to)[3],
float (*fLongVectorA)[3],
float (*fLongVectorB)[3],
@@ -221,7 +221,7 @@ DO_INLINE void add_lfvector_lfvector(float (*to)[3],
add_v3_v3v3(to[i], fLongVectorA[i], fLongVectorB[i]);
}
}
-/* A = B + C * float --> for big vector */
+/* `A = B + C * float` -> for big vector. */
DO_INLINE void add_lfvector_lfvectorS(float (*to)[3],
float (*fLongVectorA)[3],
float (*fLongVectorB)[3],
@@ -234,7 +234,7 @@ DO_INLINE void add_lfvector_lfvectorS(float (*to)[3],
VECADDS(to[i], fLongVectorA[i], fLongVectorB[i], bS);
}
}
-/* A = B * float + C * float --> for big vector */
+/* `A = B * float + C * float` -> for big vector */
DO_INLINE void add_lfvectorS_lfvectorS(float (*to)[3],
float (*fLongVectorA)[3],
float aS,
@@ -248,7 +248,7 @@ DO_INLINE void add_lfvectorS_lfvectorS(float (*to)[3],
VECADDSS(to[i], fLongVectorA[i], aS, fLongVectorB[i], bS);
}
}
-/* A = B - C * float --> for big vector */
+/* `A = B - C * float` -> for big vector. */
DO_INLINE void sub_lfvector_lfvectorS(float (*to)[3],
float (*fLongVectorA)[3],
float (*fLongVectorB)[3],
@@ -260,7 +260,7 @@ DO_INLINE void sub_lfvector_lfvectorS(float (*to)[3],
VECSUBS(to[i], fLongVectorA[i], fLongVectorB[i], bS);
}
}
-/* A = B - C --> for big vector */
+/* `A = B - C` -> for big vector. */
DO_INLINE void sub_lfvector_lfvector(float (*to)[3],
float (*fLongVectorA)[3],
float (*fLongVectorB)[3],
@@ -455,7 +455,7 @@ DO_INLINE void add_fmatrix_fmatrix(float to[3][3],
add_v3_v3v3(to[1], matrixA[1], matrixB[1]);
add_v3_v3v3(to[2], matrixA[2], matrixB[2]);
}
-/* A -= B*x + C*y (3x3 matrix sub-addition with 3x3 matrix) */
+/* `A -= B*x + (C * y)` (3x3 matrix sub-addition with 3x3 matrix). */
DO_INLINE void subadd_fmatrixS_fmatrixS(
float to[3][3], const float matrixA[3][3], float aS, const float matrixB[3][3], float bS)
{
@@ -463,7 +463,7 @@ DO_INLINE void subadd_fmatrixS_fmatrixS(
VECSUBADDSS(to[1], matrixA[1], aS, matrixB[1], bS);
VECSUBADDSS(to[2], matrixA[2], aS, matrixB[2], bS);
}
-/* A = B - C (3x3 matrix subtraction with 3x3 matrix) */
+/* `A = B - C` (3x3 matrix subtraction with 3x3 matrix). */
DO_INLINE void sub_fmatrix_fmatrix(float to[3][3],
const float matrixA[3][3],
const float matrixB[3][3])
@@ -1439,7 +1439,7 @@ void SIM_mass_spring_force_drag(Implicit_Data *data, float drag)
for (i = 0; i < numverts; i++) {
float tmp[3][3];
- /* NB: uses root space velocity, no need to transform */
+ /* NOTE: Uses root space velocity, no need to transform. */
madd_v3_v3fl(data->F[i], data->V[i], -drag);
copy_m3_m3(tmp, I);
@@ -1683,8 +1683,8 @@ BLI_INLINE void dfdx_damp(float to[3][3],
float rest,
float damping)
{
- /* inner spring damping vel is the relative velocity of the endpoints. */
- // return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest)));
+ /* Inner spring damping `vel` is the relative velocity of the endpoints. */
+ // return (I - outerprod(dir, dir)) * (-damping * -(dot(dir, vel) / Max(length, rest)));
mul_fvectorT_fvector(to, dir, dir);
sub_fmatrix_fmatrix(to, I, to);
mul_fmatrix_S(to, (-damping * -(dot_v3v3(dir, vel) / MAX2(length, rest))));
diff --git a/source/blender/simulation/intern/implicit_eigen.cpp b/source/blender/simulation/intern/implicit_eigen.cpp
index aa9d5d1d34d..d509b3db873 100644
--- a/source/blender/simulation/intern/implicit_eigen.cpp
+++ b/source/blender/simulation/intern/implicit_eigen.cpp
@@ -797,7 +797,7 @@ void SIM_mass_spring_force_drag(Implicit_Data *data, float drag)
for (int i = 0; i < numverts; i++) {
float tmp[3][3];
- /* NB: uses root space velocity, no need to transform */
+ /* NOTE: Uses root space velocity, no need to transform. */
madd_v3_v3fl(data->F.v3(i), data->V.v3(i), -drag);
copy_m3_m3(tmp, I);
@@ -894,8 +894,8 @@ BLI_INLINE void dfdx_damp(float to[3][3],
float rest,
float damping)
{
- /* inner spring damping vel is the relative velocity of the endpoints. */
- // return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest)));
+ /* Inner spring damping vel is the relative velocity of the endpoints. */
+ // return (I - outerprod(dir, dir)) * (-damping * -(dot(dir, vel) / Max(length, rest)));
mul_fvectorT_fvector(to, dir, dir);
sub_fmatrix_fmatrix(to, I, to);
mul_fmatrix_S(to, (-damping * -(dot_v3v3(dir, vel) / MAX2(length, rest))));
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 2b48a5f6648..cc8fb307c92 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -924,10 +924,10 @@ typedef struct wmDragID {
} wmDragID;
typedef struct wmDragAsset {
- char name[64]; /* MAX_NAME */
+ /* Owning pointer. Contains the file with all the asset data (name, local ID, etc.) */
+ struct AssetHandle *asset_handle;
/* Always freed. */
const char *path;
- int id_type;
int import_type; /* eFileAssetImportType */
} wmDragAsset;
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index 6a328679c2e..5ec26a7b208 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -91,7 +91,7 @@ enum {
/* -------------------------------------------------------------------- */
/** \name wmGizmoMap Selection Array API
*
- * Just handle ``wm_gizmomap_select_array_*``, not flags or callbacks.
+ * Just handle `wm_gizmomap_select_array_*`, not flags or callbacks.
*
* \{ */
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index da40040ce56..319e83f667f 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -42,6 +42,8 @@
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "ED_asset.h"
+
#include "GPU_shader.h"
#include "GPU_state.h"
#include "GPU_viewport.h"
@@ -196,6 +198,7 @@ void WM_drag_data_free(int dragtype, void *poin)
/* Not too nice, could become a callback. */
if (dragtype == WM_DRAG_ASSET) {
wmDragAsset *asset_drag = poin;
+ MEM_SAFE_FREE(asset_drag->asset_handle);
MEM_freeN((void *)asset_drag->path);
}
MEM_freeN(poin);
@@ -373,18 +376,20 @@ wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode)
}
wmDragAsset *asset_drag = drag->poin;
- return (ELEM(idcode, 0, asset_drag->id_type)) ? asset_drag : NULL;
+ ID_Type idtype = ED_asset_handle_get_id_type(asset_drag->asset_handle);
+ return (ELEM(idcode, 0, (int)idtype)) ? asset_drag : NULL;
}
static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
{
+ const char *name = ED_asset_handle_get_name(asset_drag->asset_handle);
+ ID_Type idtype = ED_asset_handle_get_id_type(asset_drag->asset_handle);
+
switch ((eFileAssetImportType)asset_drag->import_type) {
case FILE_ASSET_IMPORT_LINK:
- return WM_file_link_datablock(
- G_MAIN, NULL, NULL, NULL, asset_drag->path, asset_drag->id_type, asset_drag->name);
+ return WM_file_link_datablock(G_MAIN, NULL, NULL, NULL, asset_drag->path, idtype, name);
case FILE_ASSET_IMPORT_APPEND:
- return WM_file_append_datablock(
- G_MAIN, NULL, NULL, NULL, asset_drag->path, asset_drag->id_type, asset_drag->name);
+ return WM_file_append_datablock(G_MAIN, NULL, NULL, NULL, asset_drag->path, idtype, name);
}
BLI_assert_unreachable();
@@ -444,7 +449,8 @@ void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox *
return;
}
- ID *id = BKE_libblock_find_name(bmain, asset_drag->id_type, name);
+ ID_Type idtype = ED_asset_handle_get_id_type(asset_drag->asset_handle);
+ ID *id = BKE_libblock_find_name(bmain, idtype, name);
if (id) {
BKE_id_delete(bmain, id);
}
@@ -478,7 +484,7 @@ static const char *wm_drag_name(wmDrag *drag)
}
case WM_DRAG_ASSET: {
const wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0);
- return asset_drag->name;
+ return ED_asset_handle_get_name(asset_drag->asset_handle);
}
case WM_DRAG_PATH:
case WM_DRAG_NAME:
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 0922aaaee53..f01e28f8822 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -457,6 +457,7 @@ static void wm_draw_region_buffer_create(ARegion *region, bool stereo, bool use_
GPUOffScreen *offscreen = GPU_offscreen_create(
region->winx, region->winy, false, false, NULL);
if (!offscreen) {
+ WM_report(RPT_ERROR, "Region could not be drawn!");
return;
}
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
index e7603a02cff..006dc220a56 100644
--- a/source/blender/windowmanager/intern/wm_event_query.c
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -85,10 +85,10 @@ void WM_event_print(const wmEvent *event)
event_ids_from_type_and_value(event->prevtype, event->prevval, &prev_type_id, &prev_val_id);
printf(
- "wmEvent type:%d / %s, val:%d / %s,\n"
- " prev_type:%d / %s, prev_val:%d / %s,\n"
- " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, is_repeat:%d,\n"
- " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n",
+ "wmEvent type:%d / %s, val:%d / %s,\n"
+ " prev_type:%d / %s, prev_val:%d / %s,\n"
+ " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, is_repeat:%d,\n"
+ " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n",
event->type,
type_id,
event->val,
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 3633d3c07d3..06aaf95f232 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -987,7 +987,7 @@ const char *WM_init_state_app_template_get(void)
* or called for 'New File' both startup.blend and userpref.blend are checked.
*
* \param use_factory_settings:
- * Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead.
+ * Ignore on-disk startup file, use bundled `datatoc_startup_blend` instead.
* Used for "Restore Factory Settings".
*
* \param use_userdef: Load factory settings as well as startup file.
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index 9da901d6c4e..92ca0b87527 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -23,8 +23,8 @@
* Default operator callbacks for use with gestures (border/circle/lasso/straightline).
* Operators themselves are defined elsewhere.
*
- * - Keymaps are in ``wm_operators.c``.
- * - Property definitions are in ``wm_operator_props.c``.
+ * - Keymaps are in `wm_operators.c`.
+ * - Property definitions are in `wm_operator_props.c`.
*/
#include "MEM_guardedalloc.h"
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index b0b4f0f5904..795f78e215f 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -207,7 +207,7 @@ wmKeyMap *WM_keymap_guess_from_context(const bContext *C)
/* Needs to be kept up to date with Keymap and Operator naming */
wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
{
- /* Op types purposely skipped for now:
+ /* Op types purposely skipped for now:
* BRUSH_OT
* BOID_OT
* BUTTONS_OT
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index e17d5a9ae70..39435721d1a 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -498,12 +498,11 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname,
ot->cancel = wm_macro_cancel;
ot->poll = NULL;
- if (!ot->description) {
- /* XXX All ops should have a description but for now allow them not to. */
- ot->description = UNDOCUMENTED_OPERATOR_TIP;
- }
+ /* XXX All ops should have a description but for now allow them not to. */
+ BLI_assert((ot->description == NULL) || (ot->description[0]));
- RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
+ RNA_def_struct_ui_text(
+ ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
/* Use i18n context from rna_ext.srna if possible (py operators). */
i18n_context = ot->rna_ext.srna ? RNA_struct_translation_context(ot->rna_ext.srna) :
@@ -530,16 +529,16 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *),
ot->cancel = wm_macro_cancel;
ot->poll = NULL;
- if (!ot->description) {
- ot->description = UNDOCUMENTED_OPERATOR_TIP;
- }
+ /* XXX All ops should have a description but for now allow them not to. */
+ BLI_assert((ot->description == NULL) || (ot->description[0]));
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
opfunc(ot, userdata);
- RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
+ RNA_def_struct_ui_text(
+ ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
diff --git a/source/blender/windowmanager/wm_surface.h b/source/blender/windowmanager/wm_surface.h
index 06c29231361..36d74f612fc 100644
--- a/source/blender/windowmanager/wm_surface.h
+++ b/source/blender/windowmanager/wm_surface.h
@@ -42,9 +42,9 @@ typedef struct wmSurface {
/** Free customdata, not the surface itself (done by wm_surface API) */
void (*free_data)(struct wmSurface *);
- /** Called when surface is activated for drawing (made drawable). */
+ /** Called when surface is activated for drawing (made drawable). */
void (*activate)(void);
- /** Called when surface is deactivated for drawing (current drawable cleared). */
+ /** Called when surface is deactivated for drawing (current drawable cleared). */
void (*deactivate)(void);
} wmSurface;
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
index 1f722855696..4ac05e339b9 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
@@ -24,6 +24,7 @@
#include <string.h>
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "ED_view3d_offscreen.h"
@@ -61,10 +62,12 @@ static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat);
copy_v3_v3(eye_pose.position, draw_view->eye_pose.position);
- sub_v3_v3(eye_pose.position, draw_data->eye_position_ofs);
if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
sub_v3_v3(eye_pose.position, draw_view->local_pose.position);
}
+ if ((session_settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
+ sub_v3_v3(eye_pose.position, draw_data->eye_position_ofs);
+ }
perspective_m4_fov(r_proj_mat,
draw_view->fov.angle_left,
@@ -89,6 +92,9 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer(
const wmXrSurfaceData *surface_data,
const GHOST_XrDrawViewInfo *draw_view)
{
+ const wmXrViewportPair *vp = BLI_findlink(&surface_data->viewports, draw_view->view_idx);
+ BLI_assert(vp && vp->viewport);
+
const bool is_upside_down = GHOST_XrSessionNeedsUpsideDownDrawing(runtime_data->context);
rcti rect = {.xmin = 0, .ymin = 0, .xmax = draw_view->width - 1, .ymax = draw_view->height - 1};
@@ -98,8 +104,7 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer(
if (is_upside_down) {
SWAP(int, rect.ymin, rect.ymax);
}
- GPU_viewport_draw_to_screen_ex(
- surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer, true);
+ GPU_viewport_draw_to_screen_ex(vp->viewport, 0, &rect, draw_view->expects_srgb_buffer, true);
}
/**
@@ -130,6 +135,9 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
return;
}
+ const wmXrViewportPair *vp = BLI_findlink(&surface_data->viewports, draw_view->view_idx);
+ BLI_assert(vp && vp->offscreen && vp->viewport);
+
/* In case a framebuffer is still bound from drawing the last eye. */
GPU_framebuffer_restore();
/* Some systems have drawing glitches without this. */
@@ -151,8 +159,8 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
true,
NULL,
false,
- surface_data->offscreen,
- surface_data->viewport);
+ vp->offscreen,
+ vp->viewport);
/* The draw-manager uses both GPUOffscreen and GPUViewport to manage frame and texture buffers. A
* call to GPU_viewport_draw_to_screen() is still needed to get the final result from the
@@ -162,7 +170,7 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
* In a next step, Ghost-XR will use the currently bound frame-buffer to retrieve the image
* to be submitted to the OpenXR swap-chain. So do not un-bind the off-screen yet! */
- GPU_offscreen_bind(surface_data->offscreen, false);
+ GPU_offscreen_bind(vp->offscreen, false);
wm_xr_draw_viewport_buffers_to_active_framebuffer(xr_data->runtime, surface_data, draw_view);
}
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
index 9bf63be61dd..24582388228 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h
+++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
@@ -85,9 +85,15 @@ typedef struct wmXrRuntimeData {
wmXrSessionExitFn exit_fn;
} wmXrRuntimeData;
-typedef struct {
+typedef struct wmXrViewportPair {
+ struct wmXrViewportPair *next, *prev;
struct GPUOffScreen *offscreen;
struct GPUViewport *viewport;
+} wmXrViewportPair;
+
+typedef struct {
+ /* Offscreen buffers/viewports for each view. */
+ ListBase viewports; /* wmXrViewportPair */
} wmXrSurfaceData;
typedef struct wmXrDrawData {
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index 1ddbe228e05..252f358c798 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -225,7 +225,7 @@ typedef enum wmXrSessionStateEvent {
SESSION_STATE_EVENT_NONE = 0,
SESSION_STATE_EVENT_START,
SESSION_STATE_EVENT_RESET_TO_BASE_POSE,
- SESSION_STATE_EVENT_POSITON_TRACKING_TOGGLE,
+ SESSION_STATE_EVENT_POSITION_TRACKING_TOGGLE,
} wmXrSessionStateEvent;
static bool wm_xr_session_draw_data_needs_reset_to_base_pose(const wmXrSessionState *state,
@@ -253,7 +253,7 @@ static wmXrSessionStateEvent wm_xr_session_state_to_event(const wmXrSessionState
XR_SESSION_USE_POSITION_TRACKING) !=
(settings->flag & XR_SESSION_USE_POSITION_TRACKING));
if (position_tracking_toggled) {
- return SESSION_STATE_EVENT_POSITON_TRACKING_TOGGLE;
+ return SESSION_STATE_EVENT_POSITION_TRACKING_TOGGLE;
}
return SESSION_STATE_EVENT_NONE;
@@ -288,7 +288,7 @@ void wm_xr_session_draw_data_update(const wmXrSessionState *state,
copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
}
break;
- case SESSION_STATE_EVENT_POSITON_TRACKING_TOGGLE:
+ case SESSION_STATE_EVENT_POSITION_TRACKING_TOGGLE:
if (use_position_tracking) {
/* Keep the current position, and let the user move from there. */
copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs);
@@ -317,6 +317,7 @@ void wm_xr_session_state_update(const XrSessionSettings *settings,
{
GHOST_XrPose viewer_pose;
const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING;
+ const bool use_absolute_tracking = settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING;
mul_qt_qtqt(viewer_pose.orientation_quat,
draw_data->base_pose.orientation_quat,
@@ -324,14 +325,16 @@ void wm_xr_session_state_update(const XrSessionSettings *settings,
copy_v3_v3(viewer_pose.position, draw_data->base_pose.position);
/* The local pose and the eye pose (which is copied from an earlier local pose) both are view
* space, so Y-up. In this case we need them in regular Z-up. */
- viewer_pose.position[0] -= draw_data->eye_position_ofs[0];
- viewer_pose.position[1] += draw_data->eye_position_ofs[2];
- viewer_pose.position[2] -= draw_data->eye_position_ofs[1];
if (use_position_tracking) {
viewer_pose.position[0] += draw_view->local_pose.position[0];
viewer_pose.position[1] -= draw_view->local_pose.position[2];
viewer_pose.position[2] += draw_view->local_pose.position[1];
}
+ if (!use_absolute_tracking) {
+ viewer_pose.position[0] -= draw_data->eye_position_ofs[0];
+ viewer_pose.position[1] += draw_data->eye_position_ofs[2];
+ viewer_pose.position[2] -= draw_data->eye_position_ofs[1];
+ }
copy_v3_v3(state->viewer_pose.position, viewer_pose.position);
copy_qt_qt(state->viewer_pose.orientation_quat, viewer_pose.orientation_quat);
@@ -451,9 +454,14 @@ static void wm_xr_session_controller_mats_update(const XrSessionSettings *settin
float base_inv[4][4];
float tmp[4][4];
- zero_v3(view_ofs);
if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
- add_v3_v3(view_ofs, state->prev_local_pose.position);
+ copy_v3_v3(view_ofs, state->prev_local_pose.position);
+ }
+ else {
+ zero_v3(view_ofs);
+ }
+ if ((settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
+ add_v3_v3(view_ofs, state->prev_eye_position_ofs);
}
wm_xr_pose_to_viewmat(&state->prev_base_pose, base_inv);
@@ -538,7 +546,6 @@ void wm_xr_session_controller_data_clear(wmXrSessionState *state)
*/
static void wm_xr_session_surface_draw(bContext *C)
{
- wmXrSurfaceData *surface_data = g_xr_surface->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
Main *bmain = CTX_data_main(C);
wmXrDrawData draw_data;
@@ -554,38 +561,50 @@ static void wm_xr_session_surface_draw(bContext *C)
GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data);
- GPU_offscreen_unbind(surface_data->offscreen, false);
+ GPU_framebuffer_restore();
}
bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data,
const GHOST_XrDrawViewInfo *draw_view)
{
- const bool size_changed = surface_data->offscreen &&
- (GPU_offscreen_width(surface_data->offscreen) != draw_view->width) &&
- (GPU_offscreen_height(surface_data->offscreen) != draw_view->height);
+ wmXrViewportPair *vp = NULL;
+ if (draw_view->view_idx >= BLI_listbase_count(&surface_data->viewports)) {
+ vp = MEM_callocN(sizeof(*vp), __func__);
+ BLI_addtail(&surface_data->viewports, vp);
+ }
+ else {
+ vp = BLI_findlink(&surface_data->viewports, draw_view->view_idx);
+ }
+ BLI_assert(vp);
+
+ GPUOffScreen *offscreen = vp->offscreen;
+ GPUViewport *viewport = vp->viewport;
+ const bool size_changed = offscreen && (GPU_offscreen_width(offscreen) != draw_view->width) &&
+ (GPU_offscreen_height(offscreen) != draw_view->height);
char err_out[256] = "unknown";
bool failure = false;
- if (surface_data->offscreen) {
- BLI_assert(surface_data->viewport);
+ if (offscreen) {
+ BLI_assert(viewport);
if (!size_changed) {
return true;
}
- GPU_viewport_free(surface_data->viewport);
- GPU_offscreen_free(surface_data->offscreen);
- }
-
- if (!(surface_data->offscreen = GPU_offscreen_create(
- draw_view->width, draw_view->height, true, false, err_out))) {
- failure = true;
- }
-
- if (failure) {
- /* Pass. */
+ GPU_viewport_free(viewport);
+ GPU_offscreen_free(offscreen);
+ }
+
+ offscreen = vp->offscreen = GPU_offscreen_create(
+ draw_view->width, draw_view->height, true, false, err_out);
+ if (offscreen) {
+ viewport = vp->viewport = GPU_viewport_create();
+ if (!viewport) {
+ GPU_offscreen_free(offscreen);
+ offscreen = vp->offscreen = NULL;
+ failure = true;
+ }
}
- else if (!(surface_data->viewport = GPU_viewport_create())) {
- GPU_offscreen_free(surface_data->offscreen);
+ else {
failure = true;
}
@@ -600,12 +619,17 @@ bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data,
static void wm_xr_session_surface_free_data(wmSurface *surface)
{
wmXrSurfaceData *data = surface->customdata;
+ ListBase *lb = &data->viewports;
+ wmXrViewportPair *vp;
- if (data->viewport) {
- GPU_viewport_free(data->viewport);
- }
- if (data->offscreen) {
- GPU_offscreen_free(data->offscreen);
+ while ((vp = BLI_pophead(lb))) {
+ if (vp->viewport) {
+ GPU_viewport_free(vp->viewport);
+ }
+ if (vp->offscreen) {
+ GPU_offscreen_free(vp->offscreen);
+ }
+ BLI_freelinkN(lb, vp);
}
MEM_freeN(surface->customdata);
diff --git a/source/tools b/source/tools
-Subproject 01f51a0e551ab730f0934dc6488613690ac4bf8
+Subproject c8579c5cf43229843df505da9644b5b0b720197
diff --git a/tests/performance/api/config.py b/tests/performance/api/config.py
index 68f4df8d487..d3a79eede14 100644
--- a/tests/performance/api/config.py
+++ b/tests/performance/api/config.py
@@ -31,6 +31,7 @@ class TestEntry:
device_id: str = 'CPU'
device_name: str = 'Unknown CPU'
status: str = 'queued'
+ error_msg: str = ''
output: Dict = field(default_factory=dict)
benchmark_type: str = 'comparison'
@@ -42,7 +43,8 @@ class TestEntry:
def from_json(self, json_dict):
for field in self.__dataclass_fields__:
- setattr(self, field, json_dict[field])
+ if field in json_dict:
+ setattr(self, field, json_dict[field])
class TestQueue:
@@ -112,7 +114,7 @@ class TestConfig:
self.base_dir = env.base_dir / name
self.logs_dir = self.base_dir / 'logs'
- config = self._read_config_module()
+ config = TestConfig._read_config_module(self.base_dir)
self.tests = TestCollection(env,
getattr(config, 'tests', ['*']),
getattr(config, 'categories', ['*']))
@@ -154,10 +156,17 @@ class TestConfig:
with open(config_file, 'w') as f:
f.write(default_config)
- def _read_config_module(self) -> None:
+ @staticmethod
+ def read_blender_executables(env, name) -> List:
+ config = TestConfig._read_config_module(env.base_dir / name)
+ builds = getattr(config, 'builds', {})
+ return [pathlib.Path(build) for build in builds.values()]
+
+ @staticmethod
+ def _read_config_module(base_dir: pathlib.Path) -> None:
# Import config.py as a module.
import importlib.util
- spec = importlib.util.spec_from_file_location("testconfig", self.base_dir / 'config.py')
+ spec = importlib.util.spec_from_file_location("testconfig", base_dir / 'config.py')
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod
@@ -195,14 +204,14 @@ class TestConfig:
# Get entries for revisions based on existing builds.
for revision_name, executable in self.builds.items():
- executable_path = pathlib.Path(executable)
- if not executable_path.exists():
+ executable_path = env._blender_executable_from_path(pathlib.Path(executable))
+ if not executable_path:
sys.stderr.write(f'Error: build {executable} not found\n')
sys.exit(1)
env.set_blender_executable(executable_path)
git_hash, _ = env.run_in_blender(get_build_hash, {})
- env.unset_blender_executable()
+ env.set_default_blender_executable()
mtime = executable_path.stat().st_mtime
entries += self._get_entries(revision_name, git_hash, executable, mtime)
diff --git a/tests/performance/api/environment.py b/tests/performance/api/environment.py
index c9ddd493394..3a9b3eaf936 100644
--- a/tests/performance/api/environment.py
+++ b/tests/performance/api/environment.py
@@ -27,9 +27,10 @@ class TestEnvironment:
self.git_executable = 'git'
self.cmake_executable = 'cmake'
self.cmake_options = ['-DWITH_INTERNATIONAL=OFF', '-DWITH_BUILDINFO=OFF']
- self.unset_blender_executable()
self.log_file = None
self.machine = None
+ self._init_default_blender_executable()
+ self.set_default_blender_executable()
def get_machine(self, need_gpus: bool=True) -> None:
if not self.machine or (need_gpus and not self.machine.has_gpus):
@@ -46,7 +47,7 @@ class TestEnvironment:
print(f'Init {self.base_dir}')
self.base_dir.mkdir(parents=True, exist_ok=True)
- if len(self.get_configs(names_only=True)) == 0:
+ if len(self.get_configs_names()) == 0:
config_dir = self.base_dir / 'default'
print(f'Creating default configuration in {config_dir}')
TestConfig.write_default_config(self, config_dir)
@@ -77,7 +78,7 @@ class TestEnvironment:
print('Done')
- def checkout(self) -> None:
+ def checkout(self, git_hash) -> None:
# Checkout Blender revision
if not self.blender_dir.exists():
sys.stderr.write('\n\nError: no build set up, run `./benchmark init --build` first\n')
@@ -87,32 +88,68 @@ class TestEnvironment:
self.call([self.git_executable, 'reset', '--hard', 'HEAD'], self.blender_dir)
self.call([self.git_executable, 'checkout', '--detach', git_hash], self.blender_dir)
- self.build()
-
- def build(self) -> None:
+ def build(self) -> bool:
# Build Blender revision
if not self.build_dir.exists():
sys.stderr.write('\n\nError: no build set up, run `./benchmark init --build` first\n')
sys.exit(1)
jobs = str(multiprocessing.cpu_count())
- self.call([self.cmake_executable, '.'] + self.cmake_options, self.build_dir)
- self.call([self.cmake_executable, '--build', '.', '-j', jobs, '--target', 'install'], self.build_dir)
+ try:
+ self.call([self.cmake_executable, '.'] + self.cmake_options, self.build_dir)
+ self.call([self.cmake_executable, '--build', '.', '-j', jobs, '--target', 'install'], self.build_dir)
+ except:
+ return False
+
+ self._init_default_blender_executable()
+ return True
def set_blender_executable(self, executable_path: pathlib.Path) -> None:
# Run all Blender commands with this executable.
self.blender_executable = executable_path
- def unset_blender_executable(self) -> None:
+ def _blender_executable_name(self) -> pathlib.Path:
if platform.system() == "Windows":
- self.blender_executable = self.build_dir / 'bin' / 'blender.exe'
+ return pathlib.Path('blender.exe')
elif platform.system() == "Darwin":
- self.blender_executable = self.build_dir / 'bin' / 'Blender.app' / 'Contents' / 'MacOS' / 'Blender'
+ return pathlib.Path('Blender.app') / 'Contents' / 'MacOS' / 'Blender'
else:
- self.blender_executable = self.build_dir / 'bin' / 'blender'
-
- if not self.blender_executable.exists():
- self.blender_executable = 'blender'
+ return pathlib.Path('blender')
+
+ def _blender_executable_from_path(self, executable: pathlib.Path) -> pathlib.Path:
+ if executable.is_dir():
+ # Directory
+ executable = executable / self._blender_executable_name()
+ elif not executable.is_file() and executable.name == 'blender':
+ # Executable path without proper path on Windows or macOS.
+ executable = executable.parent() / self._blender_executable_name()
+
+ if executable.is_file():
+ return executable
+
+ return None
+
+ def _init_default_blender_executable(self) -> None:
+ # Find a default executable to run commands independent of testing a specific build.
+ # Try own built executable.
+ built_executable = self._blender_executable_from_path(self.build_dir / 'bin')
+ if built_executable:
+ self.default_blender_executable = built_executable
+ return
+
+ # Try find an executable in the configs.
+ for config_name in self.get_config_names():
+ for executable in TestConfig.read_blender_executables(self, config_name):
+ executable = self._blender_executable_from_path(executable)
+ if executable:
+ self.default_blender_executable = executable
+ return
+
+ # Fallback to a "blender" command in the hope it's available.
+ self.default_blender_executable = pathlib.Path("blender")
+
+ def set_default_blender_executable(self) -> None:
+ self.blender_executable = self.default_blender_executable
def set_log_file(self, filepath: pathlib.Path, clear=True) -> None:
# Log all commands and output to this file.
@@ -219,26 +256,36 @@ class TestEnvironment:
filepaths.append(pathlib.Path(filename))
return filepaths
+ def get_config_names(self) -> List:
+ names = []
+
+ if self.base_dir.exists():
+ for dirname in os.listdir(self.base_dir):
+ dirpath = self.base_dir / dirname / 'config.py'
+ if dirpath.exists():
+ names.append(dirname)
+
+ return names
+
def get_configs(self, name: str=None, names_only: bool=False) -> List:
# Get list of configurations in the benchmarks directory.
configs = []
- if self.base_dir.exists():
- for dirname in os.listdir(self.base_dir):
- if not name or dirname == name:
- dirpath = self.base_dir / dirname / 'config.py'
- if dirpath.exists():
- if names_only:
- configs.append(dirname)
- else:
- configs.append(TestConfig(self, dirname))
+ for config_name in self.get_config_names():
+ if not name or config_name == name:
+ if names_only:
+ configs.append(config_name)
+ else:
+ configs.append(TestConfig(self, config_name))
return configs
def resolve_git_hash(self, revision):
# Get git hash for a tag or branch.
- return self.call([self.git_executable, 'rev-parse', revision], self.blender_git_dir)[0].strip()
+ lines = self.call([self.git_executable, 'rev-parse', revision], self.blender_git_dir)
+ return lines[0].strip() if len(lines) else revision
def git_hash_date(self, git_hash):
# Get commit data for a git hash.
- return int(self.call([self.git_executable, 'log', '-n1', git_hash, '--format=%at'], self.blender_git_dir)[0].strip())
+ lines = self.call([self.git_executable, 'log', '-n1', git_hash, '--format=%at'], self.blender_git_dir)
+ return int(lines[0].strip()) if len(lines) else 0
diff --git a/tests/performance/api/graph.py b/tests/performance/api/graph.py
index b3c8329ff27..4ee5ae7cf0e 100644
--- a/tests/performance/api/graph.py
+++ b/tests/performance/api/graph.py
@@ -30,6 +30,7 @@ class TestGraph:
data = []
for device_name, device_entries in devices.items():
+
# Gather used categories.
categories = {}
for entry in device_entries:
@@ -57,6 +58,8 @@ class TestGraph:
self.json = json.dumps(data, indent=2)
def chart(self, device_name: str, chart_name: str, entries: List, chart_type: str, output: str) -> Dict:
+ entries = sorted(entries, key=lambda entry: entry.date)
+
# Gather used tests.
tests = {}
for entry in entries:
diff --git a/tests/performance/benchmark b/tests/performance/benchmark
index 3b43bd0aa96..eb01b6053a7 100755
--- a/tests/performance/benchmark
+++ b/tests/performance/benchmark
@@ -66,6 +66,8 @@ def print_row(config: api.TestConfig, entries: List, end='\n') -> None:
if status == 'outdated':
result += " (outdated)"
+ elif status == 'failed':
+ result = "failed: " + entry.error_msg
else:
result = status
@@ -105,20 +107,37 @@ def run_entry(env: api.TestEnvironment, config: api.TestConfig, row: List, entry
logname += '_' + device_id
env.set_log_file(config.logs_dir / (logname + '.log'), clear=True)
+ # Clear output
+ entry.output = None
+ entry.error_msg = ''
+
# Build revision, or just set path to existing executable.
entry.status = 'building'
print_row(config, row, end='\r')
+ executable_ok = True
if len(entry.executable):
env.set_blender_executable(pathlib.Path(entry.executable))
else:
env.checkout(git_hash)
- env.build(git_hash)
+ executable_ok = env.build()
+ if not executable_ok:
+ entry.status = 'failed'
+ entry.error_msg = 'Failed to build'
# Run test and update output and status.
entry.status = 'running'
print_row(config, row, end='\r')
- entry.output = test.run(env, device_id)
- entry.status = 'done' if entry.output else 'failed'
+
+ if executable_ok:
+ try:
+ entry.output = test.run(env, device_id)
+ if not entry.output:
+ raise Exception("Test produced no output")
+ entry.status = 'done'
+ except Exception as e:
+ entry.status = 'failed'
+ entry.error_msg = str(e)
+
print_row(config, row, end='\r')
# Update device name in case the device changed since the entry was created.
@@ -126,7 +145,7 @@ def run_entry(env: api.TestEnvironment, config: api.TestConfig, row: List, entry
# Restore default logging and Blender executable.
env.unset_log_file()
- env.unset_blender_executable()
+ env.set_default_blender_executable()
return True
@@ -155,7 +174,7 @@ def cmd_list(env: api.TestEnvironment, argv: List) -> None:
print('')
print('CONFIGS')
- configs = env.get_configs(names_only=True)
+ configs = env.get_config_names()
for config_name in configs:
print(config_name)