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:
authorJulian Eisel <julian@blender.org>2022-05-27 12:33:26 +0300
committerJulian Eisel <julian@blender.org>2022-05-27 12:33:26 +0300
commite1ced645fa208b3b77e07c99cb289cf7fa659ad3 (patch)
tree60f5d3478007bb1fbb5c09425c32f256dfab74d6
parent3f7015a79f09783bc560dce109fbd3eed6f6aa2a (diff)
parent5162632a209176350cc951a1783b3b010c910acd (diff)
Merge branch 'asset-browser-grid-view' into file-browser-grid-view
-rw-r--r--CMakeLists.txt1
-rw-r--r--doc/python_api/sphinx_doc_gen.py653
-rw-r--r--intern/atomic/atomic_ops.h10
-rw-r--r--intern/atomic/intern/atomic_ops_ext.h18
-rw-r--r--intern/atomic/intern/atomic_ops_msvc.h53
-rw-r--r--intern/atomic/intern/atomic_ops_unix.h131
-rw-r--r--intern/atomic/tests/atomic_test.cc170
-rw-r--r--intern/cycles/blender/volume.cpp22
-rw-r--r--intern/cycles/device/cuda/device_impl.cpp4
-rw-r--r--intern/cycles/device/hip/device_impl.cpp4
-rw-r--r--intern/cycles/device/memory.cpp2
-rw-r--r--intern/cycles/kernel/device/cpu/image.h10
-rw-r--r--intern/cycles/kernel/device/gpu/image.h13
-rw-r--r--intern/cycles/kernel/device/gpu/kernel.h10
-rw-r--r--intern/cycles/kernel/film/adaptive_sampling.h8
-rw-r--r--intern/cycles/kernel/integrator/init_from_bake.h2
-rw-r--r--intern/cycles/kernel/svm/blackbody.h1
-rw-r--r--intern/cycles/kernel/svm/math_util.h30
-rw-r--r--intern/cycles/kernel/tables.h39
-rw-r--r--intern/cycles/scene/image.cpp11
-rw-r--r--intern/cycles/scene/image_oiio.cpp2
-rw-r--r--intern/cycles/scene/image_vdb.cpp31
-rw-r--r--intern/cycles/scene/image_vdb.h1
-rw-r--r--intern/cycles/scene/object.cpp6
-rw-r--r--intern/cycles/scene/shader_nodes.cpp2
-rw-r--r--intern/cycles/test/render_graph_finalize_test.cpp2
-rw-r--r--intern/cycles/util/texture.h2
-rw-r--r--intern/ghost/intern/GHOST_Buttons.cpp24
-rw-r--r--intern/ghost/intern/GHOST_Buttons.h4
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.cpp6
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp6
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp79
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h4
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp4
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.cpp15
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp2
-rw-r--r--intern/opencolorio/fallback_impl.cc5
-rw-r--r--intern/opencolorio/ocio_capi.cc4
-rw-r--r--intern/opencolorio/ocio_capi.h16
-rw-r--r--intern/opencolorio/ocio_impl.cc20
-rw-r--r--intern/opencolorio/ocio_impl.h7
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output.h19
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_gpu.cc6
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_gpu.h2
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_capi.cc14
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_impl.cc10
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_impl.h6
-rw-r--r--intern/opensubdiv/opensubdiv_evaluator_capi.h7
-rw-r--r--release/datafiles/blender_icons_geom.py48
-rw-r--r--release/datafiles/icons/brush.gpencil_draw.erase.datbin1052 -> 1052 bytes
-rw-r--r--release/datafiles/icons/brush.paint_texture.multiply.datbin25352 -> 18476 bytes
-rw-r--r--release/datafiles/icons/brush.paint_vertex.replace.datbin2942 -> 2942 bytes
-rw-r--r--release/datafiles/icons/brush.particle.comb.datbin4472 -> 4472 bytes
-rw-r--r--release/datafiles/icons/brush.particle.cut.datbin2456 -> 2456 bytes
-rw-r--r--release/datafiles/icons/brush.particle.puff.datbin1718 -> 1718 bytes
-rw-r--r--release/datafiles/icons/brush.particle.smooth.datbin746 -> 746 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.boundary.datbin7550 -> 7550 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.cloth.datbin3698 -> 3698 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.displacement_eraser.datbin3104 -> 3104 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.displacement_smear.datbin3968 -> 3968 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.draw_face_sets.datbin3266 -> 3266 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.draw_sharp.datbin2492 -> 2492 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.elastic_deform.datbin2564 -> 2564 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.fill.datbin3104 -> 3104 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.flatten.datbin1808 -> 1808 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.grab.datbin1772 -> 1772 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.layer.datbin3068 -> 3068 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.multiplane_scrape.datbin2060 -> 2060 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.nudge.datbin3212 -> 3212 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.pinch.datbin2744 -> 2744 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.pose.datbin1322 -> 1322 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.rotate.datbin7694 -> 7694 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.scrape.datbin4022 -> 4022 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.smooth.datbin4346 -> 4346 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.snake_hook.datbin2492 -> 2492 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.thumb.datbin1610 -> 1610 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.topology.datbin7964 -> 7964 bytes
-rw-r--r--release/datafiles/icons/brush.uv_sculpt.relax.datbin2024 -> 7208 bytes
-rw-r--r--release/datafiles/icons/ops.armature.bone.roll.datbin1646 -> 1646 bytes
-rw-r--r--release/datafiles/icons/ops.curve.pen.datbin3374 -> 3374 bytes
-rw-r--r--release/datafiles/icons/ops.curve.radius.datbin1466 -> 1466 bytes
-rw-r--r--release/datafiles/icons/ops.curve.vertex_random.datbin1412 -> 1412 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_comb.datbin4472 -> 4472 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_cut.datbin2456 -> 2456 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_delete.datbin2060 -> 2060 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_pinch.datbin0 -> 2132 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_puff.datbin1718 -> 1718 bytes
-rw-r--r--release/datafiles/icons/ops.generic.select_box.datbin2312 -> 2312 bytes
-rw-r--r--release/datafiles/icons/ops.generic.select_circle.datbin2564 -> 2564 bytes
-rw-r--r--release/datafiles/icons/ops.generic.select_lasso.datbin2402 -> 2402 bytes
-rw-r--r--release/datafiles/icons/ops.generic.select_paint.datbin1790 -> 1790 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.draw.eraser.datbin1268 -> 1268 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.edit_bend.datbin1664 -> 1664 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.edit_shear.datbin1286 -> 1286 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.edit_to_sphere.datbin2492 -> 152 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.radius.datbin1466 -> 1466 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.stroke_cutter.datbin1916 -> 1916 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.transform_fill.datbin2132 -> 2132 bytes
-rw-r--r--release/datafiles/icons/ops.mesh.rip.datbin944 -> 944 bytes
-rw-r--r--release/datafiles/icons/ops.mesh.rip_edge.datbin890 -> 890 bytes
-rw-r--r--release/datafiles/icons/ops.mesh.vertices_smooth.datbin296 -> 296 bytes
-rw-r--r--release/datafiles/icons/ops.node.links_cut.datbin1628 -> 1628 bytes
-rw-r--r--release/datafiles/icons/ops.pose.push.datbin2384 -> 2384 bytes
-rw-r--r--release/datafiles/icons/ops.pose.relax.datbin1394 -> 1394 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.border_face_set.datbin1142 -> 1142 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.box_trim.datbin1736 -> 1736 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.cloth_filter.datbin5570 -> 5570 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.face_set_edit.datbin1700 -> 1700 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.lasso_face_set.datbin3284 -> 3284 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.lasso_trim.datbin2816 -> 2816 bytes
-rw-r--r--release/datafiles/icons/ops.transform.bone_envelope.datbin1736 -> 1736 bytes
-rw-r--r--release/datafiles/icons/ops.transform.bone_size.datbin1052 -> 1052 bytes
-rw-r--r--release/datafiles/icons/ops.transform.edge_slide.datbin800 -> 800 bytes
-rw-r--r--release/datafiles/icons/ops.transform.push_pull.datbin728 -> 728 bytes
-rw-r--r--release/datafiles/icons/ops.transform.resize.cage.datbin2456 -> 2456 bytes
-rw-r--r--release/datafiles/icons/ops.transform.resize.datbin278 -> 278 bytes
-rw-r--r--release/datafiles/icons/ops.transform.rotate.datbin1664 -> 1664 bytes
-rw-r--r--release/datafiles/icons/ops.transform.shear.datbin206 -> 206 bytes
-rw-r--r--release/datafiles/icons/ops.transform.shrink_fatten.datbin1142 -> 1142 bytes
-rw-r--r--release/datafiles/icons/ops.transform.tilt.datbin5822 -> 5822 bytes
-rw-r--r--release/datafiles/icons/ops.transform.tosphere.datbin1232 -> 1232 bytes
-rw-r--r--release/datafiles/icons/ops.transform.vert_slide.datbin1106 -> 1106 bytes
-rw-r--r--release/datafiles/icons/ops.transform.vertex_random.datbin296 -> 296 bytes
m---------release/datafiles/locale0
m---------release/scripts/addons0
-rw-r--r--release/scripts/modules/rna_info.py20
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py12
-rw-r--r--release/scripts/startup/bl_operators/wm.py60
-rw-r--r--release/scripts/startup/bl_ui/properties_data_volume.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py2
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py5
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py2
-rw-r--r--release/scripts/templates_py/gizmo_operator.py5
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h21
-rw-r--r--source/blender/blenkernel/BKE_deform.h4
-rw-r--r--source/blender/blenkernel/BKE_global.h1
-rw-r--r--source/blender/blenkernel/BKE_image_partial_update.hh5
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h10
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c37
-rw-r--r--source/blender/blenkernel/intern/bvhutils.cc25
-rw-r--r--source/blender/blenkernel/intern/customdata.cc16
-rw-r--r--source/blender/blenkernel/intern/deform.c2
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc8
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc11
-rw-r--r--source/blender/blenkernel/intern/image.cc78
-rw-r--r--source/blender/blenkernel/intern/image_gpu.cc185
-rw-r--r--source/blender/blenkernel/intern/image_save.cc2
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c17
-rw-r--r--source/blender/blenkernel/intern/lib_override.c46
-rw-r--r--source/blender/blenkernel/intern/lib_override_proxy_conversion.c5
-rw-r--r--source/blender/blenkernel/intern/movieclip.c3
-rw-r--r--source/blender/blenkernel/intern/nla.c79
-rw-r--r--source/blender/blenkernel/intern/node_tree_update.cc37
-rw-r--r--source/blender/blenkernel/intern/unit.c2
-rw-r--r--source/blender/blenlib/BLI_array.hh4
-rw-r--r--source/blender/blenlib/BLI_generic_array.hh2
-rw-r--r--source/blender/blenlib/BLI_linear_allocator.hh2
-rw-r--r--source/blender/blenlib/BLI_map.hh4
-rw-r--r--source/blender/blenlib/BLI_math_color.h3
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh24
-rw-r--r--source/blender/blenlib/BLI_set.hh8
-rw-r--r--source/blender/blenlib/BLI_stack.hh4
-rw-r--r--source/blender/blenlib/BLI_utildefines.h12
-rw-r--r--source/blender/blenlib/BLI_vector.hh4
-rw-r--r--source/blender/blenlib/BLI_vector_set.hh4
-rw-r--r--source/blender/blenlib/intern/math_color.c155
-rw-r--r--source/blender/blenloader/intern/versioning_290.c7
-rw-r--r--source/blender/depsgraph/CMakeLists.txt2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc79
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h49
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_stack.cc94
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_stack.h140
-rw-r--r--source/blender/draw/CMakeLists.txt2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders_extra.cc4
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl24
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_vert.glsl26
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.cc1
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl25
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader_shared.h26
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl2
-rw-r--r--source/blender/draw/intern/draw_attributes.cc112
-rw-r--r--source/blender/draw/intern/draw_attributes.h60
-rw-r--r--source/blender/draw/intern/draw_cache.c3
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h15
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc8
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h1
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc226
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c151
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc116
-rw-r--r--source/blender/draw/intern/draw_common.h4
-rw-r--r--source/blender/draw/intern/draw_curves.cc218
-rw-r--r--source/blender/draw/intern/draw_curves_private.h29
-rw-r--r--source/blender/draw/intern/draw_fluid.c4
-rw-r--r--source/blender/draw/intern/draw_manager.c13
-rw-r--r--source/blender/draw/intern/draw_manager.h2
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h14
-rw-r--r--source/blender/draw/intern/draw_subdivision.h5
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc27
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc22
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc7
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc7
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc67
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc18
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc4
-rw-r--r--source/blender/draw/intern/shaders/common_gpencil_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_math_lib.glsl1
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl43
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl41
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_lib.glsl1
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl73
-rw-r--r--source/blender/draw/intern/shaders/draw_object_infos_info.hh4
-rw-r--r--source/blender/editors/animation/anim_markers.c4
-rw-r--r--source/blender/editors/animation/keyframing.c4
-rw-r--r--source/blender/editors/animation/keyingsets.c66
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt1
-rw-r--r--source/blender/editors/include/ED_keyframing.h13
-rw-r--r--source/blender/editors/include/ED_mesh.h10
-rw-r--r--source/blender/editors/include/ED_object.h2
-rw-r--r--source/blender/editors/include/UI_interface.h10
-rw-r--r--source/blender/editors/interface/interface_handlers.c222
-rw-r--r--source/blender/editors/interface/interface_intern.h12
-rw-r--r--source/blender/editors/interface/interface_layout.c41
-rw-r--r--source/blender/editors/interface/interface_ops.c22
-rw-r--r--source/blender/editors/interface/interface_region_color_picker.cc10
-rw-r--r--source/blender/editors/interface/interface_region_search.cc37
-rw-r--r--source/blender/editors/interface/interface_template_attribute_search.cc4
-rw-r--r--source/blender/editors/interface/interface_templates.c27
-rw-r--r--source/blender/editors/interface/interface_utils.cc166
-rw-r--r--source/blender/editors/interface/interface_widgets.c461
-rw-r--r--source/blender/editors/interface/view2d.cc21
-rw-r--r--source/blender/editors/io/io_obj.c8
-rw-r--r--source/blender/editors/mask/mask_add.c4
-rw-r--r--source/blender/editors/mask/mask_query.c4
-rw-r--r--source/blender/editors/mesh/editmesh_add.c18
-rw-r--r--source/blender/editors/mesh/editmesh_add_gizmo.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c486
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c2
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c8
-rw-r--r--source/blender/editors/mesh/mesh_data.cc28
-rw-r--r--source/blender/editors/mesh/mesh_intern.h3
-rw-r--r--source/blender/editors/mesh/meshtools.cc2
-rw-r--r--source/blender/editors/object/object_add.cc108
-rw-r--r--source/blender/editors/object/object_edit.c6
-rw-r--r--source/blender/editors/object/object_modifier.cc1
-rw-r--r--source/blender/editors/object/object_relations.c78
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc9
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_brush.cc27
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_comb.cc17
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_delete.cc76
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc42
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_intern.hh13
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_ops.cc31
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc25
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.cc4
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_expand.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c2
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c3
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_node/node_add.cc130
-rw-r--r--source/blender/editors/space_node/node_edit.cc4
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc4
-rw-r--r--source/blender/editors/space_node/space_node.cc4
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_outliner/outliner_context.cc12
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.cc10
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc551
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc296
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.hh18
-rw-r--r--source/blender/editors/space_outliner/outliner_query.cc48
-rw-r--r--source/blender/editors/space_outliner/outliner_select.cc46
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc296
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.cc4
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.cc3
-rw-r--r--source/blender/editors/space_outliner/space_outliner.cc2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh16
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_libraries.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_scenes.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.cc40
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.hh17
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.cc19
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc24
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.hh4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_iterator.cc58
-rw-r--r--source/blender/editors/space_outliner/tree/tree_iterator.hh35
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c15
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c10
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c17
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c19
-rw-r--r--source/blender/geometry/GEO_uv_parametrizer.h4
-rw-r--r--source/blender/geometry/intern/uv_parametrizer.c143
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c24
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc2
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c10
-rw-r--r--source/blender/gpu/CMakeLists.txt2
-rw-r--r--source/blender/gpu/GPU_capabilities.h2
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc5
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc22
-rw-r--r--source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl23
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl12
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl12
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h43
-rw-r--r--source/blender/imbuf/IMB_imbuf.h3
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h8
-rw-r--r--source/blender/imbuf/intern/colormanagement.c229
-rw-r--r--source/blender/imbuf/intern/colormanagement_inline.c40
-rw-r--r--source/blender/imbuf/intern/util_gpu.c6
-rw-r--r--source/blender/io/usd/CMakeLists.txt2
-rw-r--r--source/blender/io/usd/intern/usd_writer_material.cc9
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h6
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_importer.cc1
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h1
-rw-r--r--source/blender/makesdna/DNA_image_types.h31
-rw-r--r--source/blender/makesdna/DNA_node_types.h2
-rw-r--r--source/blender/makesdna/DNA_volume_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_volume_types.h7
-rw-r--r--source/blender/makesrna/RNA_access.h81
-rw-r--r--source/blender/makesrna/RNA_define.h6
-rw-r--r--source/blender/makesrna/RNA_types.h49
-rw-r--r--source/blender/makesrna/intern/makesrna.c38
-rw-r--r--source/blender/makesrna/intern/rna_ID.c14
-rw-r--r--source/blender/makesrna/intern/rna_access.c89
-rw-r--r--source/blender/makesrna/intern/rna_action.c2
-rw-r--r--source/blender/makesrna/intern/rna_armature.c6
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c4
-rw-r--r--source/blender/makesrna/intern/rna_boid.c12
-rw-r--r--source/blender/makesrna/intern/rna_brush.c2
-rw-r--r--source/blender/makesrna/intern/rna_camera.c2
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c12
-rw-r--r--source/blender/makesrna/intern/rna_color.c12
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c12
-rw-r--r--source/blender/makesrna/intern/rna_curve.c10
-rw-r--r--source/blender/makesrna/intern/rna_curves.c24
-rw-r--r--source/blender/makesrna/intern/rna_define.c39
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c18
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c6
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c33
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c6
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c11
-rw-r--r--source/blender/makesrna/intern/rna_image.c6
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_internal.h6
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h14
-rw-r--r--source/blender/makesrna/intern/rna_key.c25
-rw-r--r--source/blender/makesrna/intern/rna_lattice.c8
-rw-r--r--source/blender/makesrna/intern/rna_layer.c6
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c16
-rw-r--r--source/blender/makesrna/intern/rna_mask.c4
-rw-r--r--source/blender/makesrna/intern/rna_material.c2
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c146
-rw-r--r--source/blender/makesrna/intern/rna_meta.c6
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c8
-rw-r--r--source/blender/makesrna/intern/rna_nla.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c14
-rw-r--r--source/blender/makesrna/intern/rna_object.c31
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c16
-rw-r--r--source/blender/makesrna/intern/rna_particle.c14
-rw-r--r--source/blender/makesrna/intern/rna_pointcloud.c13
-rw-r--r--source/blender/makesrna/intern/rna_pose.c6
-rw-r--r--source/blender/makesrna/intern/rna_render.c5
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c6
-rw-r--r--source/blender/makesrna/intern/rna_rna.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c43
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c32
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c14
-rw-r--r--source/blender/makesrna/intern/rna_shader_fx.c4
-rw-r--r--source/blender/makesrna/intern/rna_space.c18
-rw-r--r--source/blender/makesrna/intern/rna_texture.c2
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c10
-rw-r--r--source/blender/makesrna/intern/rna_volume.c19
-rw-r--r--source/blender/makesrna/intern/rna_wm.c3
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh5
-rw-r--r--source/blender/nodes/NOD_static_types.h6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_map_range.cc4
-rw-r--r--source/blender/nodes/function/nodes/node_fn_compare.cc4
-rw-r--r--source/blender/nodes/function/nodes/node_fn_replace_string.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc56
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc4
-rw-r--r--source/blender/nodes/shader/node_shader_tree.cc7
-rw-r--r--source/blender/nodes/shader/node_shader_util.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_blackbody.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wavelength.cc17
-rw-r--r--source/blender/python/gpu/gpu_py_element.c6
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c45
-rw-r--r--source/blender/python/intern/bpy_props.c230
-rw-r--r--source/blender/python/mathutils/CMakeLists.txt2
-rw-r--r--source/blender/python/mathutils/mathutils_Color.c418
-rw-r--r--source/blender/python/mathutils/mathutils_Color.h3
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.c218
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.h1
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c1056
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h4
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c569
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.h3
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c835
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.h3
-rw-r--r--source/blender/sequencer/intern/sequencer.c8
-rw-r--r--source/blender/windowmanager/WM_api.h57
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c13
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c2
-rw-r--r--source/blender/windowmanager/intern/wm_menu_type.c18
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c72
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c21
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c46
-rw-r--r--source/blender/windowmanager/intern/wm_panel_type.c18
m---------source/tools0
423 files changed, 8513 insertions, 5071 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 85827e01af5..3e97e393f17 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1756,6 +1756,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC")
"/wd4828" # The file contains a character that is illegal
"/wd4996" # identifier was declared deprecated
"/wd4661" # no suitable definition provided for explicit template instantiation request
+ "/wd4848" # 'no_unique_address' is a vendor extension in C++17
# errors:
"/we4013" # 'function' undefined; assuming extern returning int
"/we4133" # incompatible pointer types
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 0a20bd83c22..b29251b67cc 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -2,8 +2,7 @@
# <pep8 compliant>
-SCRIPT_HELP_MSG = """
-
+"""
API dump in RST files
---------------------
Run this script from Blender's root path once you have compiled Blender
@@ -14,10 +13,10 @@ API dump in RST files
providing ./blender is or links to the blender executable
To choose sphinx-in directory:
- blender --background --factory-startup --python doc/python_api/sphinx_doc_gen.py -- --output ../python_api
+ blender --background --factory-startup --python doc/python_api/sphinx_doc_gen.py -- --output=../python_api
For quick builds:
- blender --background --factory-startup --python doc/python_api/sphinx_doc_gen.py -- --partial bmesh.*
+ blender --background --factory-startup --python doc/python_api/sphinx_doc_gen.py -- --partial=bmesh.*
Sphinx: HTML generation
@@ -36,18 +35,17 @@ Sphinx: PDF generation
sphinx-build -b latex doc/python_api/sphinx-in doc/python_api/sphinx-out
cd doc/python_api/sphinx-out
make
-
"""
try:
- import bpy # Blender module
+ import bpy # Blender module.
except ImportError:
print("\nERROR: this script must run from inside Blender")
- print(SCRIPT_HELP_MSG)
+ print(__doc__)
import sys
sys.exit()
-import rna_info # Blender module
+import rna_info # Blender module.
def rna_info_BuildRNAInfo_cache():
@@ -69,15 +67,12 @@ import warnings
from textwrap import indent
-from platform import platform
-PLATFORM = platform().split('-')[0].lower() # 'linux', 'darwin', 'windows'
-
SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
-# For now, ignore add-ons and internal subclasses of 'bpy.types.PropertyGroup'.
+# For now, ignore add-ons and internal sub-classes of `bpy.types.PropertyGroup`.
#
# Besides disabling this line, the main change will be to add a
-# 'toctree' to 'write_rst_index' which contains the generated rst files.
+# 'toctree' to 'write_rst_index' which contains the generated RST files.
# This 'toctree' can be generated automatically.
#
# See: D6261 for reference.
@@ -85,92 +80,110 @@ USE_ONLY_BUILTIN_RNA_TYPES = True
def handle_args():
- '''
+ """
Parse the args passed to Blender after "--", ignored by Blender
- '''
+ """
import argparse
# When --help is given, print the usage text
parser = argparse.ArgumentParser(
formatter_class=argparse.RawTextHelpFormatter,
- usage=SCRIPT_HELP_MSG
+ usage=__doc__
)
# optional arguments
- parser.add_argument("-p", "--partial",
- dest="partial",
- type=str,
- default="",
- help="Use a wildcard to only build specific module(s)\n"
- "Example: --partial bmesh*\n",
- required=False)
-
- parser.add_argument("-f", "--fullrebuild",
- dest="full_rebuild",
- default=False,
- action='store_true',
- help="Rewrite all rst files in sphinx-in/ "
- "(default=False)",
- required=False)
-
- parser.add_argument("-b", "--bpy",
- dest="bpy",
- default=False,
- action='store_true',
- help="Write the rst file of the bpy module "
- "(default=False)",
- required=False)
-
- parser.add_argument("-o", "--output",
- dest="output_dir",
- type=str,
- default=SCRIPT_DIR,
- help="Path of the API docs (default=<script dir>)",
- required=False)
-
- parser.add_argument("-B", "--sphinx-build",
- dest="sphinx_build",
- default=False,
- action='store_true',
- help="Build the html docs by running:\n"
- "sphinx-build SPHINX_IN SPHINX_OUT\n"
- "(default=False; does not depend on -P)",
- required=False)
-
- parser.add_argument("-P", "--sphinx-build-pdf",
- dest="sphinx_build_pdf",
- default=False,
- action='store_true',
- help="Build the pdf by running:\n"
- "sphinx-build -b latex SPHINX_IN SPHINX_OUT_PDF\n"
- "(default=False; does not depend on -B)",
- required=False)
-
- parser.add_argument("-R", "--pack-reference",
- dest="pack_reference",
- default=False,
- action='store_true',
- help="Pack all necessary files in the deployed dir.\n"
- "(default=False; use with -B and -P)",
- required=False)
-
- parser.add_argument("-l", "--log",
- dest="log",
- default=False,
- action='store_true',
- help="Log the output of the API dump and sphinx|latex "
- "warnings and errors (default=False).\n"
- "If given, save logs in:\n"
- "* OUTPUT_DIR/.bpy.log\n"
- "* OUTPUT_DIR/.sphinx-build.log\n"
- "* OUTPUT_DIR/.sphinx-build_pdf.log\n"
- "* OUTPUT_DIR/.latex_make.log",
- required=False)
-
- # parse only the args passed after '--'
+ parser.add_argument(
+ "-p", "--partial",
+ dest="partial",
+ type=str,
+ default="",
+ help="Use a wildcard to only build specific module(s)\n"
+ "Example: --partial\"=bmesh*\"\n",
+ required=False,
+ )
+
+ parser.add_argument(
+ "-f", "--fullrebuild",
+ dest="full_rebuild",
+ default=False,
+ action='store_true',
+ help="Rewrite all RST files in sphinx-in/ "
+ "(default=False)",
+ required=False,
+ )
+
+ parser.add_argument(
+ "-b", "--bpy",
+ dest="bpy",
+ default=False,
+ action='store_true',
+ help="Write the RST file of the bpy module "
+ "(default=False)",
+ required=False,
+ )
+
+ parser.add_argument(
+ "-o", "--output",
+ dest="output_dir",
+ type=str,
+ default=SCRIPT_DIR,
+ help="Path of the API docs (default=<script dir>)",
+ required=False,
+ )
+
+ parser.add_argument(
+ "-B", "--sphinx-build",
+ dest="sphinx_build",
+ default=False,
+ action='store_true',
+ help="Build the html docs by running:\n"
+ "sphinx-build SPHINX_IN SPHINX_OUT\n"
+ "(default=False; does not depend on -P)",
+ required=False,
+ )
+
+ parser.add_argument(
+ "-P", "--sphinx-build-pdf",
+ dest="sphinx_build_pdf",
+ default=False,
+ action='store_true',
+ help="Build the pdf by running:\n"
+ "sphinx-build -b latex SPHINX_IN SPHINX_OUT_PDF\n"
+ "(default=False; does not depend on -B)",
+ required=False,
+ )
+
+ parser.add_argument(
+ "-R", "--pack-reference",
+ dest="pack_reference",
+ default=False,
+ action='store_true',
+ help="Pack all necessary files in the deployed dir.\n"
+ "(default=False; use with -B and -P)",
+ required=False,
+ )
+
+ parser.add_argument(
+ "-l", "--log",
+ dest="log",
+ default=False,
+ action='store_true',
+ help=(
+ "Log the output of the API dump and sphinx|latex "
+ "warnings and errors (default=False).\n"
+ "If given, save logs in:\n"
+ "* OUTPUT_DIR/.bpy.log\n"
+ "* OUTPUT_DIR/.sphinx-build.log\n"
+ "* OUTPUT_DIR/.sphinx-build_pdf.log\n"
+ "* OUTPUT_DIR/.latex_make.log"
+ ),
+ required=False,
+ )
+
+ # Parse only the arguments passed after "--".
argv = []
if "--" in sys.argv:
- argv = sys.argv[sys.argv.index("--") + 1:] # get all args after "--"
+ argv = sys.argv[sys.argv.index("--") + 1:] # Get all arguments after "--".
return parser.parse_args(argv)
@@ -179,7 +192,7 @@ ARGS = handle_args()
# ----------------------------------BPY-----------------------------------------
-BPY_LOGGER = logging.getLogger('bpy')
+BPY_LOGGER = logging.getLogger("bpy")
BPY_LOGGER.setLevel(logging.DEBUG)
"""
@@ -193,7 +206,7 @@ or
./blender -b -noaudio --factory-startup -P doc/python_api/sphinx_doc_gen.py -- -f -B
"""
-# Switch for quick testing so doc-builds don't take so long
+# Switch for quick testing so doc-builds don't take so long.
if not ARGS.partial:
# full build
FILTER_BPY_OPS = None
@@ -261,7 +274,7 @@ else:
# ------
# Filter
#
- # TODO, support bpy.ops and bpy.types filtering
+ # TODO: support `bpy.ops` and `bpy.types` filtering.
import fnmatch
m = None
EXCLUDE_MODULES = [m for m in EXCLUDE_MODULES if not fnmatch.fnmatchcase(m, ARGS.partial)]
@@ -275,7 +288,7 @@ else:
if FILTER_BPY_TYPES:
EXCLUDE_MODULES.remove("bpy.types")
- print(FILTER_BPY_TYPES)
+ # print(FILTER_BPY_TYPES)
EXCLUDE_INFO_DOCS = (not fnmatch.fnmatchcase("info", ARGS.partial))
@@ -283,7 +296,7 @@ else:
del fnmatch
BPY_LOGGER.debug(
- "Partial Doc Build, Skipping: %s\n" %
+ "Partial Doc Build, Skipping: %s\n",
"\n ".join(sorted(EXCLUDE_MODULES)))
#
@@ -293,13 +306,13 @@ else:
try:
__import__("aud")
except ImportError:
- BPY_LOGGER.debug("Warning: Built without 'aud' module, docs incomplete...")
+ BPY_LOGGER.debug("Warning: Built without \"aud\" module, docs incomplete...")
EXCLUDE_MODULES.append("aud")
try:
__import__("freestyle")
except ImportError:
- BPY_LOGGER.debug("Warning: Built without 'freestyle' module, docs incomplete...")
+ BPY_LOGGER.debug("Warning: Built without \"freestyle\" module, docs incomplete...")
EXCLUDE_MODULES.extend([
"freestyle",
"freestyle.chainingiterators",
@@ -329,13 +342,10 @@ EXTRA_SOURCE_FILES = (
# examples
EXAMPLES_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "examples"))
-EXAMPLE_SET = set()
-for f in os.listdir(EXAMPLES_DIR):
- if f.endswith(".py"):
- EXAMPLE_SET.add(os.path.splitext(f)[0])
+EXAMPLE_SET = set(os.path.splitext(f)[0] for f in os.listdir(EXAMPLES_DIR) if f.endswith(".py"))
EXAMPLE_SET_USED = set()
-# rst files dir
+# RST files directory.
RST_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "rst"))
# extra info, not api reference docs
@@ -362,35 +372,52 @@ RNA_BLACKLIST = {
"PreferencesSystem": {"language", }
}
+# Support suppressing errors when attributes collide with methods,
+# use `noindex` on the attributes / data declarations.
+#
+# NOTE: in general this should be avoided but changing it would break the API,
+# so explicitly suppress warnings instead.
+#
+# NOTE: Currently some API generation doesn't support this is it is not used yet,
+# see references to `RST_NOINDEX_ATTR` in code comments.
+#
+# A set of tuple identifiers: `(module, type, attr)`.
+RST_NOINDEX_ATTR = {
+ # Render is both a method and an attribute, from looking into this
+ # having both doesn't cause problems in practice since the `render` method
+ # is registered and called from C code where the attribute is accessed from the instance.
+ ("bpy.types", "RenderEngine", "render"),
+}
+
MODULE_GROUPING = {
"bmesh.types": (
- ("Base Mesh Type", '-'),
+ ("Base Mesh Type", "-"),
"BMesh",
- ("Mesh Elements", '-'),
+ ("Mesh Elements", "-"),
"BMVert",
"BMEdge",
"BMFace",
"BMLoop",
- ("Sequence Accessors", '-'),
+ ("Sequence Accessors", "-"),
"BMElemSeq",
"BMVertSeq",
"BMEdgeSeq",
"BMFaceSeq",
"BMLoopSeq",
"BMIter",
- ("Selection History", '-'),
+ ("Selection History", "-"),
"BMEditSelSeq",
"BMEditSelIter",
- ("Custom-Data Layer Access", '-'),
+ ("Custom-Data Layer Access", "-"),
"BMLayerAccessVert",
"BMLayerAccessEdge",
"BMLayerAccessFace",
"BMLayerAccessLoop",
"BMLayerCollection",
"BMLayerItem",
- ("Custom-Data Layer Types", '-'),
+ ("Custom-Data Layer Types", "-"),
"BMLoopUV",
- "BMDeformVert"
+ "BMDeformVert",
)
}
@@ -419,7 +446,7 @@ else:
BLENDER_VERSION_HASH_HTML_LINK = BLENDER_VERSION_HASH
BLENDER_VERSION_DATE = time.strftime("%Y-%m-%d")
-# '2_83'
+# Example: `2_83`.
BLENDER_VERSION_PATH = "%d_%d" % (bpy.app.version[0], bpy.app.version[1])
# --------------------------DOWNLOADABLE FILES----------------------------------
@@ -470,8 +497,8 @@ if ARGS.sphinx_build_pdf:
# --------------------------------API DUMP--------------------------------------
-# lame, python won't give some access
-ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
+# Lame, python won't give some access.
+ClassMethodDescriptorType = type(dict.__dict__["fromkeys"])
MethodDescriptorType = type(dict.get)
GetSetDescriptorType = type(int.real)
StaticMethodType = type(staticmethod(lambda: None))
@@ -502,8 +529,15 @@ def import_value_from_module(module_name, import_name):
return ns["value"]
+def execfile(filepath):
+ global_namespace = {"__file__": filepath, "__name__": "__main__"}
+ with open(filepath) as file_handle:
+ exec(compile(file_handle.read(), filepath, 'exec'), global_namespace)
+
+
def escape_rst(text):
- """ Escape plain text which may contain characters used by RST.
+ """
+ Escape plain text which may contain characters used by RST.
"""
return text.translate(escape_rst.trans)
@@ -517,36 +551,41 @@ escape_rst.trans = str.maketrans({
def is_struct_seq(value):
- return isinstance(value, tuple) and type(tuple) != tuple and hasattr(value, "n_fields")
+ return isinstance(value, tuple) and type(value) != tuple and hasattr(value, "n_fields")
def undocumented_message(module_name, type_name, identifier):
+ BPY_LOGGER.debug(
+ "Undocumented: module %s, type: %s, id: %s is not documented",
+ module_name, type_name, identifier,
+ )
+
return "Undocumented, consider `contributing <https://developer.blender.org/T51061>`__."
def range_str(val):
- '''
+ """
Converts values to strings for the range directive.
(unused function it seems)
- '''
+ """
if val < -10000000:
- return '-inf'
+ return "-inf"
elif val > 10000000:
- return 'inf'
+ return "inf"
elif type(val) == float:
- return '%g' % val
+ return "%g" % val
else:
return str(val)
def example_extract_docstring(filepath):
- '''
+ """
Return (text, line_no, line_no_has_content) where:
- ``text`` is the doc-string text.
- ``line_no`` is the line the doc-string text ends.
- ``line_no_has_content`` when False, this file only contains a doc-string.
There is no need to include the remainder.
- '''
+ """
file = open(filepath, "r", encoding="utf-8")
line = file.readline()
line_no = 0
@@ -561,8 +600,7 @@ def example_extract_docstring(filepath):
line_no += 1
if line.startswith('"""'):
break
- else:
- text.append(line.rstrip())
+ text.append(line.rstrip())
line_no += 1
line_no_has_content = False
@@ -590,7 +628,7 @@ def title_string(text, heading_char, double=False):
def write_example_ref(ident, fw, example_id, ext="py"):
if example_id in EXAMPLE_SET:
- # extract the comment
+ # Extract the comment.
filepath = os.path.join("..", "examples", "%s.%s" % (example_id, ext))
filepath_full = os.path.join(os.path.dirname(fw.__self__.name), filepath)
@@ -613,9 +651,9 @@ def write_example_ref(ident, fw, example_id, ext="py"):
EXAMPLE_SET_USED.add(example_id)
else:
if bpy.app.debug:
- BPY_LOGGER.debug("\tskipping example: " + example_id)
+ BPY_LOGGER.debug("\tskipping example: %s", example_id)
- # Support for numbered files bpy.types.Operator -> bpy.types.Operator.1.py
+ # Support for numbered files `bpy.types.Operator` -> `bpy.types.Operator.1.py`.
i = 1
while True:
example_id_num = "%s.%d" % (example_id, i)
@@ -627,22 +665,22 @@ def write_example_ref(ident, fw, example_id, ext="py"):
def write_indented_lines(ident, fn, text, strip=True):
- '''
- Apply same indentation to all lines in a multilines text.
- '''
+ """
+ Apply same indentation to all lines in a multi-lines text.
+ """
if text is None:
return
lines = text.split("\n")
- # strip empty lines from the start/end
+ # Strip empty lines from the start/end.
while lines and not lines[0].strip():
del lines[0]
while lines and not lines[-1].strip():
del lines[-1]
if strip:
- # set indentation to <indent>
+ # Set indentation to `<indent>`.
ident_strip = 1000
for l in lines:
if l.strip():
@@ -650,15 +688,15 @@ def write_indented_lines(ident, fn, text, strip=True):
for l in lines:
fn(ident + l[ident_strip:] + "\n")
else:
- # add <indent> number of blanks to the current indentation
+ # Add <indent> number of blanks to the current indentation.
for l in lines:
fn(ident + l + "\n")
def pymethod2sphinx(ident, fw, identifier, py_func):
- '''
+ """
class method to sphinx
- '''
+ """
arg_str = inspect.formatargspec(*inspect.getargspec(py_func))
if arg_str.startswith("(self, "):
arg_str = "(" + arg_str[7:]
@@ -676,9 +714,9 @@ def pymethod2sphinx(ident, fw, identifier, py_func):
def pyfunc2sphinx(ident, fw, module_name, type_name, identifier, py_func, is_class=True):
- '''
+ """
function or class method to sphinx
- '''
+ """
if type(py_func) == MethodType:
return
@@ -688,7 +726,7 @@ def pyfunc2sphinx(ident, fw, module_name, type_name, identifier, py_func, is_cla
if not is_class:
func_type = "function"
- # the rest are class methods
+ # The rest are class methods.
elif arg_str.startswith("(self, ") or arg_str == "(self)":
arg_str = "()" if (arg_str == "(self)") else ("(" + arg_str[7:])
func_type = "method"
@@ -726,10 +764,12 @@ def py_descr2sphinx(ident, fw, descr, module_name, type_name, identifier):
if type(descr) == GetSetDescriptorType:
fw(ident + ".. attribute:: %s\n\n" % identifier)
+ # NOTE: `RST_NOINDEX_ATTR` currently not supported (as it's not used).
write_indented_lines(ident + " ", fw, doc, False)
fw("\n")
- elif type(descr) == MemberDescriptorType: # same as above but use 'data'
+ elif type(descr) == MemberDescriptorType: # same as above but use "data"
fw(ident + ".. data:: %s\n\n" % identifier)
+ # NOTE: `RST_NOINDEX_ATTR` currently not supported (as it's not used).
write_indented_lines(ident + " ", fw, doc, False)
fw("\n")
elif type(descr) in {MethodDescriptorType, ClassMethodDescriptorType}:
@@ -743,11 +783,11 @@ def py_descr2sphinx(ident, fw, descr, module_name, type_name, identifier):
def py_c_func2sphinx(ident, fw, module_name, type_name, identifier, py_func, is_class=True):
- '''
- c defined function to sphinx.
- '''
+ """
+ C defined function to sphinx.
+ """
- # dump the docstring, assume its formatted correctly
+ # Dump the doc-string, assume its formatted correctly.
if py_func.__doc__:
write_indented_lines(ident, fw, py_func.__doc__, False)
fw("\n")
@@ -764,14 +804,16 @@ def py_c_func2sphinx(ident, fw, module_name, type_name, identifier, py_func, is_
def pyprop2sphinx(ident, fw, identifier, py_prop):
- '''
+ """
Python property to sphinx
- '''
- # readonly properties use "data" directive, variables use "attribute" directive
+ """
+ # Read-only properties use "data" directive, variables use "attribute" directive.
if py_prop.fset is None:
fw(ident + ".. data:: %s\n\n" % identifier)
else:
fw(ident + ".. attribute:: %s\n\n" % identifier)
+
+ # NOTE: `RST_NOINDEX_ATTR` currently not supported (as it's not used).
write_indented_lines(ident + " ", fw, py_prop.__doc__)
fw("\n")
if py_prop.fset is None:
@@ -789,8 +831,8 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
if module_all:
module_dir = module_all
- # TODO - currently only used for classes
- # grouping support
+ # TODO: currently only used for classes.
+ # Grouping support.
module_grouping = MODULE_GROUPING.get(module_name)
def module_grouping_index(name):
@@ -810,7 +852,7 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
def module_grouping_sort_key(name):
return module_grouping_index(name)
- # done grouping support
+ # Done grouping support.
file = open(filepath, "w", encoding="utf-8")
@@ -825,8 +867,8 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
fw(module.__doc__.strip())
fw("\n\n")
- # write submodules
- # we could also scan files but this ensures __all__ is used correctly
+ # Write sub-modules.
+ # We could also scan files but this ensures `__all__` is used correctly.
if module_all or module_all_extra:
submod_name = None
submod = None
@@ -859,7 +901,7 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
pymodule2sphinx(basepath, submod_name_full, submod, "%s submodule" % module_name, ())
fw("\n")
del submod_ls
- # done writing submodules!
+ # Done writing sub-modules!
write_example_ref("", fw, module_name)
@@ -870,10 +912,10 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
continue
if key in module_all_extra:
continue
- # naughty, we also add getset's into PyStructs, this is not typical py but also not incorrect.
+ # Naughty! We also add `getset` to `PyStruct`, this is not typical Python but also not incorrect.
- # type_name is only used for examples and messages
- # "<class 'bpy.app.handlers'>" --> bpy.app.handlers
+ # `type_name` is only used for examples and messages:
+ # `<class 'bpy.app.handlers'>` -> `bpy.app.handlers`.
type_name = str(type(module)).strip("<>").split(" ", 1)[-1][1:-1]
if type(descr) == types.GetSetDescriptorType:
py_descr2sphinx("", fw, descr, module_name, type_name, key)
@@ -889,13 +931,13 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
value_type = type(value)
descr_sorted.append((key, descr, value, type(value)))
- # sort by the valye type
+ # Sort by the value type.
descr_sorted.sort(key=lambda descr_data: str(descr_data[3]))
for key, descr, value, value_type in descr_sorted:
if key in module_all_extra:
continue
- # must be documented as a submodule
+ # Must be documented as a sub-module.
if is_struct_seq(value):
continue
@@ -909,7 +951,7 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
classes = []
submodules = []
- # use this list so we can sort by type
+ # Use this list so we can sort by type.
module_dir_value_type = []
for attribute in module_dir:
@@ -919,7 +961,7 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
if attribute in attribute_set:
continue
- if attribute.startswith("n_"): # annoying exception, needed for bpy.app
+ if attribute.startswith("n_"): # Annoying exception, needed for `bpy.app`.
continue
# workaround for bpy.app documenting .index() and .count()
@@ -940,31 +982,31 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
if value_type == FunctionType:
pyfunc2sphinx("", fw, module_name, None, attribute, value, is_class=False)
- # both the same at the moment but to be future proof
+ # Both the same at the moment but to be future proof.
elif value_type in {types.BuiltinMethodType, types.BuiltinFunctionType}:
- # note: can't get args from these, so dump the string as is
- # this means any module used like this must have fully formatted docstrings.
+ # NOTE: can't get args from these, so dump the string as is
+ # this means any module used like this must have fully formatted doc-strings.
py_c_func2sphinx("", fw, module_name, None, attribute, value, is_class=False)
elif value_type == type:
classes.append((attribute, value))
elif issubclass(value_type, types.ModuleType):
submodules.append((attribute, value))
elif issubclass(value_type, (bool, int, float, str, tuple)):
- # constant, not much fun we can do here except to list it.
- # TODO, figure out some way to document these!
+ # Constant, not much fun we can do here except to list it.
+ # TODO: figure out some way to document these!
fw(".. data:: %s\n\n" % attribute)
write_indented_lines(" ", fw, "Constant value %s" % repr(value), False)
fw("\n")
else:
- BPY_LOGGER.debug("\tnot documenting %s.%s of %r type" % (module_name, attribute, value_type.__name__))
+ BPY_LOGGER.debug("\tnot documenting %s.%s of %r type", module_name, attribute, value_type.__name__)
continue
attribute_set.add(attribute)
- # TODO, more types...
+ # TODO: more types.
del module_dir_value_type
- # TODO, bpy_extras does this already, mathutils not.
- '''
+ # TODO: `bpy_extras` does this already, `mathutils` not.
+ """
if submodules:
fw("\n"
"**********\n"
@@ -975,12 +1017,12 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
for attribute, submod in submodules:
fw("* :mod:`%s.%s`\n" % (module_name, attribute))
fw("\n")
- '''
+ """
if module_grouping is not None:
classes.sort(key=lambda pair: module_grouping_sort_key(pair[0]))
- # write collected classes now
+ # Write collected classes now.
for (type_name, value) in classes:
if module_grouping is not None:
@@ -988,7 +1030,7 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
if heading:
fw(title_string(heading, heading_char))
- # May need to be its own function
+ # May need to be its own function.
if value.__doc__:
if value.__doc__.startswith(".. class::"):
fw(value.__doc__)
@@ -1007,7 +1049,7 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
if type(descr) == ClassMethodDescriptorType:
py_descr2sphinx(" ", fw, descr, module_name, type_name, key)
- # needed for pure Python classes
+ # Needed for pure Python classes.
for key, descr in descr_items:
if type(descr) == FunctionType:
pyfunc2sphinx(" ", fw, module_name, type_name, key, descr, is_class=True)
@@ -1031,7 +1073,7 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
file.close()
-# Changes in Blender will force errors here
+# Changes In Blender will force errors here.
context_type_map = {
# context_member: (RNA type, is_collection)
"active_annotation_layer": ("GPencilLayer", False),
@@ -1106,7 +1148,6 @@ context_type_map = {
"selected_editable_keyframes": ("Keyframe", True),
"selected_editable_objects": ("Object", True),
"selected_editable_sequences": ("Sequence", True),
- "selected_ids": ("ID", True),
"selected_files": ("FileSelectEntry", True),
"selected_ids": ("ID", True),
"selected_nla_strips": ("NlaStrip", True),
@@ -1140,7 +1181,7 @@ context_type_map = {
def pycontext2sphinx(basepath):
- # Only use once. very irregular
+ # Only use once. very irregular.
filepath = os.path.join(basepath, "bpy.context.rst")
file = open(filepath, "w", encoding="utf-8")
@@ -1161,8 +1202,8 @@ def pycontext2sphinx(basepath):
fw(title_string("Global Context", "-"))
fw("These properties are available in any contexts.\n\n")
- # very silly. could make these global and only access once.
- # structs, funcs, ops, props = rna_info.BuildRNAInfo()
+ # Very silly. could make these global and only access once:
+ # `structs, funcs, ops, props = rna_info.BuildRNAInfo()`.
structs, funcs, ops, props = rna_info_BuildRNAInfo_cache()
struct = structs[("", "Context")]
struct_blacklist = RNA_BLACKLIST.get(struct.identifier, ())
@@ -1171,7 +1212,7 @@ def pycontext2sphinx(basepath):
sorted_struct_properties = struct.properties[:]
sorted_struct_properties.sort(key=lambda prop: prop.identifier)
- # First write RNA
+ # First write RNA.
for prop in sorted_struct_properties:
# Support blacklisting props.
if prop.identifier in struct_blacklist:
@@ -1185,14 +1226,14 @@ def pycontext2sphinx(basepath):
if prop.description:
fw(" %s\n\n" % prop.description)
- # special exception, can't use generic code here for enums
+ # Special exception, can't use generic code here for enums.
if prop.type == "enum":
enum_text = pyrna_enum2sphinx(prop)
if enum_text:
write_indented_lines(" ", fw, enum_text)
fw("\n")
del enum_text
- # end enum exception
+ # End enum exception.
fw(" :type: %s\n\n" % type_descr)
@@ -1209,7 +1250,7 @@ def pycontext2sphinx(basepath):
unique_context_strings = set()
for ctx_str, ctx_members in sorted(context_member_map.items()):
subsection = "%s Context" % ctx_str.split("_")[0].title()
- fw("\n%s\n%s\n\n" % (subsection, (len(subsection) * '-')))
+ fw("\n%s\n%s\n\n" % (subsection, (len(subsection) * "-")))
for member in ctx_members:
unique_all_len = len(unique)
unique.add(member)
@@ -1231,7 +1272,7 @@ def pycontext2sphinx(basepath):
(member, __file__)) from None
fw(" :type: %s :class:`bpy.types.%s`\n\n" % ("sequence of " if is_seq else "", member_type))
- # generate typemap...
+ # Generate type-map:
# for member in sorted(unique_context_strings):
# print(' "%s": ("", False),' % member)
if len(context_type_map) > len(unique_context_strings):
@@ -1239,13 +1280,14 @@ def pycontext2sphinx(basepath):
"Some types are not used: %s" %
str([member for member in context_type_map if member not in unique_context_strings]))
else:
- pass # will have raised an error above
+ pass # Will have raised an error above.
file.close()
def pyrna_enum2sphinx(prop, use_empty_descriptions=False):
- """ write a bullet point list of enum + descriptions
+ """
+ Write a bullet point list of enum + descriptions.
"""
if use_empty_descriptions:
@@ -1272,13 +1314,14 @@ def pyrna_enum2sphinx(prop, use_empty_descriptions=False):
def pyrna2sphinx(basepath):
- """ bpy.types and bpy.ops
"""
- # structs, funcs, ops, props = rna_info.BuildRNAInfo()
- structs, funcs, ops, props = rna_info_BuildRNAInfo_cache()
+ ``bpy.types`` and ``bpy.ops``.
+ """
+ # `structs, funcs, ops, props = rna_info.BuildRNAInfo()`
+ structs, _funcs, ops, _props = rna_info_BuildRNAInfo_cache()
if USE_ONLY_BUILTIN_RNA_TYPES:
- # Ignore properties that use non 'bpy.types' properties.
+ # Ignore properties that use non `bpy.types` properties.
structs_blacklist = {
v.identifier for v in structs.values()
if v.module_name != "bpy.types"
@@ -1335,7 +1378,7 @@ def pyrna2sphinx(basepath):
if prop.name or prop.description:
fw(indent(", ".join(val for val in (prop.name, prop.description) if val), ident + " ") + "\n\n")
- # special exception, can't use generic code here for enums
+ # Special exception, can't use generic code here for enums.
if enum_text:
write_indented_lines(ident + " ", fw, enum_text)
fw("\n")
@@ -1415,41 +1458,47 @@ def pyrna2sphinx(basepath):
fw(" %s\n\n" % struct.description)
- # properties sorted in alphabetical order
+ # Properties sorted in alphabetical order.
sorted_struct_properties = struct.properties[:]
sorted_struct_properties.sort(key=lambda prop: prop.identifier)
- # support blacklisting props
+ # Support blacklisting props.
struct_blacklist = RNA_BLACKLIST.get(struct_id, ())
for prop in sorted_struct_properties:
+ identifier = prop.identifier
- # support blacklisting props
- if prop.identifier in struct_blacklist:
+ # Support blacklisting props.
+ if identifier in struct_blacklist:
continue
type_descr = prop.get_type_description(class_fmt=":class:`%s`", collection_id=_BPY_PROP_COLLECTION_ID)
- # readonly properties use "data" directive, variables properties use "attribute" directive
- if 'readonly' in type_descr:
- fw(" .. data:: %s\n\n" % prop.identifier)
+ # Read-only properties use "data" directive, variables properties use "attribute" directive.
+ if "readonly" in type_descr:
+ fw(" .. data:: %s\n" % identifier)
else:
- fw(" .. attribute:: %s\n\n" % prop.identifier)
+ fw(" .. attribute:: %s\n" % identifier)
+ # Also write `noindex` on requerst.
+ if ("bpy.types", struct_id, identifier) in RST_NOINDEX_ATTR:
+ fw(" :noindex:\n")
+ fw("\n")
+
if prop.description:
write_indented_lines(" ", fw, prop.description, False)
fw("\n")
- # special exception, can't use generic code here for enums
+ # Special exception, can't use generic code here for enums.
if prop.type == "enum":
enum_text = pyrna_enum2sphinx(prop)
if enum_text:
write_indented_lines(" ", fw, enum_text)
fw("\n")
del enum_text
- # end enum exception
+ # End enum exception.
fw(" :type: %s\n\n" % type_descr)
- # Python attributes
+ # Python attributes.
py_properties = struct.get_py_properties()
py_prop = None
for identifier, py_prop in py_properties:
@@ -1474,17 +1523,17 @@ def pyrna2sphinx(basepath):
if len(func.return_values) == 1:
write_param(" ", fw, func.return_values[0], is_return=True)
- elif func.return_values: # multiple return values
+ elif func.return_values: # Multiple return values.
fw(" :return (%s):\n" % ", ".join(prop.identifier for prop in func.return_values))
for prop in func.return_values:
- # TODO, pyrna_enum2sphinx for multiple return values... actually don't
- # think we even use this but still!!!
+ # TODO: pyrna_enum2sphinx for multiple return values... actually don't
+ # think we even use this but still!
type_descr = prop.get_type_description(
as_ret=True, class_fmt=":class:`%s`", collection_id=_BPY_PROP_COLLECTION_ID)
descr = prop.description
if not descr:
descr = prop.name
- # In rare cases descr may be empty
+ # In rare cases `descr` may be empty.
fw(" `%s`, %s\n\n" %
(prop.identifier,
", ".join((val for val in (descr, type_descr) if val))))
@@ -1493,7 +1542,7 @@ def pyrna2sphinx(basepath):
fw("\n")
- # Python methods
+ # Python methods.
py_funcs = struct.get_py_functions()
py_func = None
@@ -1512,7 +1561,7 @@ def pyrna2sphinx(basepath):
if struct.base or _BPY_STRUCT_FAKE:
bases = list(reversed(struct.get_bases()))
- # props
+ # Properties.
del lines[:]
if _BPY_STRUCT_FAKE:
@@ -1543,7 +1592,7 @@ def pyrna2sphinx(basepath):
fw(line)
fw("\n")
- # funcs
+ # Functions.
del lines[:]
if _BPY_STRUCT_FAKE:
@@ -1598,7 +1647,7 @@ def pyrna2sphinx(basepath):
if "bpy.types" not in EXCLUDE_MODULES:
for struct in structs.values():
- # TODO, rna_info should filter these out!
+ # TODO: rna_info should filter these out!
if "_OT_" in struct.identifier:
continue
write_struct(struct)
@@ -1633,7 +1682,7 @@ def pyrna2sphinx(basepath):
]
for key, descr in descr_items:
- # GetSetDescriptorType, GetSetDescriptorType's are not documented yet
+ # `GetSetDescriptorType`, `GetSetDescriptorType` types are not documented yet.
if type(descr) == MethodDescriptorType:
py_descr2sphinx(" ", fw, descr, "bpy.types", class_name, key)
@@ -1664,6 +1713,7 @@ def pyrna2sphinx(basepath):
API_BASEURL_ADDON_CONTRIB = "https://developer.blender.org/diffusion/BAC"
op_modules = {}
+ op = None
for op in ops.values():
op_modules.setdefault(op.module_name, []).append(op)
del op
@@ -1688,7 +1738,7 @@ def pyrna2sphinx(basepath):
# if the description isn't valid, we output the standard warning
# with a link to the wiki so that people can help
if not op.description or op.description == "(undocumented operator)":
- operator_description = undocumented_message('bpy.ops', op.module_name, op.func_name)
+ operator_description = undocumented_message("bpy.ops", op.module_name, op.func_name)
else:
operator_description = op.description
@@ -1717,9 +1767,9 @@ def pyrna2sphinx(basepath):
def write_sphinx_conf_py(basepath):
- '''
- Write sphinx's conf.py
- '''
+ """
+ Write sphinx's ``conf.py``.
+ """
filepath = os.path.join(basepath, "conf.py")
file = open(filepath, "w", encoding="utf-8")
fw = file.write
@@ -1808,17 +1858,10 @@ class PatchedPythonDomain(PythonDomain):
file.close()
-def execfile(filepath):
- global_namespace = {"__file__": filepath, "__name__": "__main__"}
- file_handle = open(filepath)
- exec(compile(file_handle.read(), filepath, 'exec'), global_namespace)
- file_handle.close()
-
-
def write_rst_index(basepath):
- '''
- Write the rst file of the main page, needed for sphinx (index.html)
- '''
+ """
+ Write the RST file of the main page, needed for sphinx: ``index.html``.
+ """
filepath = os.path.join(basepath, "index.rst")
file = open(filepath, "w", encoding="utf-8")
fw = file.write
@@ -1896,7 +1939,7 @@ def write_rst_index(basepath):
fw("* :ref:`genindex`\n")
fw("* :ref:`modindex`\n\n")
- # special case, this 'bmesh.ops.rst' is extracted from C source
+ # Special case, this `bmesh.ops.rst` is extracted from C source.
if "bmesh.ops" not in EXCLUDE_MODULES:
execfile(os.path.join(SCRIPT_DIR, "rst_from_bmesh_opdefines.py"))
@@ -1904,9 +1947,9 @@ def write_rst_index(basepath):
def write_rst_bpy(basepath):
- '''
- Write rst file of bpy module (disabled by default)
- '''
+ """
+ Write RST file of ``bpy`` module (disabled by default)
+ """
if ARGS.bpy:
filepath = os.path.join(basepath, "bpy.rst")
file = open(filepath, "w", encoding="utf-8")
@@ -1923,9 +1966,9 @@ def write_rst_bpy(basepath):
def write_rst_types_index(basepath):
- '''
- Write the rst file of bpy.types module (index)
- '''
+ """
+ Write the RST file of ``bpy.types`` module (index)
+ """
if "bpy.types" not in EXCLUDE_MODULES:
filepath = os.path.join(basepath, "bpy.types.rst")
file = open(filepath, "w", encoding="utf-8")
@@ -1939,9 +1982,9 @@ def write_rst_types_index(basepath):
def write_rst_ops_index(basepath):
- '''
- Write the rst file of bpy.ops module (index)
- '''
+ """
+ Write the RST file of bpy.ops module (index)
+ """
if "bpy.ops" not in EXCLUDE_MODULES:
filepath = os.path.join(basepath, "bpy.ops.rst")
file = open(filepath, "w", encoding="utf-8")
@@ -1958,7 +2001,7 @@ def write_rst_ops_index(basepath):
def write_rst_msgbus(basepath):
"""
- Write the rst files of bpy.msgbus module
+ Write the RST files of ``bpy.msgbus`` module
"""
if 'bpy.msgbus' in EXCLUDE_MODULES:
return
@@ -1980,12 +2023,11 @@ def write_rst_msgbus(basepath):
def write_rst_data(basepath):
- '''
- Write the rst file of bpy.data module
- '''
+ """
+ Write the RST file of ``bpy.data`` module.
+ """
if "bpy.data" not in EXCLUDE_MODULES:
- # not actually a module, only write this file so we
- # can reference in the TOC
+ # Not actually a module, only write this file so we can reference in the TOC.
filepath = os.path.join(basepath, "bpy.data.rst")
file = open(filepath, "w", encoding="utf-8")
fw = file.write
@@ -2007,9 +2049,9 @@ def write_rst_data(basepath):
def write_rst_importable_modules(basepath):
- '''
- Write the rst files of importable modules
- '''
+ """
+ Write the RST files of importable modules.
+ """
importable_modules = {
# Python_modules
"bpy.path": "Path Utilities",
@@ -2071,7 +2113,7 @@ def write_rst_importable_modules(basepath):
# access such as `bpy.app.sdl` which doesn't seem useful since it hides more useful
# module-like objects among library data access.
importable_modules_parent_map = {}
- for mod_name in importable_modules.keys():
+ for mod_name in importable_modules: # Iterate over keys.
if mod_name in EXCLUDE_MODULES:
continue
if "." in mod_name:
@@ -2088,12 +2130,12 @@ def write_rst_importable_modules(basepath):
def copy_handwritten_rsts(basepath):
- # info docs
+ # Info docs.
if not EXCLUDE_INFO_DOCS:
- for info, info_desc in INFO_DOCS:
+ for info, _info_desc in INFO_DOCS:
shutil.copy2(os.path.join(RST_DIR, info), basepath)
- # TODO put this docs in Blender's code and use import as per modules above
+ # TODO: put this docs in Blender's code and use import as per modules above.
handwritten_modules = [
"bgl", # "Blender OpenGl wrapper"
"bmesh.ops", # generated by rst_from_bmesh_opdefines.py
@@ -2104,13 +2146,13 @@ def copy_handwritten_rsts(basepath):
for mod_name in handwritten_modules:
if mod_name not in EXCLUDE_MODULES:
- # copy2 keeps time/date stamps
+ # Copy2 keeps time/date stamps.
shutil.copy2(os.path.join(RST_DIR, "%s.rst" % mod_name), basepath)
- # changelog
+ # Change-log.
shutil.copy2(os.path.join(RST_DIR, "change_log.rst"), basepath)
- # copy images, could be smarter but just glob for now.
+ # Copy images, could be smarter but just glob for now.
for f in os.listdir(RST_DIR):
if f.endswith(".png"):
shutil.copy2(os.path.join(RST_DIR, f), basepath)
@@ -2132,12 +2174,16 @@ def copy_handwritten_extra(basepath):
def copy_theme_assets(basepath):
- shutil.copytree(os.path.join(SCRIPT_DIR, "static"),
- os.path.join(basepath, "static"),
- copy_function=shutil.copy)
- shutil.copytree(os.path.join(SCRIPT_DIR, "templates"),
- os.path.join(basepath, "templates"),
- copy_function=shutil.copy)
+ shutil.copytree(
+ os.path.join(SCRIPT_DIR, "static"),
+ os.path.join(basepath, "static"),
+ copy_function=shutil.copy,
+ )
+ shutil.copytree(
+ os.path.join(SCRIPT_DIR, "templates"),
+ os.path.join(basepath, "templates"),
+ copy_function=shutil.copy,
+ )
def rna2sphinx(basepath):
@@ -2177,21 +2223,21 @@ def rna2sphinx(basepath):
def align_sphinx_in_to_sphinx_in_tmp(dir_src, dir_dst):
- '''
+ """
Move changed files from SPHINX_IN_TMP to SPHINX_IN
- '''
+ """
import filecmp
- # possible the dir doesn't exist when running recursively
+ # Possible the dir doesn't exist when running recursively.
os.makedirs(dir_dst, exist_ok=True)
sphinx_dst_files = set(os.listdir(dir_dst))
sphinx_src_files = set(os.listdir(dir_src))
- # remove deprecated files that have been removed
+ # Remove deprecated files that have been removed.
for f in sorted(sphinx_dst_files):
if f not in sphinx_src_files:
- BPY_LOGGER.debug("\tdeprecated: %s" % f)
+ BPY_LOGGER.debug("\tdeprecated: %s", f)
f_dst = os.path.join(dir_dst, f)
if os.path.isdir(f_dst):
shutil.rmtree(f_dst, True)
@@ -2212,7 +2258,7 @@ def align_sphinx_in_to_sphinx_in_tmp(dir_src, dir_dst):
do_copy = False
if do_copy:
- BPY_LOGGER.debug("\tupdating: %s" % f)
+ BPY_LOGGER.debug("\tupdating: %s", f)
shutil.copy(f_src, f_dst)
@@ -2234,10 +2280,7 @@ def refactor_sphinx_log(sphinx_logfile):
def setup_monkey_patch():
filepath = os.path.join(SCRIPT_DIR, "sphinx_doc_gen_monkeypatch.py")
- global_namespace = {"__file__": filepath, "__name__": "__main__"}
- file = open(filepath, 'rb')
- exec(compile(file.read(), filepath, 'exec'), global_namespace)
- file.close()
+ execfile(filepath)
# Avoid adding too many changes here.
@@ -2270,109 +2313,119 @@ def main():
# Perform changes to Blender itself.
setup_data = setup_blender()
- # eventually, create the dirs
+ # Eventually, create the directories.
for dir_path in [ARGS.output_dir, SPHINX_IN]:
if not os.path.exists(dir_path):
os.mkdir(dir_path)
- # eventually, log in files
+ # Eventually, log in files.
if ARGS.log:
bpy_logfile = os.path.join(ARGS.output_dir, ".bpy.log")
bpy_logfilehandler = logging.FileHandler(bpy_logfile, mode="w")
bpy_logfilehandler.setLevel(logging.DEBUG)
BPY_LOGGER.addHandler(bpy_logfilehandler)
- # using a FileHandler seems to disable the stdout, so we add a StreamHandler
+ # using a `FileHandler` seems to disable the `stdout`, so we add a `StreamHandler`.
bpy_log_stdout_handler = logging.StreamHandler(stream=sys.stdout)
bpy_log_stdout_handler.setLevel(logging.DEBUG)
BPY_LOGGER.addHandler(bpy_log_stdout_handler)
- # in case of out-of-source build, copy the needed dirs
+ # In case of out-of-source build, copy the needed directories.
if ARGS.output_dir != SCRIPT_DIR:
- # examples dir
+ # Examples directory.
examples_dir_copy = os.path.join(ARGS.output_dir, "examples")
if os.path.exists(examples_dir_copy):
shutil.rmtree(examples_dir_copy, True)
- shutil.copytree(EXAMPLES_DIR,
- examples_dir_copy,
- ignore=shutil.ignore_patterns(*(".svn",)),
- copy_function=shutil.copy)
-
- # dump the api in rst files
+ shutil.copytree(
+ EXAMPLES_DIR,
+ examples_dir_copy,
+ ignore=shutil.ignore_patterns(*(".svn",)),
+ copy_function=shutil.copy,
+ )
+
+ # Dump the API in RST files.
if os.path.exists(SPHINX_IN_TMP):
shutil.rmtree(SPHINX_IN_TMP, True)
rna2sphinx(SPHINX_IN_TMP)
if ARGS.full_rebuild:
- # only for full updates
+ # Only for full updates.
shutil.rmtree(SPHINX_IN, True)
- shutil.copytree(SPHINX_IN_TMP,
- SPHINX_IN,
- copy_function=shutil.copy)
+ shutil.copytree(
+ SPHINX_IN_TMP,
+ SPHINX_IN,
+ copy_function=shutil.copy,
+ )
if ARGS.sphinx_build and os.path.exists(SPHINX_OUT):
shutil.rmtree(SPHINX_OUT, True)
if ARGS.sphinx_build_pdf and os.path.exists(SPHINX_OUT_PDF):
shutil.rmtree(SPHINX_OUT_PDF, True)
else:
- # move changed files in SPHINX_IN
+ # Move changed files in `SPHINX_IN`.
align_sphinx_in_to_sphinx_in_tmp(SPHINX_IN_TMP, SPHINX_IN)
- # report which example files weren't used
+ # Report which example files weren't used.
EXAMPLE_SET_UNUSED = EXAMPLE_SET - EXAMPLE_SET_USED
if EXAMPLE_SET_UNUSED:
- BPY_LOGGER.debug("\nUnused examples found in '%s'..." % EXAMPLES_DIR)
+ BPY_LOGGER.debug("\nUnused examples found in '%s'...", EXAMPLES_DIR)
for f in sorted(EXAMPLE_SET_UNUSED):
- BPY_LOGGER.debug(" %s.py" % f)
- BPY_LOGGER.debug(" %d total\n" % len(EXAMPLE_SET_UNUSED))
+ BPY_LOGGER.debug(" %s.py", f)
+ BPY_LOGGER.debug(" %d total\n", len(EXAMPLE_SET_UNUSED))
- # eventually, build the html docs
+ # Eventually, build the html docs.
if ARGS.sphinx_build:
import subprocess
subprocess.call(SPHINX_BUILD)
- # sphinx-build log cleanup+sort
+ # Sphinx-build log cleanup+sort.
if ARGS.log:
if os.stat(SPHINX_BUILD_LOG).st_size:
refactor_sphinx_log(SPHINX_BUILD_LOG)
- # eventually, build the pdf docs
+ # Eventually, build the PDF docs.
if ARGS.sphinx_build_pdf:
import subprocess
subprocess.call(SPHINX_BUILD_PDF)
subprocess.call(SPHINX_MAKE_PDF, stdout=SPHINX_MAKE_PDF_STDOUT)
- # sphinx-build log cleanup+sort
+ # Sphinx-build log cleanup+sort.
if ARGS.log:
if os.stat(SPHINX_BUILD_PDF_LOG).st_size:
refactor_sphinx_log(SPHINX_BUILD_PDF_LOG)
- # eventually, prepare the dir to be deployed online (REFERENCE_PATH)
+ # Eventually, prepare the dir to be deployed online (REFERENCE_PATH).
if ARGS.pack_reference:
if ARGS.sphinx_build:
- # delete REFERENCE_PATH
+ # Delete REFERENCE_PATH.
if os.path.exists(REFERENCE_PATH):
shutil.rmtree(REFERENCE_PATH, True)
- # copy SPHINX_OUT to the REFERENCE_PATH
- ignores = ('.doctrees', '.buildinfo')
- shutil.copytree(SPHINX_OUT,
- REFERENCE_PATH,
- ignore=shutil.ignore_patterns(*ignores))
+ # Copy SPHINX_OUT to the REFERENCE_PATH.
+ ignores = (".doctrees", ".buildinfo")
+ shutil.copytree(
+ SPHINX_OUT,
+ REFERENCE_PATH,
+ ignore=shutil.ignore_patterns(*ignores),
+ )
- # zip REFERENCE_PATH
+ # Zip REFERENCE_PATH.
basename = os.path.join(ARGS.output_dir, REFERENCE_NAME)
- tmp_path = shutil.make_archive(basename, 'zip',
- root_dir=ARGS.output_dir,
- base_dir=REFERENCE_NAME)
+ tmp_path = shutil.make_archive(
+ basename, "zip",
+ root_dir=ARGS.output_dir,
+ base_dir=REFERENCE_NAME,
+ )
final_path = os.path.join(REFERENCE_PATH, BLENDER_ZIP_FILENAME)
os.rename(tmp_path, final_path)
if ARGS.sphinx_build_pdf:
- # copy the pdf to REFERENCE_PATH
- shutil.copy(os.path.join(SPHINX_OUT_PDF, "contents.pdf"),
- os.path.join(REFERENCE_PATH, BLENDER_PDF_FILENAME))
+ # Copy the pdf to REFERENCE_PATH.
+ shutil.copy(
+ os.path.join(SPHINX_OUT_PDF, "contents.pdf"),
+ os.path.join(REFERENCE_PATH, BLENDER_PDF_FILENAME),
+ )
teardown_blender(setup_data)
diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h
index 6a4d6d263c0..2bedce1b4f0 100644
--- a/intern/atomic/atomic_ops.h
+++ b/intern/atomic/atomic_ops.h
@@ -64,16 +64,22 @@ ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new);
+ATOMIC_INLINE uint64_t atomic_load_uint64(const uint64_t *v);
+ATOMIC_INLINE void atomic_store_uint64(uint64_t *p, uint64_t v);
ATOMIC_INLINE int64_t atomic_add_and_fetch_int64(int64_t *p, int64_t x);
ATOMIC_INLINE int64_t atomic_sub_and_fetch_int64(int64_t *p, int64_t x);
ATOMIC_INLINE int64_t atomic_fetch_and_add_int64(int64_t *p, int64_t x);
ATOMIC_INLINE int64_t atomic_fetch_and_sub_int64(int64_t *p, int64_t x);
ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new);
+ATOMIC_INLINE int64_t atomic_load_int64(const int64_t *v);
+ATOMIC_INLINE void atomic_store_int64(int64_t *p, int64_t v);
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new);
+ATOMIC_INLINE uint32_t atomic_load_uint32(const uint32_t *v);
+ATOMIC_INLINE void atomic_store_uint32(uint32_t *p, uint32_t v);
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_fetch_and_or_uint32(uint32_t *p, uint32_t x);
@@ -82,6 +88,8 @@ ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE int32_t atomic_add_and_fetch_int32(int32_t *p, int32_t x);
ATOMIC_INLINE int32_t atomic_sub_and_fetch_int32(int32_t *p, int32_t x);
ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new);
+ATOMIC_INLINE int32_t atomic_load_int32(const int32_t *v);
+ATOMIC_INLINE void atomic_store_int32(int32_t *p, int32_t v);
ATOMIC_INLINE int32_t atomic_fetch_and_add_int32(int32_t *p, int32_t x);
ATOMIC_INLINE int32_t atomic_fetch_and_or_int32(int32_t *p, int32_t x);
@@ -104,6 +112,8 @@ ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_fetch_and_add_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_fetch_and_sub_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new);
+ATOMIC_INLINE size_t atomic_load_z(const size_t *v);
+ATOMIC_INLINE void atomic_store_z(size_t *p, size_t v);
/* Uses CAS loop, see warning below. */
ATOMIC_INLINE size_t atomic_fetch_and_update_max_z(size_t *p, size_t x);
diff --git a/intern/atomic/intern/atomic_ops_ext.h b/intern/atomic/intern/atomic_ops_ext.h
index aedf0985169..6ecc47f18be 100644
--- a/intern/atomic/intern/atomic_ops_ext.h
+++ b/intern/atomic/intern/atomic_ops_ext.h
@@ -102,6 +102,24 @@ ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new)
#endif
}
+ATOMIC_INLINE size_t atomic_load_z(const size_t *v)
+{
+#if (LG_SIZEOF_PTR == 8)
+ return (size_t)atomic_load_uint64((const uint64_t *)v);
+#elif (LG_SIZEOF_PTR == 4)
+ return (size_t)atomic_load_uint32((const uint32_t *)v);
+#endif
+}
+
+ATOMIC_INLINE void atomic_store_z(size_t *p, size_t v)
+{
+#if (LG_SIZEOF_PTR == 8)
+ atomic_store_uint64((uint64_t *)p, v);
+#elif (LG_SIZEOF_PTR == 4)
+ atomic_store_uint32((uint32_t *)p, v);
+#endif
+}
+
ATOMIC_INLINE size_t atomic_fetch_and_update_max_z(size_t *p, size_t x)
{
size_t prev_value;
diff --git a/intern/atomic/intern/atomic_ops_msvc.h b/intern/atomic/intern/atomic_ops_msvc.h
index ea5ae666db9..e65691d3970 100644
--- a/intern/atomic/intern/atomic_ops_msvc.h
+++ b/intern/atomic/intern/atomic_ops_msvc.h
@@ -49,6 +49,16 @@
# pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
#endif
+/* TODO(sergey): On x64 platform both read and write of a variable aligned to its type size is
+ * atomic, so in theory it is possible to avoid memory barrier and gain performance. The downside
+ * of that would be that it will impose requirement to value which is being operated on. */
+#define __atomic_impl_load_generic(v) (MemoryBarrier(), *(v))
+#define __atomic_impl_store_generic(p, v) \
+ do { \
+ *(p) = (v); \
+ MemoryBarrier(); \
+ } while (0)
+
/* 64-bit operations. */
/* Unsigned */
ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
@@ -66,6 +76,16 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne
return InterlockedCompareExchange64((int64_t *)v, _new, old);
}
+ATOMIC_INLINE uint64_t atomic_load_uint64(const uint64_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_uint64(uint64_t *p, uint64_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x);
@@ -92,6 +112,16 @@ ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new)
return InterlockedCompareExchange64(v, _new, old);
}
+ATOMIC_INLINE int64_t atomic_load_int64(const int64_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_int64(int64_t *p, int64_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
ATOMIC_INLINE int64_t atomic_fetch_and_add_int64(int64_t *p, int64_t x)
{
return InterlockedExchangeAdd64(p, x);
@@ -120,6 +150,16 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne
return InterlockedCompareExchange((long *)v, _new, old);
}
+ATOMIC_INLINE uint32_t atomic_load_uint32(const uint32_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_uint32(uint32_t *p, uint32_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
{
return InterlockedExchangeAdd(p, x);
@@ -151,6 +191,16 @@ ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new)
return InterlockedCompareExchange((long *)v, _new, old);
}
+ATOMIC_INLINE int32_t atomic_load_int32(const int32_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_int32(int32_t *p, int32_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
ATOMIC_INLINE int32_t atomic_fetch_and_add_int32(int32_t *p, int32_t x)
{
return InterlockedExchangeAdd((long *)p, x);
@@ -225,6 +275,9 @@ ATOMIC_INLINE int8_t atomic_fetch_and_or_int8(int8_t *p, int8_t b)
#endif
}
+#undef __atomic_impl_load_generic
+#undef __atomic_impl_store_generic
+
#if defined(__clang__)
# pragma GCC diagnostic pop
#endif
diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h
index 2fcfe34d03c..8c703fc4a8d 100644
--- a/intern/atomic/intern/atomic_ops_unix.h
+++ b/intern/atomic/intern/atomic_ops_unix.h
@@ -99,6 +99,22 @@ ATOMIC_INLINE void atomic_spin_unlock(volatile AtomicSpinLock *lock)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Common part of x64 implementation
+ * \{ */
+
+/* TODO(sergey): On x64 platform both read and write of a variable aligned to its type size is
+ * atomic, so in theory it is possible to avoid memory barrier and gain performance. The downside
+ * of that would be that it will impose requirement to value which is being operated on. */
+#define __atomic_impl_load_generic(v) (__sync_synchronize(), *(v))
+#define __atomic_impl_store_generic(p, v) \
+ do { \
+ *(p) = (v); \
+ __sync_synchronize(); \
+ } while (0)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Common part of locking fallback implementation
* \{ */
@@ -158,6 +174,23 @@ static _ATOMIC_MAYBE_UNUSED AtomicSpinLock _atomic_global_lock = {0};
return original_value; \
}
+#define ATOMIC_LOCKING_LOAD_DEFINE(_type) \
+ ATOMIC_INLINE _type##_t atomic_load_##_type(const _type##_t *v) \
+ { \
+ atomic_spin_lock(&_atomic_global_lock); \
+ const _type##_t value = *v; \
+ atomic_spin_unlock(&_atomic_global_lock); \
+ return value; \
+ }
+
+#define ATOMIC_LOCKING_STORE_DEFINE(_type) \
+ ATOMIC_INLINE void atomic_store_##_type(_type##_t *p, const _type##_t v) \
+ { \
+ atomic_spin_lock(&_atomic_global_lock); \
+ *p = v; \
+ atomic_spin_unlock(&_atomic_global_lock); \
+ }
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -192,6 +225,16 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne
return __sync_val_compare_and_swap(v, old, _new);
}
+ATOMIC_INLINE uint64_t atomic_load_uint64(const uint64_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_uint64(uint64_t *p, uint64_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
/* Signed */
ATOMIC_INLINE int64_t atomic_add_and_fetch_int64(int64_t *p, int64_t x)
{
@@ -218,6 +261,16 @@ ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new)
return __sync_val_compare_and_swap(v, old, _new);
}
+ATOMIC_INLINE int64_t atomic_load_int64(const int64_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_int64(int64_t *p, int64_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
#elif !defined(ATOMIC_FORCE_USE_FALLBACK) && (defined(__amd64__) || defined(__x86_64__))
/* Unsigned */
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
@@ -256,6 +309,16 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne
return ret;
}
+ATOMIC_INLINE uint64_t atomic_load_uint64(const uint64_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_uint64(uint64_t *p, uint64_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
/* Signed */
ATOMIC_INLINE int64_t atomic_fetch_and_add_int64(int64_t *p, int64_t x)
{
@@ -292,6 +355,17 @@ ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new)
asm volatile("lock; cmpxchgq %2,%1" : "=a"(ret), "+m"(*v) : "r"(_new), "0"(old) : "memory");
return ret;
}
+
+ATOMIC_INLINE int64_t atomic_load_int64(const int64_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_int64(int64_t *p, int64_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
#else
/* Unsigned */
@@ -304,6 +378,9 @@ ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE(uint64)
ATOMIC_LOCKING_CAS_DEFINE(uint64)
+ATOMIC_LOCKING_LOAD_DEFINE(uint64)
+ATOMIC_LOCKING_STORE_DEFINE(uint64)
+
/* Signed */
ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(int64)
ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(int64)
@@ -313,6 +390,9 @@ ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE(int64)
ATOMIC_LOCKING_CAS_DEFINE(int64)
+ATOMIC_LOCKING_LOAD_DEFINE(int64)
+ATOMIC_LOCKING_STORE_DEFINE(int64)
+
#endif
/** \} */
@@ -339,6 +419,16 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne
return __sync_val_compare_and_swap(v, old, _new);
}
+ATOMIC_INLINE uint32_t atomic_load_uint32(const uint32_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_uint32(uint32_t *p, uint32_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
/* Signed */
ATOMIC_INLINE int32_t atomic_add_and_fetch_int32(int32_t *p, int32_t x)
{
@@ -355,6 +445,16 @@ ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new)
return __sync_val_compare_and_swap(v, old, _new);
}
+ATOMIC_INLINE int32_t atomic_load_int32(const int32_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_int32(int32_t *p, int32_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
#elif !defined(ATOMIC_FORCE_USE_FALLBACK) && \
(defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
/* Unsigned */
@@ -385,6 +485,16 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne
return ret;
}
+ATOMIC_INLINE uint32_t atomic_load_uint32(const uint32_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_uint32(uint32_t *p, uint32_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
/* Signed */
ATOMIC_INLINE int32_t atomic_add_and_fetch_int32(int32_t *p, int32_t x)
{
@@ -413,6 +523,16 @@ ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new)
return ret;
}
+ATOMIC_INLINE int32_t atomic_load_int32(const int32_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_int32(int32_t *p, int32_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
#else
/* Unsigned */
@@ -422,6 +542,9 @@ ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(uint32)
ATOMIC_LOCKING_CAS_DEFINE(uint32)
+ATOMIC_LOCKING_LOAD_DEFINE(uint32)
+ATOMIC_LOCKING_STORE_DEFINE(uint32)
+
/* Signed */
ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(int32)
@@ -429,6 +552,9 @@ ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(int32)
ATOMIC_LOCKING_CAS_DEFINE(int32)
+ATOMIC_LOCKING_LOAD_DEFINE(int32)
+ATOMIC_LOCKING_STORE_DEFINE(int32)
+
#endif
#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
@@ -548,6 +674,9 @@ ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(int8)
/** \} */
+#undef __atomic_impl_load_generic
+#undef __atomic_impl_store_generic
+
#undef ATOMIC_LOCKING_OP_AND_FETCH_DEFINE
#undef ATOMIC_LOCKING_FETCH_AND_OP_DEFINE
#undef ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE
@@ -557,5 +686,7 @@ ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(int8)
#undef ATOMIC_LOCKING_FETCH_AND_OR_DEFINE
#undef ATOMIC_LOCKING_FETCH_AND_AND_DEFINE
#undef ATOMIC_LOCKING_CAS_DEFINE
+#undef ATOMIC_LOCKING_LOAD_DEFINE
+#undef ATOMIC_LOCKING_STORE_DEFINE
#endif /* __ATOMIC_OPS_UNIX_H__ */
diff --git a/intern/atomic/tests/atomic_test.cc b/intern/atomic/tests/atomic_test.cc
index d79374416ec..ee06085c95d 100644
--- a/intern/atomic/tests/atomic_test.cc
+++ b/intern/atomic/tests/atomic_test.cc
@@ -143,6 +143,40 @@ TEST(atomic, atomic_cas_uint64)
}
}
+TEST(atomic, atomic_load_uint64)
+{
+ /* Make sure alias is implemented. */
+ {
+ uint64_t value = 2;
+ EXPECT_EQ(atomic_load_uint64(&value), 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const uint64_t uint64_t_max = std::numeric_limits<uint64_t>::max();
+ uint64_t value = uint64_t_max;
+ EXPECT_EQ(atomic_load_uint64(&value), uint64_t_max);
+ }
+}
+
+TEST(atomic, atomic_store_uint64)
+{
+ /* Make sure alias is implemented. */
+ {
+ uint64_t value = 0;
+ atomic_store_uint64(&value, 2);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const uint64_t uint64_t_max = std::numeric_limits<uint64_t>::max();
+ uint64_t value = 0;
+ atomic_store_uint64(&value, uint64_t_max);
+ EXPECT_EQ(value, uint64_t_max);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -277,6 +311,40 @@ TEST(atomic, atomic_cas_int64)
}
}
+TEST(atomic, atomic_load_int64)
+{
+ /* Make sure alias is implemented. */
+ {
+ int64_t value = 2;
+ EXPECT_EQ(atomic_load_int64(&value), 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const int64_t int64_t_max = std::numeric_limits<int64_t>::max();
+ int64_t value = int64_t_max;
+ EXPECT_EQ(atomic_load_int64(&value), int64_t_max);
+ }
+}
+
+TEST(atomic, atomic_store_int64)
+{
+ /* Make sure alias is implemented. */
+ {
+ int64_t value = 0;
+ atomic_store_int64(&value, 2);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const int64_t int64_t_max = std::numeric_limits<int64_t>::max();
+ int64_t value = 0;
+ atomic_store_int64(&value, int64_t_max);
+ EXPECT_EQ(value, int64_t_max);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -358,6 +426,40 @@ TEST(atomic, atomic_cas_uint32)
}
}
+TEST(atomic, atomic_load_uint32)
+{
+ /* Make sure alias is implemented. */
+ {
+ uint32_t value = 2;
+ EXPECT_EQ(atomic_load_uint32(&value), 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const uint32_t uint32_t_max = std::numeric_limits<uint32_t>::max();
+ uint32_t value = uint32_t_max;
+ EXPECT_EQ(atomic_load_uint32(&value), uint32_t_max);
+ }
+}
+
+TEST(atomic, atomic_store_uint32)
+{
+ /* Make sure alias is implemented. */
+ {
+ uint32_t value = 0;
+ atomic_store_uint32(&value, 2);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const uint32_t uint32_t_max = std::numeric_limits<uint32_t>::max();
+ uint32_t value = 0;
+ atomic_store_uint32(&value, uint32_t_max);
+ EXPECT_EQ(value, uint32_t_max);
+ }
+}
+
TEST(atomic, atomic_fetch_and_add_uint32)
{
{
@@ -505,6 +607,40 @@ TEST(atomic, atomic_cas_int32)
}
}
+TEST(atomic, atomic_load_int32)
+{
+ /* Make sure alias is implemented. */
+ {
+ int32_t value = 2;
+ EXPECT_EQ(atomic_load_int32(&value), 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const int32_t int32_t_max = std::numeric_limits<int32_t>::max();
+ int32_t value = int32_t_max;
+ EXPECT_EQ(atomic_load_int32(&value), int32_t_max);
+ }
+}
+
+TEST(atomic, atomic_store_int32)
+{
+ /* Make sure alias is implemented. */
+ {
+ int32_t value = 0;
+ atomic_store_int32(&value, 2);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const int32_t int32_t_max = std::numeric_limits<int32_t>::max();
+ int32_t value = 0;
+ atomic_store_int32(&value, int32_t_max);
+ EXPECT_EQ(value, int32_t_max);
+ }
+}
+
TEST(atomic, atomic_fetch_and_add_int32)
{
{
@@ -761,6 +897,40 @@ TEST(atomic, atomic_cas_z)
}
}
+TEST(atomic, atomic_load_z)
+{
+ /* Make sure alias is implemented. */
+ {
+ size_t value = 2;
+ EXPECT_EQ(atomic_load_z(&value), 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const size_t size_t_max = std::numeric_limits<size_t>::max();
+ size_t value = size_t_max;
+ EXPECT_EQ(atomic_load_z(&value), size_t_max);
+ }
+}
+
+TEST(atomic, atomic_store_z)
+{
+ /* Make sure alias is implemented. */
+ {
+ size_t value = 0;
+ atomic_store_z(&value, 2);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const size_t size_t_max = std::numeric_limits<size_t>::max();
+ size_t value = 0;
+ atomic_store_z(&value, size_t_max);
+ EXPECT_EQ(value, size_t_max);
+ }
+}
+
TEST(atomic, atomic_fetch_and_update_max_z)
{
const size_t size_t_max = std::numeric_limits<size_t>::max();
diff --git a/intern/cycles/blender/volume.cpp b/intern/cycles/blender/volume.cpp
index 8dd2d45c0b6..a9a2c474f40 100644
--- a/intern/cycles/blender/volume.cpp
+++ b/intern/cycles/blender/volume.cpp
@@ -219,7 +219,10 @@ static void sync_smoke_volume(
class BlenderVolumeLoader : public VDBImageLoader {
public:
- BlenderVolumeLoader(BL::BlendData &b_data, BL::Volume &b_volume, const string &grid_name)
+ BlenderVolumeLoader(BL::BlendData &b_data,
+ BL::Volume &b_volume,
+ const string &grid_name,
+ BL::VolumeRender::precision_enum precision_)
: VDBImageLoader(grid_name), b_volume(b_volume)
{
b_volume.grids.load(b_data.ptr.data);
@@ -241,6 +244,20 @@ class BlenderVolumeLoader : public VDBImageLoader {
}
}
#endif
+#ifdef WITH_NANOVDB
+ switch (precision_) {
+ case BL::VolumeRender::precision_FULL:
+ precision = 32;
+ break;
+ case BL::VolumeRender::precision_HALF:
+ precision = 16;
+ break;
+ default:
+ case BL::VolumeRender::precision_VARIABLE:
+ precision = 0;
+ break;
+ }
+#endif
}
BL::Volume b_volume;
@@ -318,7 +335,8 @@ static void sync_volume_object(BL::BlendData &b_data,
volume->attributes.add(std) :
volume->attributes.add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL);
- ImageLoader *loader = new BlenderVolumeLoader(b_data, b_volume, name.string());
+ ImageLoader *loader = new BlenderVolumeLoader(
+ b_data, b_volume, name.string(), b_render.precision());
ImageParams params;
params.frame = b_volume.grids.frame();
diff --git a/intern/cycles/device/cuda/device_impl.cpp b/intern/cycles/device/cuda/device_impl.cpp
index 6908ae5ead3..75177566901 100644
--- a/intern/cycles/device/cuda/device_impl.cpp
+++ b/intern/cycles/device/cuda/device_impl.cpp
@@ -1084,7 +1084,9 @@ void CUDADevice::tex_alloc(device_texture &mem)
need_texture_info = true;
if (mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
- mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3 &&
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FPN &&
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FP16) {
CUDA_RESOURCE_DESC resDesc;
memset(&resDesc, 0, sizeof(resDesc));
diff --git a/intern/cycles/device/hip/device_impl.cpp b/intern/cycles/device/hip/device_impl.cpp
index 7159277b325..f8fdb86ca29 100644
--- a/intern/cycles/device/hip/device_impl.cpp
+++ b/intern/cycles/device/hip/device_impl.cpp
@@ -1042,7 +1042,9 @@ void HIPDevice::tex_alloc(device_texture &mem)
need_texture_info = true;
if (mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
- mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3 &&
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FPN &&
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FP16) {
/* Bindless textures. */
hipResourceDesc resDesc;
memset(&resDesc, 0, sizeof(resDesc));
diff --git a/intern/cycles/device/memory.cpp b/intern/cycles/device/memory.cpp
index 4c068dbdd3e..40cf2573cfb 100644
--- a/intern/cycles/device/memory.cpp
+++ b/intern/cycles/device/memory.cpp
@@ -165,6 +165,8 @@ device_texture::device_texture(Device *device,
case IMAGE_DATA_TYPE_BYTE:
case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
+ case IMAGE_DATA_TYPE_NANOVDB_FPN:
+ case IMAGE_DATA_TYPE_NANOVDB_FP16:
data_type = TYPE_UCHAR;
data_elements = 1;
break;
diff --git a/intern/cycles/kernel/device/cpu/image.h b/intern/cycles/kernel/device/cpu/image.h
index 3b714a3e580..7809ec5f4a7 100644
--- a/intern/cycles/kernel/device/cpu/image.h
+++ b/intern/cycles/kernel/device/cpu/image.h
@@ -817,6 +817,16 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
}
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
return NanoVDBInterpolator<nanovdb::Vec3f>::interp_3d(info, P.x, P.y, P.z, interp);
+ case IMAGE_DATA_TYPE_NANOVDB_FPN: {
+ const float f = NanoVDBInterpolator<nanovdb::FpN, float>::interp_3d(
+ info, P.x, P.y, P.z, interp);
+ return make_float4(f, f, f, 1.0f);
+ }
+ case IMAGE_DATA_TYPE_NANOVDB_FP16: {
+ const float f = NanoVDBInterpolator<nanovdb::Fp16, float>::interp_3d(
+ info, P.x, P.y, P.z, interp);
+ return make_float4(f, f, f, 1.0f);
+ }
#endif
default:
assert(0);
diff --git a/intern/cycles/kernel/device/gpu/image.h b/intern/cycles/kernel/device/gpu/image.h
index c5bc7d88e02..29d851ae478 100644
--- a/intern/cycles/kernel/device/gpu/image.h
+++ b/intern/cycles/kernel/device/gpu/image.h
@@ -125,7 +125,8 @@ kernel_tex_image_interp_tricubic(ccl_global const TextureInfo &info, float x, fl
#ifdef WITH_NANOVDB
template<typename T, typename S>
-ccl_device T kernel_tex_image_interp_tricubic_nanovdb(S &s, float x, float y, float z)
+ccl_device typename nanovdb::NanoGrid<T>::ValueType kernel_tex_image_interp_tricubic_nanovdb(
+ S &s, float x, float y, float z)
{
float px = floorf(x);
float py = floorf(y);
@@ -157,7 +158,7 @@ ccl_device T kernel_tex_image_interp_tricubic_nanovdb(S &s, float x, float y, fl
}
template<typename T>
-ccl_device_noinline T kernel_tex_image_interp_nanovdb(
+ccl_device_noinline typename nanovdb::NanoGrid<T>::ValueType kernel_tex_image_interp_nanovdb(
ccl_global const TextureInfo &info, float x, float y, float z, uint interpolation)
{
using namespace nanovdb;
@@ -238,6 +239,14 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
info, x, y, z, interpolation);
return make_float4(f[0], f[1], f[2], 1.0f);
}
+ if (texture_type == IMAGE_DATA_TYPE_NANOVDB_FPN) {
+ float f = kernel_tex_image_interp_nanovdb<nanovdb::FpN>(info, x, y, z, interpolation);
+ return make_float4(f, f, f, 1.0f);
+ }
+ if (texture_type == IMAGE_DATA_TYPE_NANOVDB_FP16) {
+ float f = kernel_tex_image_interp_nanovdb<nanovdb::Fp16>(info, x, y, z, interpolation);
+ return make_float4(f, f, f, 1.0f);
+ }
#endif
if (texture_type == IMAGE_DATA_TYPE_FLOAT4 || texture_type == IMAGE_DATA_TYPE_BYTE4 ||
texture_type == IMAGE_DATA_TYPE_HALF4 || texture_type == IMAGE_DATA_TYPE_USHORT4) {
diff --git a/intern/cycles/kernel/device/gpu/kernel.h b/intern/cycles/kernel/device/gpu/kernel.h
index 82b51843864..328c58e7905 100644
--- a/intern/cycles/kernel/device/gpu/kernel.h
+++ b/intern/cycles/kernel/device/gpu/kernel.h
@@ -647,8 +647,9 @@ ccl_device_inline void kernel_gpu_film_convert_half_write(ccl_global uchar4 *rgb
const int x = render_pixel_index % width; \
const int y = render_pixel_index / width; \
\
- ccl_global const float *buffer = render_buffer + offset + x * kfilm_convert.pass_stride + \
- y * stride * kfilm_convert.pass_stride; \
+ const uint64_t buffer_pixel_index = x + y * stride; \
+ ccl_global const float *buffer = render_buffer + offset + \
+ buffer_pixel_index * kfilm_convert.pass_stride; \
\
ccl_global float *pixel = pixels + \
(render_pixel_index + rgba_offset) * kfilm_convert.pixel_stride; \
@@ -677,8 +678,9 @@ ccl_device_inline void kernel_gpu_film_convert_half_write(ccl_global uchar4 *rgb
const int x = render_pixel_index % width; \
const int y = render_pixel_index / width; \
\
- ccl_global const float *buffer = render_buffer + offset + x * kfilm_convert.pass_stride + \
- y * stride * kfilm_convert.pass_stride; \
+ const uint64_t buffer_pixel_index = x + y * stride; \
+ ccl_global const float *buffer = render_buffer + offset + \
+ buffer_pixel_index * kfilm_convert.pass_stride; \
\
float pixel[4]; \
film_get_pass_pixel_##variant(&kfilm_convert, buffer, pixel); \
diff --git a/intern/cycles/kernel/film/adaptive_sampling.h b/intern/cycles/kernel/film/adaptive_sampling.h
index ad9b3b08ac5..16867c39d99 100644
--- a/intern/cycles/kernel/film/adaptive_sampling.h
+++ b/intern/cycles/kernel/film/adaptive_sampling.h
@@ -91,13 +91,13 @@ ccl_device void kernel_adaptive_sampling_filter_x(KernelGlobals kg,
bool prev = false;
for (int x = start_x; x < start_x + width; ++x) {
int index = offset + x + y * stride;
- ccl_global float *buffer = render_buffer + index * kernel_data.film.pass_stride;
+ ccl_global float *buffer = render_buffer + (uint64_t)index * kernel_data.film.pass_stride;
const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3;
if (buffer[aux_w_offset] == 0.0f) {
if (x > start_x && !prev) {
index = index - 1;
- buffer = render_buffer + index * kernel_data.film.pass_stride;
+ buffer = render_buffer + (uint64_t)index * kernel_data.film.pass_stride;
buffer[aux_w_offset] = 0.0f;
}
prev = true;
@@ -124,13 +124,13 @@ ccl_device void kernel_adaptive_sampling_filter_y(KernelGlobals kg,
bool prev = false;
for (int y = start_y; y < start_y + height; ++y) {
int index = offset + x + y * stride;
- ccl_global float *buffer = render_buffer + index * kernel_data.film.pass_stride;
+ ccl_global float *buffer = render_buffer + (uint64_t)index * kernel_data.film.pass_stride;
const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3;
if (buffer[aux_w_offset] == 0.0f) {
if (y > start_y && !prev) {
index = index - stride;
- buffer = render_buffer + index * kernel_data.film.pass_stride;
+ buffer = render_buffer + (uint64_t)index * kernel_data.film.pass_stride;
buffer[aux_w_offset] = 0.0f;
}
prev = true;
diff --git a/intern/cycles/kernel/integrator/init_from_bake.h b/intern/cycles/kernel/integrator/init_from_bake.h
index 3772db845a8..293c1d243f8 100644
--- a/intern/cycles/kernel/integrator/init_from_bake.h
+++ b/intern/cycles/kernel/integrator/init_from_bake.h
@@ -102,7 +102,7 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg,
/* Setup render buffers. */
const int index = INTEGRATOR_STATE(state, path, render_pixel_index);
const int pass_stride = kernel_data.film.pass_stride;
- ccl_global float *buffer = render_buffer + index * pass_stride;
+ ccl_global float *buffer = render_buffer + (uint64_t)index * pass_stride;
ccl_global float *primitive = buffer + kernel_data.film.pass_bake_primitive;
ccl_global float *differential = buffer + kernel_data.film.pass_bake_differential;
diff --git a/intern/cycles/kernel/svm/blackbody.h b/intern/cycles/kernel/svm/blackbody.h
index af59c2fe747..774fa16b384 100644
--- a/intern/cycles/kernel/svm/blackbody.h
+++ b/intern/cycles/kernel/svm/blackbody.h
@@ -24,6 +24,7 @@ ccl_device_noinline void svm_node_blackbody(KernelGlobals kg,
float temperature = stack_load_float(stack, temperature_offset);
float3 color_rgb = rec709_to_rgb(kg, svm_math_blackbody_color_rec709(temperature));
+ color_rgb = max(color_rgb, zero_float3());
stack_store_float3(stack, col_offset, color_rgb);
}
diff --git a/intern/cycles/kernel/svm/math_util.h b/intern/cycles/kernel/svm/math_util.h
index 9f2d9561e26..89bd4a501a7 100644
--- a/intern/cycles/kernel/svm/math_util.h
+++ b/intern/cycles/kernel/svm/math_util.h
@@ -192,28 +192,26 @@ ccl_device float svm_math(NodeMathType type, float a, float b, float c)
ccl_device float3 svm_math_blackbody_color_rec709(float t)
{
/* Calculate color in range 800..12000 using an approximation
- * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
- * Max absolute error for RGB is (0.00095, 0.00077, 0.00057),
- * which is enough to get the same 8 bit/channel color.
- */
+ * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B.
+ *
+ * The result of this can be negative to support gamut wider than
+ * than rec.709, just needs to be clamped. */
if (t >= 12000.0f) {
- return make_float3(0.826270103f, 0.994478524f, 1.56626022f);
+ return make_float3(0.8262954810464208f, 0.9945080501520986f, 1.566307710274283f);
}
- else if (t < 965.0f) {
- /* For 800 <= t < 965 color does not change in OSL implementation, so keep color the same */
- return make_float3(4.70366907f, 0.0f, 0.0f);
+ else if (t < 800.0f) {
+ /* Arbitrary lower limit where light is very dim, matching OSL. */
+ return make_float3(5.413294490189271f, -0.20319390035873933f, -0.0822535242887164f);
}
- /* Manually align for readability. */
- /* clang-format off */
- int i = (t >= 6365.0f) ? 5 :
- (t >= 3315.0f) ? 4 :
- (t >= 1902.0f) ? 3 :
- (t >= 1449.0f) ? 2 :
- (t >= 1167.0f) ? 1 :
+ int i = (t >= 6365.0f) ? 6 :
+ (t >= 3315.0f) ? 5 :
+ (t >= 1902.0f) ? 4 :
+ (t >= 1449.0f) ? 3 :
+ (t >= 1167.0f) ? 2 :
+ (t >= 965.0f) ? 1 :
0;
- /* clang-format on */
ccl_constant float *r = blackbody_table_r[i];
ccl_constant float *g = blackbody_table_g[i];
diff --git a/intern/cycles/kernel/tables.h b/intern/cycles/kernel/tables.h
index f826cc5c5ef..c1fdbba3fa7 100644
--- a/intern/cycles/kernel/tables.h
+++ b/intern/cycles/kernel/tables.h
@@ -4,30 +4,33 @@
/* clang-format off */
ccl_inline_constant float blackbody_table_r[][3] = {
- {2.52432244e+03f, -1.06185848e-03f, 3.11067539e+00f},
- {3.37763626e+03f, -4.34581697e-04f, 1.64843306e+00f},
- {4.10671449e+03f, -8.61949938e-05f, 6.41423749e-01f},
- {4.66849800e+03f, 2.85655028e-05f, 1.29075375e-01f},
- {4.60124770e+03f, 2.89727618e-05f, 1.48001316e-01f},
- {3.78765709e+03f, 9.36026367e-06f, 3.98995841e-01f}
+ {1.61919106e+03f, -2.05010916e-03f, 5.02995757e+00f},
+ {2.48845471e+03f, -1.11330907e-03f, 3.22621544e+00f},
+ {3.34143193e+03f, -4.86551192e-04f, 1.76486769e+00f},
+ {4.09461742e+03f, -1.27446582e-04f, 7.25731635e-01f},
+ {4.67028036e+03f, 2.91258199e-05f, 1.26703442e-01f},
+ {4.59509185e+03f, 2.87495649e-05f, 1.50345020e-01f},
+ {3.78717450e+03f, 9.35907826e-06f, 3.99075871e-01f}
};
ccl_inline_constant float blackbody_table_g[][3] = {
- {-7.50343014e+02f, 3.15679613e-04f, 4.73464526e-01f},
- {-1.00402363e+03f, 1.29189794e-04f, 9.08181524e-01f},
- {-1.22075471e+03f, 2.56245413e-05f, 1.20753416e+00f},
- {-1.42546105e+03f, -4.01730887e-05f, 1.44002695e+00f},
- {-1.18134453e+03f, -2.18913373e-05f, 1.30656109e+00f},
- {-5.00279505e+02f, -4.59745390e-06f, 1.09090465e+00f}
+ {-4.88999748e+02f, 6.04330754e-04f, -7.55807526e-02f},
+ {-7.55994277e+02f, 3.16730098e-04f, 4.78306139e-01f},
+ {-1.02363977e+03f, 1.20223470e-04f, 9.36662319e-01f},
+ {-1.26571316e+03f, 4.87340896e-06f, 1.27054498e+00f},
+ {-1.42529332e+03f, -4.01150431e-05f, 1.43972784e+00f},
+ {-1.17554822e+03f, -2.16378048e-05f, 1.30408023e+00f},
+ {-5.00799571e+02f, -4.59832026e-06f, 1.09098763e+00f}
};
ccl_inline_constant float blackbody_table_b[][4] = {
- {0.0f, 0.0f, 0.0f, 0.0f}, /* zeros should be optimized by compiler */
- {0.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
- {-2.02524603e-11f, 1.79435860e-07f, -2.60561875e-04f, -1.41761141e-02f},
- {-2.22463426e-13f, -1.55078698e-08f, 3.81675160e-04f, -7.30646033e-01f},
- {6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f}
+ {5.96945309e-11f, -4.85742887e-08f, -9.70622247e-05f, -4.07936148e-03f},
+ {2.40430366e-11f, 5.55021075e-08f, -1.98503712e-04f, 2.89312858e-02f},
+ {-1.40949732e-11f, 1.89878968e-07f, -3.56632824e-04f, 9.10767778e-02f},
+ {-3.61460868e-11f, 2.84822009e-07f, -4.93211319e-04f, 1.56723440e-01f},
+ {-1.97075738e-11f, 1.75359352e-07f, -2.50542825e-04f, -2.22783266e-02f},
+ {-1.61997957e-13f, -1.64216008e-08f, 3.86216271e-04f, -7.38077418e-01f},
+ {6.72650283e-13f, -2.73078809e-08f, 4.24098264e-04f, -7.52335691e-01f}
};
ccl_inline_constant float cie_colour_match[][3] = {
diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp
index c61ad1f1d71..2aa9a6bc1a1 100644
--- a/intern/cycles/scene/image.cpp
+++ b/intern/cycles/scene/image.cpp
@@ -64,6 +64,10 @@ const char *name_from_type(ImageDataType type)
return "nanovdb_float";
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
return "nanovdb_float3";
+ case IMAGE_DATA_TYPE_NANOVDB_FPN:
+ return "nanovdb_fpn";
+ case IMAGE_DATA_TYPE_NANOVDB_FP16:
+ return "nanovdb_fp16";
case IMAGE_DATA_NUM_TYPES:
assert(!"System enumerator type, should never be used");
return "";
@@ -378,7 +382,9 @@ void ImageManager::load_image_metadata(Image *img)
metadata.detect_colorspace();
assert(features.has_nanovdb || (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT ||
- metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3));
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3 ||
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FPN ||
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FP16));
img->need_metadata = false;
}
@@ -796,7 +802,8 @@ void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Pro
}
}
#ifdef WITH_NANOVDB
- else if (type == IMAGE_DATA_TYPE_NANOVDB_FLOAT || type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
+ else if (type == IMAGE_DATA_TYPE_NANOVDB_FLOAT || type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3 ||
+ type == IMAGE_DATA_TYPE_NANOVDB_FPN || type == IMAGE_DATA_TYPE_NANOVDB_FP16) {
thread_scoped_lock device_lock(device_mutex);
void *pixels = img->mem->alloc(img->metadata.byte_size, 0);
diff --git a/intern/cycles/scene/image_oiio.cpp b/intern/cycles/scene/image_oiio.cpp
index 3f825afbe90..1b7f8f49696 100644
--- a/intern/cycles/scene/image_oiio.cpp
+++ b/intern/cycles/scene/image_oiio.cpp
@@ -199,6 +199,8 @@ bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
break;
case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
+ case IMAGE_DATA_TYPE_NANOVDB_FPN:
+ case IMAGE_DATA_TYPE_NANOVDB_FP16:
case IMAGE_DATA_NUM_TYPES:
break;
}
diff --git a/intern/cycles/scene/image_vdb.cpp b/intern/cycles/scene/image_vdb.cpp
index b6f0911fa2c..d0b41a239df 100644
--- a/intern/cycles/scene/image_vdb.cpp
+++ b/intern/cycles/scene/image_vdb.cpp
@@ -44,14 +44,30 @@ struct ToDenseOp {
# ifdef WITH_NANOVDB
struct ToNanoOp {
nanovdb::GridHandle<> nanogrid;
+ int precision;
template<typename GridType, typename FloatGridType, typename FloatDataType, int channels>
bool operator()(const openvdb::GridBase::ConstPtr &grid)
{
if constexpr (!std::is_same_v<GridType, openvdb::MaskGrid>) {
try {
- nanogrid = nanovdb::openToNanoVDB(
- FloatGridType(*openvdb::gridConstPtrCast<GridType>(grid)));
+ FloatGridType floatgrid(*openvdb::gridConstPtrCast<GridType>(grid));
+ if constexpr (std::is_same_v<FloatGridType, openvdb::FloatGrid>) {
+ if (precision == 0) {
+ nanogrid = nanovdb::openToNanoVDB<nanovdb::HostBuffer,
+ typename FloatGridType::TreeType,
+ nanovdb::FpN>(floatgrid);
+ return true;
+ }
+ else if (precision == 16) {
+ nanogrid = nanovdb::openToNanoVDB<nanovdb::HostBuffer,
+ typename FloatGridType::TreeType,
+ nanovdb::Fp16>(floatgrid);
+ return true;
+ }
+ }
+
+ nanogrid = nanovdb::openToNanoVDB(floatgrid);
}
catch (const std::exception &e) {
VLOG(1) << "Error converting OpenVDB to NanoVDB grid: " << e.what();
@@ -102,6 +118,7 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet
openvdb::tools::pruneInactive(pruned_grid.tree());
nanogrid = nanovdb::openToNanoVDB(pruned_grid);*/
ToNanoOp op;
+ op.precision = precision;
if (!openvdb::grid_type_operation(grid, op)) {
return false;
}
@@ -124,7 +141,15 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet
if (nanogrid) {
metadata.byte_size = nanogrid.size();
if (metadata.channels == 1) {
- metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT;
+ if (precision == 0) {
+ metadata.type = IMAGE_DATA_TYPE_NANOVDB_FPN;
+ }
+ else if (precision == 16) {
+ metadata.type = IMAGE_DATA_TYPE_NANOVDB_FP16;
+ }
+ else {
+ metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT;
+ }
}
else {
metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT3;
diff --git a/intern/cycles/scene/image_vdb.h b/intern/cycles/scene/image_vdb.h
index a5fd51915ef..ea5f6b0b3d9 100644
--- a/intern/cycles/scene/image_vdb.h
+++ b/intern/cycles/scene/image_vdb.h
@@ -51,6 +51,7 @@ class VDBImageLoader : public ImageLoader {
#endif
#ifdef WITH_NANOVDB
nanovdb::GridHandle<> nanogrid;
+ int precision = 0;
#endif
};
diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp
index 8015be6393b..ddd89a16640 100644
--- a/intern/cycles/scene/object.cpp
+++ b/intern/cycles/scene/object.cpp
@@ -327,9 +327,11 @@ float Object::compute_volume_step_size() const
/* Auto detect step size. */
float3 size = one_float3();
#ifdef WITH_NANOVDB
- /* Dimensions were not applied to image transform with NanOVDB (see image_vdb.cpp) */
+ /* Dimensions were not applied to image transform with NanoVDB (see image_vdb.cpp) */
if (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
- metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3)
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3 &&
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FPN &&
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FP16)
#endif
size /= make_float3(metadata.width, metadata.height, metadata.depth);
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
index 03c152928d5..3b58556f601 100644
--- a/intern/cycles/scene/shader_nodes.cpp
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -5882,7 +5882,7 @@ void BlackbodyNode::constant_fold(const ConstantFolder &folder)
if (folder.all_inputs_constant()) {
const float3 rgb_rec709 = svm_math_blackbody_color_rec709(temperature);
const float3 rgb = folder.scene->shader_manager->rec709_to_scene_linear(rgb_rec709);
- folder.make_constant(rgb);
+ folder.make_constant(max(rgb, zero_float3()));
}
}
diff --git a/intern/cycles/test/render_graph_finalize_test.cpp b/intern/cycles/test/render_graph_finalize_test.cpp
index 143628f1e30..dac36ab0135 100644
--- a/intern/cycles/test/render_graph_finalize_test.cpp
+++ b/intern/cycles/test/render_graph_finalize_test.cpp
@@ -946,7 +946,7 @@ TEST_F(RenderGraph, constant_fold_bright_contrast)
TEST_F(RenderGraph, constant_fold_blackbody)
{
EXPECT_ANY_MESSAGE(log);
- CORRECT_INFO_MESSAGE(log, "Folding Blackbody::Color to constant (3.94163, 0.226523, 0).");
+ CORRECT_INFO_MESSAGE(log, "Folding Blackbody::Color to constant (3.96553, 0.227897, 0).");
builder
.add_node(ShaderNodeBuilder<BlackbodyNode>(graph, "Blackbody").set("Temperature", 1200.0f))
diff --git a/intern/cycles/util/texture.h b/intern/cycles/util/texture.h
index e8bb058a3c9..90e842933c2 100644
--- a/intern/cycles/util/texture.h
+++ b/intern/cycles/util/texture.h
@@ -37,6 +37,8 @@ typedef enum ImageDataType {
IMAGE_DATA_TYPE_USHORT = 7,
IMAGE_DATA_TYPE_NANOVDB_FLOAT = 8,
IMAGE_DATA_TYPE_NANOVDB_FLOAT3 = 9,
+ IMAGE_DATA_TYPE_NANOVDB_FPN = 10,
+ IMAGE_DATA_TYPE_NANOVDB_FP16 = 11,
IMAGE_DATA_NUM_TYPES
} ImageDataType;
diff --git a/intern/ghost/intern/GHOST_Buttons.cpp b/intern/ghost/intern/GHOST_Buttons.cpp
index c948c7beadb..3367d256325 100644
--- a/intern/ghost/intern/GHOST_Buttons.cpp
+++ b/intern/ghost/intern/GHOST_Buttons.cpp
@@ -21,6 +21,14 @@ bool GHOST_Buttons::get(GHOST_TButtonMask mask) const
return m_ButtonMiddle;
case GHOST_kButtonMaskRight:
return m_ButtonRight;
+ case GHOST_kButtonMaskButton4:
+ return m_Button4;
+ case GHOST_kButtonMaskButton5:
+ return m_Button5;
+ case GHOST_kButtonMaskButton6:
+ return m_Button6;
+ case GHOST_kButtonMaskButton7:
+ return m_Button7;
default:
return false;
}
@@ -38,6 +46,18 @@ void GHOST_Buttons::set(GHOST_TButtonMask mask, bool down)
case GHOST_kButtonMaskRight:
m_ButtonRight = down;
break;
+ case GHOST_kButtonMaskButton4:
+ m_Button4 = down;
+ break;
+ case GHOST_kButtonMaskButton5:
+ m_Button5 = down;
+ break;
+ case GHOST_kButtonMaskButton6:
+ m_Button6 = down;
+ break;
+ case GHOST_kButtonMaskButton7:
+ m_Button7 = down;
+ break;
default:
break;
}
@@ -48,6 +68,10 @@ void GHOST_Buttons::clear()
m_ButtonLeft = false;
m_ButtonMiddle = false;
m_ButtonRight = false;
+ m_Button4 = false;
+ m_Button5 = false;
+ m_Button6 = false;
+ m_Button7 = false;
}
GHOST_Buttons::~GHOST_Buttons()
diff --git a/intern/ghost/intern/GHOST_Buttons.h b/intern/ghost/intern/GHOST_Buttons.h
index 17f25f1e082..72cb17a3322 100644
--- a/intern/ghost/intern/GHOST_Buttons.h
+++ b/intern/ghost/intern/GHOST_Buttons.h
@@ -44,4 +44,8 @@ struct GHOST_Buttons {
uint8_t m_ButtonLeft : 1;
uint8_t m_ButtonMiddle : 1;
uint8_t m_ButtonRight : 1;
+ uint8_t m_Button4 : 1;
+ uint8_t m_Button5 : 1;
+ uint8_t m_Button6 : 1;
+ uint8_t m_Button7 : 1;
};
diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp
index fa9e2a8f360..7417358e9ae 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextWGL.cpp
@@ -136,10 +136,10 @@ static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd, PIXELFORMATDESCRIPTOR
/* cull unusable pixel formats */
/* if no formats can be found, can we determine why it was rejected? */
if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL) || !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
- !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
+ !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this. */
!(pfd.iPixelType == PFD_TYPE_RGBA) ||
- (pfd.cColorBits > 32) || /* 64 bit formats disable aero */
- (pfd.dwFlags & PFD_GENERIC_FORMAT)) /* no software renderers */
+ (pfd.cColorBits > 32) || /* 64 bit formats disable AERO. */
+ (pfd.dwFlags & PFD_GENERIC_FORMAT)) /* No software renderers. */
{
return 0;
}
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index d088b6717f9..b013127d1f3 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -125,7 +125,7 @@ uint8_t GHOST_SystemSDL::getNumDisplays() const
return SDL_GetNumVideoDisplays();
}
-GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GLSettings glSettings)
+GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GLSettings /*glSettings*/)
{
GHOST_Context *context = new GHOST_ContextSDL(0,
NULL,
@@ -732,12 +732,12 @@ GHOST_TSuccess GHOST_SystemSDL::getButtons(GHOST_Buttons &buttons) const
return GHOST_kSuccess;
}
-char *GHOST_SystemSDL::getClipboard(bool selection) const
+char *GHOST_SystemSDL::getClipboard(bool /*selection*/) const
{
return (char *)SDL_GetClipboardText();
}
-void GHOST_SystemSDL::putClipboard(const char *buffer, bool selection) const
+void GHOST_SystemSDL::putClipboard(const char *buffer, bool /*selection*/) const
{
SDL_SetClipboardText(buffer);
}
diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h
index 77707924675..aefea5eda34 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.h
+++ b/intern/ghost/intern/GHOST_SystemSDL.h
@@ -33,7 +33,7 @@ class GHOST_SystemSDL : public GHOST_System {
bool processEvents(bool waitForEvent);
- int setConsoleWindowState(GHOST_TConsoleWindowState action)
+ int setConsoleWindowState(GHOST_TConsoleWindowState /*action*/)
{
return 0;
}
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index dae3d578fa0..24d3f525c97 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -38,7 +38,8 @@
#include <cstring>
-/* selected input event code defines from 'linux/input-event-codes.h'
+/**
+ * Selected input event code defines from `linux/input-event-codes.h`
* We include some of the button input event codes here, since the header is
* only available in more recent kernel versions. The event codes are used to
* to differentiate from which mouse button an event comes from.
@@ -46,6 +47,11 @@
#define BTN_LEFT 0x110
#define BTN_RIGHT 0x111
#define BTN_MIDDLE 0x112
+#define BTN_SIDE 0x113
+#define BTN_EXTRA 0x114
+#define BTN_FORWARD 0x115
+#define BTN_BACK 0x116
+// #define BTN_TASK 0x117 /* UNUSED. */
struct buffer_t {
void *data;
@@ -974,6 +980,18 @@ static void pointer_button(void *data,
case BTN_RIGHT:
ebutton = GHOST_kButtonMaskRight;
break;
+ case BTN_SIDE:
+ ebutton = GHOST_kButtonMaskButton4;
+ break;
+ case BTN_EXTRA:
+ ebutton = GHOST_kButtonMaskButton5;
+ break;
+ case BTN_FORWARD:
+ ebutton = GHOST_kButtonMaskButton6;
+ break;
+ case BTN_BACK:
+ ebutton = GHOST_kButtonMaskButton7;
+ break;
}
input->data_source->source_serial = serial;
@@ -1902,6 +1920,8 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
}
GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode,
+ const GHOST_TGrabCursorMode mode_current,
+
wl_surface *surface)
{
/* ignore, if the required protocols are not supported */
@@ -1915,36 +1935,37 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
input_t *input = d->inputs[0];
- switch (mode) {
- case GHOST_kGrabDisable:
- if (input->relative_pointer) {
- zwp_relative_pointer_v1_destroy(input->relative_pointer);
- input->relative_pointer = nullptr;
- }
- if (input->locked_pointer) {
- zwp_locked_pointer_v1_destroy(input->locked_pointer);
- input->locked_pointer = nullptr;
- }
- break;
-
- case GHOST_kGrabNormal:
- break;
- case GHOST_kGrabWrap:
- input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
- d->relative_pointer_manager, input->pointer);
- zwp_relative_pointer_v1_add_listener(
- input->relative_pointer, &relative_pointer_listener, input);
- input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
- d->pointer_constraints,
- surface,
- input->pointer,
- nullptr,
- ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
- break;
+ if (mode != GHOST_kGrabDisable) {
+ /* TODO(@campbellbarton): Support #GHOST_kGrabWrap,
+ * where the cursor moves but is constrained to a region. */
+ input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
+ d->relative_pointer_manager, input->pointer);
+ zwp_relative_pointer_v1_add_listener(
+ input->relative_pointer, &relative_pointer_listener, input);
+ input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
+ d->pointer_constraints,
+ surface,
+ input->pointer,
+ nullptr,
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+
+ if (mode == GHOST_kGrabHide) {
+ setCursorVisibility(false);
+ }
+ }
+ else {
+ if (input->relative_pointer) {
+ zwp_relative_pointer_v1_destroy(input->relative_pointer);
+ input->relative_pointer = nullptr;
+ }
+ if (input->locked_pointer) {
+ zwp_locked_pointer_v1_destroy(input->locked_pointer);
+ input->locked_pointer = nullptr;
+ }
- case GHOST_kGrabHide:
+ if (mode_current == GHOST_kGrabHide) {
setCursorVisibility(false);
- break;
+ }
}
return GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index 1f664915ad3..01b47358618 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -103,7 +103,9 @@ class GHOST_SystemWayland : public GHOST_System {
GHOST_TSuccess setCursorVisibility(bool visible);
- GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode, wl_surface *surface);
+ GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode,
+ const GHOST_TGrabCursorMode mode_current,
+ wl_surface *surface);
private:
struct display_t *d;
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index bbce6fdfdb5..54d38e1c0f3 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -1117,7 +1117,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
#else
/* In keyboards like Latin ones,
* numbers needs a 'Shift' to be accessed but key_sym
- * is unmodified (or anyone swapping the keys with xmodmap).
+ * is unmodified (or anyone swapping the keys with `xmodmap`).
*
* Here we look at the 'Shifted' version of the key.
* If it is a number, then we take it instead of the normal key.
@@ -1612,6 +1612,8 @@ GHOST_TSuccess GHOST_SystemX11::getButtons(GHOST_Buttons &buttons) const
buttons.set(GHOST_kButtonMaskLeft, (mask_return & Button1Mask) != 0);
buttons.set(GHOST_kButtonMaskMiddle, (mask_return & Button2Mask) != 0);
buttons.set(GHOST_kButtonMaskRight, (mask_return & Button3Mask) != 0);
+ buttons.set(GHOST_kButtonMaskButton4, (mask_return & Button4Mask) != 0);
+ buttons.set(GHOST_kButtonMaskButton5, (mask_return & Button5Mask) != 0);
}
else {
return GHOST_kFailure;
diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp
index 7a9ff348b0a..168949771c9 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.cpp
+++ b/intern/ghost/intern/GHOST_WindowSDL.cpp
@@ -22,7 +22,7 @@ GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system,
GHOST_TDrawingContextType type,
const bool stereoVisual,
const bool exclusive,
- const GHOST_IWindow *parentWindow)
+ const GHOST_IWindow * /*parentWindow*/)
: GHOST_Window(width, height, state, stereoVisual, exclusive),
m_system(system),
m_valid_setup(false),
@@ -581,7 +581,7 @@ static SDL_Cursor *getStandardCursorShape(GHOST_TStandardCursor shape)
return sdl_std_cursor_array[(int)shape];
}
-GHOST_TSuccess GHOST_WindowSDL::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
+GHOST_TSuccess GHOST_WindowSDL::setWindowCursorGrab(GHOST_TGrabCursorMode /*mode*/)
{
return GHOST_kSuccess;
}
@@ -602,15 +602,20 @@ GHOST_TSuccess GHOST_WindowSDL::hasCursorShape(GHOST_TStandardCursor shape)
return (getStandardCursorShape(shape)) ? GHOST_kSuccess : GHOST_kFailure;
}
-GHOST_TSuccess GHOST_WindowSDL::setWindowCustomCursorShape(
- uint8_t *bitmap, uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor)
+GHOST_TSuccess GHOST_WindowSDL::setWindowCustomCursorShape(uint8_t *bitmap,
+ uint8_t *mask,
+ int sizex,
+ int sizey,
+ int hotX,
+ int hotY,
+ bool /*canInvertColor*/)
{
if (m_sdl_custom_cursor) {
SDL_FreeCursor(m_sdl_custom_cursor);
}
m_sdl_custom_cursor = sdl_ghost_CreateCursor(
- (const Uint8 *)bitmap, (const Uint8 *)mask, sizex, sizex, hotX, hotY);
+ (const Uint8 *)bitmap, (const Uint8 *)mask, sizex, sizey, hotX, hotY);
SDL_SetCursor(m_sdl_custom_cursor);
return GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h
index cdea7e0d0b6..5805febab65 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.h
+++ b/intern/ghost/intern/GHOST_WindowSDL.h
@@ -109,7 +109,7 @@ class GHOST_WindowSDL : public GHOST_Window {
GHOST_TWindowState getState() const;
- GHOST_TSuccess setOrder(GHOST_TWindowOrder order)
+ GHOST_TSuccess setOrder(GHOST_TWindowOrder /*order*/)
{
// TODO
return GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index 7ae06623c91..7f2a2c992d9 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -320,7 +320,7 @@ int &GHOST_WindowWayland::scale()
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
{
- return m_system->setCursorGrab(mode, w->surface);
+ return m_system->setCursorGrab(mode, m_cursorGrab, w->surface);
}
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor shape)
diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc
index d78b34d3c92..8fc0ccd7918 100644
--- a/intern/opencolorio/fallback_impl.cc
+++ b/intern/opencolorio/fallback_impl.cc
@@ -241,10 +241,11 @@ void FallbackImpl::configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr * /*config*/,
rgb[2] = 0.0722f;
}
-void FallbackImpl::configGetXYZtoRGB(OCIO_ConstConfigRcPtr * /*config*/, float xyz_to_rgb[3][3])
+void FallbackImpl::configGetXYZtoSceneLinear(OCIO_ConstConfigRcPtr * /*config*/,
+ float xyz_to_scene_linear[3][3])
{
/* Default to ITU-BT.709. */
- memcpy(xyz_to_rgb, OCIO_XYZ_TO_LINEAR_SRGB, sizeof(OCIO_XYZ_TO_LINEAR_SRGB));
+ memcpy(xyz_to_scene_linear, OCIO_XYZ_TO_REC709, sizeof(OCIO_XYZ_TO_REC709));
}
int FallbackImpl::configGetNumLooks(OCIO_ConstConfigRcPtr * /*config*/)
diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc
index 5e4c2a87a0b..b31f3794361 100644
--- a/intern/opencolorio/ocio_capi.cc
+++ b/intern/opencolorio/ocio_capi.cc
@@ -118,9 +118,9 @@ void OCIO_configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb)
impl->configGetDefaultLumaCoefs(config, rgb);
}
-void OCIO_configGetXYZtoRGB(OCIO_ConstConfigRcPtr *config, float xyz_to_rgb[3][3])
+void OCIO_configGetXYZtoSceneLinear(OCIO_ConstConfigRcPtr *config, float xyz_to_scene_linear[3][3])
{
- impl->configGetXYZtoRGB(config, xyz_to_rgb);
+ impl->configGetXYZtoSceneLinear(config, xyz_to_scene_linear);
}
int OCIO_configGetNumLooks(OCIO_ConstConfigRcPtr *config)
diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h
index 9bd4ec374e2..97e6ff02779 100644
--- a/intern/opencolorio/ocio_capi.h
+++ b/intern/opencolorio/ocio_capi.h
@@ -31,10 +31,15 @@ OCIO_DECLARE_HANDLE(OCIO_ConstContextRcPtr);
OCIO_DECLARE_HANDLE(OCIO_PackedImageDesc);
OCIO_DECLARE_HANDLE(OCIO_ConstLookRcPtr);
-/* Standard XYZ to linear sRGB transform, for fallback. */
-static const float OCIO_XYZ_TO_LINEAR_SRGB[3][3] = {{3.2404542f, -0.9692660f, 0.0556434f},
- {-1.5371385f, 1.8760108f, -0.2040259f},
- {-0.4985314f, 0.0415560f, 1.0572252f}};
+/* Standard XYZ (D65) to linear Rec.709 transform. */
+static const float OCIO_XYZ_TO_REC709[3][3] = {{3.2404542f, -0.9692660f, 0.0556434f},
+ {-1.5371385f, 1.8760108f, -0.2040259f},
+ {-0.4985314f, 0.0415560f, 1.0572252f}};
+/* Standard ACES to XYZ (D65) transform.
+ * Matches OpenColorIO builtin transform: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD. */
+static const float OCIO_ACES_TO_XYZ[3][3] = {{0.938280f, 0.337369f, 0.001174f},
+ {-0.004451f, 0.729522f, -0.003711f},
+ {0.016628f, -0.066890f, 1.091595f}};
/* This structure is used to pass curve mapping settings from
* blender's DNA structure stored in view transform settings
@@ -130,7 +135,8 @@ const char *OCIO_configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config,
const char *view);
void OCIO_configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb);
-void OCIO_configGetXYZtoRGB(OCIO_ConstConfigRcPtr *config, float xyz_to_rgb[3][3]);
+void OCIO_configGetXYZtoSceneLinear(OCIO_ConstConfigRcPtr *config,
+ float xyz_to_scene_linear[3][3]);
int OCIO_configGetNumLooks(OCIO_ConstConfigRcPtr *config);
const char *OCIO_configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index);
diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc
index 8d9c5dd2d49..7cf7fbefcd6 100644
--- a/intern/opencolorio/ocio_impl.cc
+++ b/intern/opencolorio/ocio_impl.cc
@@ -311,13 +311,14 @@ static bool to_scene_linear_matrix(ConstConfigRcPtr &config,
return true;
}
-void OCIOImpl::configGetXYZtoRGB(OCIO_ConstConfigRcPtr *config_, float xyz_to_rgb[3][3])
+void OCIOImpl::configGetXYZtoSceneLinear(OCIO_ConstConfigRcPtr *config_,
+ float xyz_to_scene_linear[3][3])
{
ConstConfigRcPtr config = (*(ConstConfigRcPtr *)config_);
/* Default to ITU-BT.709 in case no appropriate transform found.
* Note XYZ is defined here as having a D65 white point. */
- memcpy(xyz_to_rgb, OCIO_XYZ_TO_LINEAR_SRGB, sizeof(OCIO_XYZ_TO_LINEAR_SRGB));
+ memcpy(xyz_to_scene_linear, OCIO_XYZ_TO_REC709, sizeof(OCIO_XYZ_TO_REC709));
/* Get from OpenColorO config if it has the required roles. */
if (!config->hasRole(ROLE_SCENE_LINEAR)) {
@@ -326,22 +327,17 @@ void OCIOImpl::configGetXYZtoRGB(OCIO_ConstConfigRcPtr *config_, float xyz_to_rg
if (config->hasRole("aces_interchange")) {
/* Standard OpenColorIO role, defined as ACES AP0 (ACES2065-1). */
- float aces_to_rgb[3][3];
- if (to_scene_linear_matrix(config, "aces_interchange", aces_to_rgb)) {
- /* This is the OpenColorIO builtin transform:
- * UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD. */
- const float ACES_AP0_to_xyz_D65[3][3] = {{0.938280f, 0.337369f, 0.001174f},
- {-0.004451f, 0.729522f, -0.003711f},
- {0.016628f, -0.066890f, 1.091595f}};
+ float aces_to_scene_linear[3][3];
+ if (to_scene_linear_matrix(config, "aces_interchange", aces_to_scene_linear)) {
float xyz_to_aces[3][3];
- invert_m3_m3(xyz_to_aces, ACES_AP0_to_xyz_D65);
+ invert_m3_m3(xyz_to_aces, OCIO_ACES_TO_XYZ);
- mul_m3_m3m3(xyz_to_rgb, aces_to_rgb, xyz_to_aces);
+ mul_m3_m3m3(xyz_to_scene_linear, aces_to_scene_linear, xyz_to_aces);
}
}
else if (config->hasRole("XYZ")) {
/* Custom role used before the standard existed. */
- to_scene_linear_matrix(config, "XYZ", xyz_to_rgb);
+ to_scene_linear_matrix(config, "XYZ", xyz_to_scene_linear);
}
}
diff --git a/intern/opencolorio/ocio_impl.h b/intern/opencolorio/ocio_impl.h
index f8397c62e52..2c00eff6d6c 100644
--- a/intern/opencolorio/ocio_impl.h
+++ b/intern/opencolorio/ocio_impl.h
@@ -48,7 +48,8 @@ class IOCIOImpl {
const char *view) = 0;
virtual void configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb) = 0;
- virtual void configGetXYZtoRGB(OCIO_ConstConfigRcPtr *config, float xyz_to_rgb[3][3]) = 0;
+ virtual void configGetXYZtoSceneLinear(OCIO_ConstConfigRcPtr *config,
+ float xyz_to_scene_linear[3][3]) = 0;
virtual int configGetNumLooks(OCIO_ConstConfigRcPtr *config) = 0;
virtual const char *configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index) = 0;
@@ -167,7 +168,7 @@ class FallbackImpl : public IOCIOImpl {
const char *view);
void configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb);
- void configGetXYZtoRGB(OCIO_ConstConfigRcPtr *config, float xyz_to_rgb[3][3]);
+ void configGetXYZtoSceneLinear(OCIO_ConstConfigRcPtr *config, float xyz_to_scene_linear[3][3]);
int configGetNumLooks(OCIO_ConstConfigRcPtr *config);
const char *configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index);
@@ -257,7 +258,7 @@ class OCIOImpl : public IOCIOImpl {
const char *view);
void configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb);
- void configGetXYZtoRGB(OCIO_ConstConfigRcPtr *config, float xyz_to_rgb[3][3]);
+ void configGetXYZtoSceneLinear(OCIO_ConstConfigRcPtr *config, float xyz_to_scene_linear[3][3]);
int configGetNumLooks(OCIO_ConstConfigRcPtr *config);
const char *configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index);
diff --git a/intern/opensubdiv/internal/evaluator/eval_output.h b/intern/opensubdiv/internal/evaluator/eval_output.h
index bc5494bfe41..c0da108edca 100644
--- a/intern/opensubdiv/internal/evaluator/eval_output.h
+++ b/intern/opensubdiv/internal/evaluator/eval_output.h
@@ -103,6 +103,10 @@ class EvalOutputAPI::EvalOutput {
{
}
+ virtual void wrapSrcVertexDataBuffer(OpenSubdiv_Buffer * /*src_buffer*/)
+ {
+ }
+
virtual void fillFVarPatchArraysBuffer(const int /*face_varying_channel*/,
OpenSubdiv_Buffer * /*patch_arrays_buffer*/)
{
@@ -122,6 +126,11 @@ class EvalOutputAPI::EvalOutput {
OpenSubdiv_Buffer * /*src_buffer*/)
{
}
+
+ virtual bool hasVertexData() const
+ {
+ return false;
+ }
};
namespace {
@@ -437,6 +446,11 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
return face_varying_evaluators_.size() != 0;
}
+ bool hasVertexData() const override
+ {
+ return src_vertex_data_ != nullptr;
+ }
+
void refine() override
{
// Evaluate vertex positions.
@@ -599,6 +613,11 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
return src_data_;
}
+ SRC_VERTEX_BUFFER *getSrcVertexDataBuffer() const
+ {
+ return src_vertex_data_;
+ }
+
PATCH_TABLE *getPatchTable() const
{
return patch_table_;
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc
index 566071d581b..274772b2c37 100644
--- a/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc
+++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc
@@ -86,6 +86,12 @@ void GpuEvalOutput::wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer)
src_buffer->wrap_device_handle(src_buffer, vertex_buffer->BindVBO());
}
+void GpuEvalOutput::wrapSrcVertexDataBuffer(OpenSubdiv_Buffer *src_buffer)
+{
+ GLVertexBuffer *vertex_buffer = getSrcVertexDataBuffer();
+ src_buffer->wrap_device_handle(src_buffer, vertex_buffer->BindVBO());
+}
+
void GpuEvalOutput::fillFVarPatchArraysBuffer(const int face_varying_channel,
OpenSubdiv_Buffer *patch_arrays_buffer)
{
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.h b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h
index 2306a87b87c..8a4950dd3bc 100644
--- a/intern/opensubdiv/internal/evaluator/eval_output_gpu.h
+++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h
@@ -52,6 +52,8 @@ class GpuEvalOutput : public VolatileEvalOutput<GLVertexBuffer,
void wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer) override;
+ void wrapSrcVertexDataBuffer(OpenSubdiv_Buffer *src_buffer) override;
+
void fillFVarPatchArraysBuffer(const int face_varying_channel,
OpenSubdiv_Buffer *patch_arrays_buffer) override;
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
index 8a54ed653dc..5a3a2ff131c 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
+++ b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
@@ -191,6 +191,12 @@ void wrapSrcBuffer(struct OpenSubdiv_Evaluator *evaluator, struct OpenSubdiv_Buf
evaluator->impl->eval_output->wrapSrcBuffer(src_buffer);
}
+void wrapSrcVertexDataBuffer(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *src_buffer)
+{
+ evaluator->impl->eval_output->wrapSrcVertexDataBuffer(src_buffer);
+}
+
void fillFVarPatchArraysBuffer(struct OpenSubdiv_Evaluator *evaluator,
const int face_varying_channel,
struct OpenSubdiv_Buffer *patch_array_buffer)
@@ -220,6 +226,11 @@ void wrapFVarSrcBuffer(struct OpenSubdiv_Evaluator *evaluator,
evaluator->impl->eval_output->wrapFVarSrcBuffer(face_varying_channel, src_buffer);
}
+bool hasVertexData(struct OpenSubdiv_Evaluator *evaluator)
+{
+ return evaluator->impl->eval_output->hasVertexData();
+}
+
void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
{
evaluator->setCoarsePositions = setCoarsePositions;
@@ -246,11 +257,14 @@ void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
evaluator->wrapPatchIndexBuffer = wrapPatchIndexBuffer;
evaluator->wrapPatchParamBuffer = wrapPatchParamBuffer;
evaluator->wrapSrcBuffer = wrapSrcBuffer;
+ evaluator->wrapSrcVertexDataBuffer = wrapSrcVertexDataBuffer;
evaluator->fillFVarPatchArraysBuffer = fillFVarPatchArraysBuffer;
evaluator->wrapFVarPatchIndexBuffer = wrapFVarPatchIndexBuffer;
evaluator->wrapFVarPatchParamBuffer = wrapFVarPatchParamBuffer;
evaluator->wrapFVarSrcBuffer = wrapFVarSrcBuffer;
+
+ evaluator->hasVertexData = hasVertexData;
}
} // namespace
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
index bb9e6e7bd0d..a5273cad13a 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
+++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
@@ -383,6 +383,11 @@ void EvalOutputAPI::wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer)
implementation_->wrapSrcBuffer(src_buffer);
}
+void EvalOutputAPI::wrapSrcVertexDataBuffer(OpenSubdiv_Buffer *src_buffer)
+{
+ implementation_->wrapSrcVertexDataBuffer(src_buffer);
+}
+
void EvalOutputAPI::fillFVarPatchArraysBuffer(const int face_varying_channel,
OpenSubdiv_Buffer *patch_arrays_buffer)
{
@@ -407,6 +412,11 @@ void EvalOutputAPI::wrapFVarSrcBuffer(const int face_varying_channel,
implementation_->wrapFVarSrcBuffer(face_varying_channel, src_buffer);
}
+bool EvalOutputAPI::hasVertexData() const
+{
+ return implementation_->hasVertexData();
+}
+
} // namespace opensubdiv
} // namespace blender
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.h b/intern/opensubdiv/internal/evaluator/evaluator_impl.h
index 8ecfa4477be..df8ef70cc01 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_impl.h
+++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.h
@@ -163,6 +163,9 @@ class EvalOutputAPI {
// Wrap the buffer used by OpenSubDiv for the source data with the given buffer.
void wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer);
+ // Wrap the buffer used by OpenSubDiv for the extra source data with the given buffer.
+ void wrapSrcVertexDataBuffer(OpenSubdiv_Buffer *src_buffer);
+
// Copy the patch arrays buffer used by OpenSubDiv for the face varying channel with the given
// buffer.
void fillFVarPatchArraysBuffer(const int face_varying_channel,
@@ -181,6 +184,9 @@ class EvalOutputAPI {
// Wrap thebuffer used by OpenSubDiv for the face varying channel with the given buffer.
void wrapFVarSrcBuffer(const int face_varying_channel, OpenSubdiv_Buffer *src_buffer);
+ // Return true if source vertex data has been set.
+ bool hasVertexData() const;
+
protected:
PatchMap *patch_map_;
EvalOutput *implementation_;
diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h
index 98e1db6e323..094244c4681 100644
--- a/intern/opensubdiv/opensubdiv_evaluator_capi.h
+++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h
@@ -195,6 +195,10 @@ typedef struct OpenSubdiv_Evaluator {
void (*wrapSrcBuffer)(struct OpenSubdiv_Evaluator *evaluator,
struct OpenSubdiv_Buffer *src_buffer);
+ // Fill the given buffer with data from the evaluator's extra source buffer.
+ void (*wrapSrcVertexDataBuffer)(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *src_buffer);
+
// Fill the given buffer with data from the evaluator's face varying patch array buffer.
void (*fillFVarPatchArraysBuffer)(struct OpenSubdiv_Evaluator *evaluator,
const int face_varying_channel,
@@ -215,6 +219,9 @@ typedef struct OpenSubdiv_Evaluator {
const int face_varying_channel,
struct OpenSubdiv_Buffer *src_buffer);
+ // Return true if the evaluator has source vertex data set.
+ bool (*hasVertexData)(struct OpenSubdiv_Evaluator *evaluator);
+
// Implementation of the evaluator.
struct OpenSubdiv_EvaluatorImpl *impl;
diff --git a/release/datafiles/blender_icons_geom.py b/release/datafiles/blender_icons_geom.py
index 815bc6d49a4..b95baf3419e 100644
--- a/release/datafiles/blender_icons_geom.py
+++ b/release/datafiles/blender_icons_geom.py
@@ -45,6 +45,8 @@ import bpy
# Generic functions
+OBJECTS_TYPES_MESH_COMPATIBLE = {'CURVE', 'MESH'}
+
def area_tri_signed_2x_v2(v1, v2, v3):
return (v1[0] - v2[0]) * (v2[1] - v3[1]) + (v1[1] - v2[1]) * (v3[0] - v2[0])
@@ -70,13 +72,14 @@ class TriMesh:
@staticmethod
def _tri_copy_from_object(ob):
import bmesh
- assert(ob.type == 'MESH')
+ assert(ob.type in OBJECTS_TYPES_MESH_COMPATIBLE)
bm = bmesh.new()
- bm.from_mesh(ob.data)
+ bm.from_mesh(ob.to_mesh())
bmesh.ops.triangulate(bm, faces=bm.faces)
me = bpy.data.meshes.new(ob.name + ".copy")
bm.to_mesh(me)
bm.free()
+ ob.to_mesh_clear()
return me
@@ -118,7 +121,7 @@ def object_child_map(objects):
def mesh_data_lists_from_mesh(me, material_colors):
me_loops = me.loops[:]
- me_loops_color = me.vertex_colors.active.data[:]
+ me_loops_color = me.attributes.active_color.data[:]
me_verts = me.vertices[:]
me_polys = me.polygons[:]
@@ -164,16 +167,30 @@ def mesh_data_lists_from_mesh(me, material_colors):
v1.co.xy[:],
v2.co.xy[:],
),
- # RGBA color.
- tuple((
- [int(c * b * 255) for c, b in zip(cn.color, base_color)]
- for cn in (c0, c1, c2)
- )),
+ # RGBA color in sRGB color space.
+ (
+ color_multiply_and_from_linear_to_srgb(base_color, c0),
+ color_multiply_and_from_linear_to_srgb(base_color, c1),
+ color_multiply_and_from_linear_to_srgb(base_color, c2),
+ ),
))
i1 = i2
return tris_data
+def color_multiply_and_from_linear_to_srgb(base_color, vertex_color):
+ """
+ Return the RGBA color in sRGB and byte format (0-255).
+
+ base_color and vertex_color are expected in linear space.
+ The final color is the product between the base color and the vertex color.
+ """
+ import mathutils
+ color_linear = [c * b for c, b in zip(vertex_color.color, base_color)]
+ color_srgb = mathutils.Color(color_linear[:3]).from_scene_linear_to_srgb()
+ return tuple(round(c * 255) for c in (*color_srgb, color_linear[3]))
+
+
def mesh_data_lists_from_objects(ob_parent, ob_children):
tris_data = []
@@ -203,7 +220,7 @@ def write_mesh_to_py(fh, ob, ob_children):
assert(axis_range <= 255)
# -1..1 -> 0..255
f = (f + 1.0) * 0.5
- f = int(round(f * axis_range))
+ f = round(f * axis_range)
return min(max(f, 0), axis_range)
def vert_as_byte_pair(v):
@@ -300,6 +317,7 @@ def main():
args = parser.parse_args(argv)
objects = []
+ depsgraph = bpy.context.view_layer.depsgraph
if args.group:
group = bpy.data.collections.get(args.group)
@@ -314,23 +332,25 @@ def main():
for ob in objects_source:
# Skip non-mesh objects
- if ob.type != 'MESH':
+ if ob.type not in OBJECTS_TYPES_MESH_COMPATIBLE:
continue
- name = ob.name
+
+ ob_eval = ob.evaluated_get(depsgraph)
+ name = ob_eval.name
# Skip copies of objects
if name.rpartition(".")[2].isdigit():
continue
- if not ob.data.vertex_colors:
+ if not ob_eval.data.attributes.active_color:
print("Skipping:", name, "(no vertex colors)")
continue
- objects.append((name, ob))
+ objects.append((name, ob_eval))
objects.sort(key=lambda a: a[0])
- objects_children = object_child_map(bpy.data.objects)
+ objects_children = object_child_map(depsgraph.objects)
for name, ob in objects:
if ob.parent:
diff --git a/release/datafiles/icons/brush.gpencil_draw.erase.dat b/release/datafiles/icons/brush.gpencil_draw.erase.dat
index 5b96035c9b8..d2faa6f2112 100644
--- a/release/datafiles/icons/brush.gpencil_draw.erase.dat
+++ b/release/datafiles/icons/brush.gpencil_draw.erase.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.paint_texture.multiply.dat b/release/datafiles/icons/brush.paint_texture.multiply.dat
index 948993203be..75fa09032a8 100644
--- a/release/datafiles/icons/brush.paint_texture.multiply.dat
+++ b/release/datafiles/icons/brush.paint_texture.multiply.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.paint_vertex.replace.dat b/release/datafiles/icons/brush.paint_vertex.replace.dat
index 676436548a7..a9a9d4f047f 100644
--- a/release/datafiles/icons/brush.paint_vertex.replace.dat
+++ b/release/datafiles/icons/brush.paint_vertex.replace.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.particle.comb.dat b/release/datafiles/icons/brush.particle.comb.dat
index d6dd75a35d7..1cdbcbadcdc 100644
--- a/release/datafiles/icons/brush.particle.comb.dat
+++ b/release/datafiles/icons/brush.particle.comb.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.particle.cut.dat b/release/datafiles/icons/brush.particle.cut.dat
index e7ef86e2fbc..0acc00660db 100644
--- a/release/datafiles/icons/brush.particle.cut.dat
+++ b/release/datafiles/icons/brush.particle.cut.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.particle.puff.dat b/release/datafiles/icons/brush.particle.puff.dat
index db2bab46bfe..72b4851cc89 100644
--- a/release/datafiles/icons/brush.particle.puff.dat
+++ b/release/datafiles/icons/brush.particle.puff.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.particle.smooth.dat b/release/datafiles/icons/brush.particle.smooth.dat
index 7deaa4ed082..ba4bd081f33 100644
--- a/release/datafiles/icons/brush.particle.smooth.dat
+++ b/release/datafiles/icons/brush.particle.smooth.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.boundary.dat b/release/datafiles/icons/brush.sculpt.boundary.dat
index 8d56baf2254..1b71d24d771 100644
--- a/release/datafiles/icons/brush.sculpt.boundary.dat
+++ b/release/datafiles/icons/brush.sculpt.boundary.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.cloth.dat b/release/datafiles/icons/brush.sculpt.cloth.dat
index 7e936167381..15ad0c7dc94 100644
--- a/release/datafiles/icons/brush.sculpt.cloth.dat
+++ b/release/datafiles/icons/brush.sculpt.cloth.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.displacement_eraser.dat b/release/datafiles/icons/brush.sculpt.displacement_eraser.dat
index e4637b9b12f..5c479fd59cb 100644
--- a/release/datafiles/icons/brush.sculpt.displacement_eraser.dat
+++ b/release/datafiles/icons/brush.sculpt.displacement_eraser.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.displacement_smear.dat b/release/datafiles/icons/brush.sculpt.displacement_smear.dat
index 9e4df45b2d2..ed84702cbd3 100644
--- a/release/datafiles/icons/brush.sculpt.displacement_smear.dat
+++ b/release/datafiles/icons/brush.sculpt.displacement_smear.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.draw_face_sets.dat b/release/datafiles/icons/brush.sculpt.draw_face_sets.dat
index a234aa7af2c..ade40de029d 100644
--- a/release/datafiles/icons/brush.sculpt.draw_face_sets.dat
+++ b/release/datafiles/icons/brush.sculpt.draw_face_sets.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.draw_sharp.dat b/release/datafiles/icons/brush.sculpt.draw_sharp.dat
index 9bea1b02894..cf606324b07 100644
--- a/release/datafiles/icons/brush.sculpt.draw_sharp.dat
+++ b/release/datafiles/icons/brush.sculpt.draw_sharp.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.elastic_deform.dat b/release/datafiles/icons/brush.sculpt.elastic_deform.dat
index 0b12d717d3a..db57ef2fac5 100644
--- a/release/datafiles/icons/brush.sculpt.elastic_deform.dat
+++ b/release/datafiles/icons/brush.sculpt.elastic_deform.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.fill.dat b/release/datafiles/icons/brush.sculpt.fill.dat
index b2898919bd4..08fe0711d33 100644
--- a/release/datafiles/icons/brush.sculpt.fill.dat
+++ b/release/datafiles/icons/brush.sculpt.fill.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.flatten.dat b/release/datafiles/icons/brush.sculpt.flatten.dat
index 25b5f0cf8a9..a4439d75eed 100644
--- a/release/datafiles/icons/brush.sculpt.flatten.dat
+++ b/release/datafiles/icons/brush.sculpt.flatten.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.grab.dat b/release/datafiles/icons/brush.sculpt.grab.dat
index 0b61977e792..819c9263b45 100644
--- a/release/datafiles/icons/brush.sculpt.grab.dat
+++ b/release/datafiles/icons/brush.sculpt.grab.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.layer.dat b/release/datafiles/icons/brush.sculpt.layer.dat
index 1031d95332a..337362185e0 100644
--- a/release/datafiles/icons/brush.sculpt.layer.dat
+++ b/release/datafiles/icons/brush.sculpt.layer.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.multiplane_scrape.dat b/release/datafiles/icons/brush.sculpt.multiplane_scrape.dat
index 6e17f520282..ea64b2d9e45 100644
--- a/release/datafiles/icons/brush.sculpt.multiplane_scrape.dat
+++ b/release/datafiles/icons/brush.sculpt.multiplane_scrape.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.nudge.dat b/release/datafiles/icons/brush.sculpt.nudge.dat
index e10157e9cd0..f5a93ede065 100644
--- a/release/datafiles/icons/brush.sculpt.nudge.dat
+++ b/release/datafiles/icons/brush.sculpt.nudge.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.pinch.dat b/release/datafiles/icons/brush.sculpt.pinch.dat
index abdb62dcfc8..7dbbdef3bcc 100644
--- a/release/datafiles/icons/brush.sculpt.pinch.dat
+++ b/release/datafiles/icons/brush.sculpt.pinch.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.pose.dat b/release/datafiles/icons/brush.sculpt.pose.dat
index 6183583ea27..6bd7764bf23 100644
--- a/release/datafiles/icons/brush.sculpt.pose.dat
+++ b/release/datafiles/icons/brush.sculpt.pose.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.rotate.dat b/release/datafiles/icons/brush.sculpt.rotate.dat
index 8d1723a8c71..b7b8f083bde 100644
--- a/release/datafiles/icons/brush.sculpt.rotate.dat
+++ b/release/datafiles/icons/brush.sculpt.rotate.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.scrape.dat b/release/datafiles/icons/brush.sculpt.scrape.dat
index 9b37a9876a1..afb5a46a3bd 100644
--- a/release/datafiles/icons/brush.sculpt.scrape.dat
+++ b/release/datafiles/icons/brush.sculpt.scrape.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.smooth.dat b/release/datafiles/icons/brush.sculpt.smooth.dat
index 36d8098ad26..c42049cb51a 100644
--- a/release/datafiles/icons/brush.sculpt.smooth.dat
+++ b/release/datafiles/icons/brush.sculpt.smooth.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.snake_hook.dat b/release/datafiles/icons/brush.sculpt.snake_hook.dat
index 20300c1d97c..ce47b7141cf 100644
--- a/release/datafiles/icons/brush.sculpt.snake_hook.dat
+++ b/release/datafiles/icons/brush.sculpt.snake_hook.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.thumb.dat b/release/datafiles/icons/brush.sculpt.thumb.dat
index 9da33eccd98..f54a141eca7 100644
--- a/release/datafiles/icons/brush.sculpt.thumb.dat
+++ b/release/datafiles/icons/brush.sculpt.thumb.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.topology.dat b/release/datafiles/icons/brush.sculpt.topology.dat
index 0d455dce556..ec3699a7c2d 100644
--- a/release/datafiles/icons/brush.sculpt.topology.dat
+++ b/release/datafiles/icons/brush.sculpt.topology.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.uv_sculpt.relax.dat b/release/datafiles/icons/brush.uv_sculpt.relax.dat
index 3a30ac72cb6..1df2828c669 100644
--- a/release/datafiles/icons/brush.uv_sculpt.relax.dat
+++ b/release/datafiles/icons/brush.uv_sculpt.relax.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.armature.bone.roll.dat b/release/datafiles/icons/ops.armature.bone.roll.dat
index bb5158c43c9..3945b2fdffd 100644
--- a/release/datafiles/icons/ops.armature.bone.roll.dat
+++ b/release/datafiles/icons/ops.armature.bone.roll.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curve.pen.dat b/release/datafiles/icons/ops.curve.pen.dat
index 1007f7ea604..8031fdd8606 100644
--- a/release/datafiles/icons/ops.curve.pen.dat
+++ b/release/datafiles/icons/ops.curve.pen.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curve.radius.dat b/release/datafiles/icons/ops.curve.radius.dat
index 1c887bc11e7..e7b7913fb22 100644
--- a/release/datafiles/icons/ops.curve.radius.dat
+++ b/release/datafiles/icons/ops.curve.radius.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curve.vertex_random.dat b/release/datafiles/icons/ops.curve.vertex_random.dat
index ced246f4eae..75f1973c7a3 100644
--- a/release/datafiles/icons/ops.curve.vertex_random.dat
+++ b/release/datafiles/icons/ops.curve.vertex_random.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_comb.dat b/release/datafiles/icons/ops.curves.sculpt_comb.dat
index d6dd75a35d7..1cdbcbadcdc 100644
--- a/release/datafiles/icons/ops.curves.sculpt_comb.dat
+++ b/release/datafiles/icons/ops.curves.sculpt_comb.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_cut.dat b/release/datafiles/icons/ops.curves.sculpt_cut.dat
index e7ef86e2fbc..0acc00660db 100644
--- a/release/datafiles/icons/ops.curves.sculpt_cut.dat
+++ b/release/datafiles/icons/ops.curves.sculpt_cut.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_delete.dat b/release/datafiles/icons/ops.curves.sculpt_delete.dat
index 896d472e017..bd76aef9a81 100644
--- a/release/datafiles/icons/ops.curves.sculpt_delete.dat
+++ b/release/datafiles/icons/ops.curves.sculpt_delete.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_pinch.dat b/release/datafiles/icons/ops.curves.sculpt_pinch.dat
new file mode 100644
index 00000000000..49f40efc931
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_pinch.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_puff.dat b/release/datafiles/icons/ops.curves.sculpt_puff.dat
index db2bab46bfe..72b4851cc89 100644
--- a/release/datafiles/icons/ops.curves.sculpt_puff.dat
+++ b/release/datafiles/icons/ops.curves.sculpt_puff.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.generic.select_box.dat b/release/datafiles/icons/ops.generic.select_box.dat
index da435ab3925..609c2f76927 100644
--- a/release/datafiles/icons/ops.generic.select_box.dat
+++ b/release/datafiles/icons/ops.generic.select_box.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.generic.select_circle.dat b/release/datafiles/icons/ops.generic.select_circle.dat
index 83e1deb119d..d9fcda69be1 100644
--- a/release/datafiles/icons/ops.generic.select_circle.dat
+++ b/release/datafiles/icons/ops.generic.select_circle.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.generic.select_lasso.dat b/release/datafiles/icons/ops.generic.select_lasso.dat
index 54994c48a3d..f8ec3d4d199 100644
--- a/release/datafiles/icons/ops.generic.select_lasso.dat
+++ b/release/datafiles/icons/ops.generic.select_lasso.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.generic.select_paint.dat b/release/datafiles/icons/ops.generic.select_paint.dat
index 26d76d4548f..745cd073967 100644
--- a/release/datafiles/icons/ops.generic.select_paint.dat
+++ b/release/datafiles/icons/ops.generic.select_paint.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.draw.eraser.dat b/release/datafiles/icons/ops.gpencil.draw.eraser.dat
index 44f65c4581d..d1be26fa43f 100644
--- a/release/datafiles/icons/ops.gpencil.draw.eraser.dat
+++ b/release/datafiles/icons/ops.gpencil.draw.eraser.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.edit_bend.dat b/release/datafiles/icons/ops.gpencil.edit_bend.dat
index 81fcb7cbf27..ebbddf6a455 100644
--- a/release/datafiles/icons/ops.gpencil.edit_bend.dat
+++ b/release/datafiles/icons/ops.gpencil.edit_bend.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.edit_shear.dat b/release/datafiles/icons/ops.gpencil.edit_shear.dat
index e591b102499..6f1f53d0ea0 100644
--- a/release/datafiles/icons/ops.gpencil.edit_shear.dat
+++ b/release/datafiles/icons/ops.gpencil.edit_shear.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.edit_to_sphere.dat b/release/datafiles/icons/ops.gpencil.edit_to_sphere.dat
index 485d0a80c79..32bbb64fdba 100644
--- a/release/datafiles/icons/ops.gpencil.edit_to_sphere.dat
+++ b/release/datafiles/icons/ops.gpencil.edit_to_sphere.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.radius.dat b/release/datafiles/icons/ops.gpencil.radius.dat
index 1c887bc11e7..e7b7913fb22 100644
--- a/release/datafiles/icons/ops.gpencil.radius.dat
+++ b/release/datafiles/icons/ops.gpencil.radius.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.stroke_cutter.dat b/release/datafiles/icons/ops.gpencil.stroke_cutter.dat
index 31a130a23f5..d69e61cf74f 100644
--- a/release/datafiles/icons/ops.gpencil.stroke_cutter.dat
+++ b/release/datafiles/icons/ops.gpencil.stroke_cutter.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.transform_fill.dat b/release/datafiles/icons/ops.gpencil.transform_fill.dat
index a364882d33f..8983a6c5eaf 100644
--- a/release/datafiles/icons/ops.gpencil.transform_fill.dat
+++ b/release/datafiles/icons/ops.gpencil.transform_fill.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.mesh.rip.dat b/release/datafiles/icons/ops.mesh.rip.dat
index fb1000c66aa..d55520ab18f 100644
--- a/release/datafiles/icons/ops.mesh.rip.dat
+++ b/release/datafiles/icons/ops.mesh.rip.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.mesh.rip_edge.dat b/release/datafiles/icons/ops.mesh.rip_edge.dat
index e8b494e07c9..d60b969c714 100644
--- a/release/datafiles/icons/ops.mesh.rip_edge.dat
+++ b/release/datafiles/icons/ops.mesh.rip_edge.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.mesh.vertices_smooth.dat b/release/datafiles/icons/ops.mesh.vertices_smooth.dat
index e460bbaeed8..aa1ea6d424e 100644
--- a/release/datafiles/icons/ops.mesh.vertices_smooth.dat
+++ b/release/datafiles/icons/ops.mesh.vertices_smooth.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.node.links_cut.dat b/release/datafiles/icons/ops.node.links_cut.dat
index dbe79cb9661..2ca6f360cfc 100644
--- a/release/datafiles/icons/ops.node.links_cut.dat
+++ b/release/datafiles/icons/ops.node.links_cut.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.pose.push.dat b/release/datafiles/icons/ops.pose.push.dat
index 9a56909dbac..58b838eb558 100644
--- a/release/datafiles/icons/ops.pose.push.dat
+++ b/release/datafiles/icons/ops.pose.push.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.pose.relax.dat b/release/datafiles/icons/ops.pose.relax.dat
index e9849dcb374..32430f479b7 100644
--- a/release/datafiles/icons/ops.pose.relax.dat
+++ b/release/datafiles/icons/ops.pose.relax.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.border_face_set.dat b/release/datafiles/icons/ops.sculpt.border_face_set.dat
index a34bcd461eb..55343c5ba8f 100644
--- a/release/datafiles/icons/ops.sculpt.border_face_set.dat
+++ b/release/datafiles/icons/ops.sculpt.border_face_set.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.box_trim.dat b/release/datafiles/icons/ops.sculpt.box_trim.dat
index 558c2b162ac..96e98b97785 100644
--- a/release/datafiles/icons/ops.sculpt.box_trim.dat
+++ b/release/datafiles/icons/ops.sculpt.box_trim.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.cloth_filter.dat b/release/datafiles/icons/ops.sculpt.cloth_filter.dat
index dc20c8f0bfd..2dd3b983368 100644
--- a/release/datafiles/icons/ops.sculpt.cloth_filter.dat
+++ b/release/datafiles/icons/ops.sculpt.cloth_filter.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.face_set_edit.dat b/release/datafiles/icons/ops.sculpt.face_set_edit.dat
index 2e5ec79ef8c..ad83305374a 100644
--- a/release/datafiles/icons/ops.sculpt.face_set_edit.dat
+++ b/release/datafiles/icons/ops.sculpt.face_set_edit.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.lasso_face_set.dat b/release/datafiles/icons/ops.sculpt.lasso_face_set.dat
index 55c044a2ed1..a4d32f56c99 100644
--- a/release/datafiles/icons/ops.sculpt.lasso_face_set.dat
+++ b/release/datafiles/icons/ops.sculpt.lasso_face_set.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.lasso_trim.dat b/release/datafiles/icons/ops.sculpt.lasso_trim.dat
index 60c33fc9f2f..32e9c74e00b 100644
--- a/release/datafiles/icons/ops.sculpt.lasso_trim.dat
+++ b/release/datafiles/icons/ops.sculpt.lasso_trim.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.bone_envelope.dat b/release/datafiles/icons/ops.transform.bone_envelope.dat
index 2f684152e5f..26238814e9e 100644
--- a/release/datafiles/icons/ops.transform.bone_envelope.dat
+++ b/release/datafiles/icons/ops.transform.bone_envelope.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.bone_size.dat b/release/datafiles/icons/ops.transform.bone_size.dat
index d884056d76c..e00d14df608 100644
--- a/release/datafiles/icons/ops.transform.bone_size.dat
+++ b/release/datafiles/icons/ops.transform.bone_size.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.edge_slide.dat b/release/datafiles/icons/ops.transform.edge_slide.dat
index 7fb29564551..851b84915ef 100644
--- a/release/datafiles/icons/ops.transform.edge_slide.dat
+++ b/release/datafiles/icons/ops.transform.edge_slide.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.push_pull.dat b/release/datafiles/icons/ops.transform.push_pull.dat
index e9a74bfd6e2..51f01da16d2 100644
--- a/release/datafiles/icons/ops.transform.push_pull.dat
+++ b/release/datafiles/icons/ops.transform.push_pull.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.resize.cage.dat b/release/datafiles/icons/ops.transform.resize.cage.dat
index 8eabffad087..f4e94c7f804 100644
--- a/release/datafiles/icons/ops.transform.resize.cage.dat
+++ b/release/datafiles/icons/ops.transform.resize.cage.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.resize.dat b/release/datafiles/icons/ops.transform.resize.dat
index 9c26224da68..0d1b5f60e62 100644
--- a/release/datafiles/icons/ops.transform.resize.dat
+++ b/release/datafiles/icons/ops.transform.resize.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.rotate.dat b/release/datafiles/icons/ops.transform.rotate.dat
index f42bd25137e..0afb420aab7 100644
--- a/release/datafiles/icons/ops.transform.rotate.dat
+++ b/release/datafiles/icons/ops.transform.rotate.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.shear.dat b/release/datafiles/icons/ops.transform.shear.dat
index 92912e2cfb7..aeadc7e3701 100644
--- a/release/datafiles/icons/ops.transform.shear.dat
+++ b/release/datafiles/icons/ops.transform.shear.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.shrink_fatten.dat b/release/datafiles/icons/ops.transform.shrink_fatten.dat
index 8d1d4c130a4..5c683c94c96 100644
--- a/release/datafiles/icons/ops.transform.shrink_fatten.dat
+++ b/release/datafiles/icons/ops.transform.shrink_fatten.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.tilt.dat b/release/datafiles/icons/ops.transform.tilt.dat
index a0f1040e1cf..70316d37d81 100644
--- a/release/datafiles/icons/ops.transform.tilt.dat
+++ b/release/datafiles/icons/ops.transform.tilt.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.tosphere.dat b/release/datafiles/icons/ops.transform.tosphere.dat
index b55b4b1f283..5976ac5e224 100644
--- a/release/datafiles/icons/ops.transform.tosphere.dat
+++ b/release/datafiles/icons/ops.transform.tosphere.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.vert_slide.dat b/release/datafiles/icons/ops.transform.vert_slide.dat
index 26e8696e336..1f97030e99b 100644
--- a/release/datafiles/icons/ops.transform.vert_slide.dat
+++ b/release/datafiles/icons/ops.transform.vert_slide.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.transform.vertex_random.dat b/release/datafiles/icons/ops.transform.vertex_random.dat
index 876d0649dbd..b094f0658e9 100644
--- a/release/datafiles/icons/ops.transform.vertex_random.dat
+++ b/release/datafiles/icons/ops.transform.vertex_random.dat
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject fb1eac2ec80c0adee69990a5386b74a5bd4ca00
+Subproject 647c85462d87c3a9d3a189d28d72d1bd93f4d4a
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 7025cd28ede25eb44208722f842e35b10325c6c
+Subproject d936e4c01fa263a71a7d0665628ae621283b15e
diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py
index 687f3c95d0b..04120508df5 100644
--- a/release/scripts/modules/rna_info.py
+++ b/release/scripts/modules/rna_info.py
@@ -61,7 +61,8 @@ def range_str(val):
def float_as_string(f):
val_str = "%g" % f
- if '.' not in val_str and '-' not in val_str: # value could be 1e-05
+ # Ensure a `.0` suffix for whole numbers, excluding scientific notation such as `1e-05` or `1e+5`.
+ if '.' not in val_str and 'e' not in val_str:
val_str += '.0'
return val_str
@@ -584,6 +585,16 @@ def BuildRNAInfo():
structs = []
def _bpy_types_iterator():
+ # Don't report when these types are ignored.
+ suppress_warning = {
+ "bpy_func",
+ "bpy_prop",
+ "bpy_prop_array",
+ "bpy_prop_collection",
+ "bpy_struct",
+ "bpy_struct_meta_idprop",
+ }
+
names_unique = set()
rna_type_list = []
for rna_type_name in dir(bpy.types):
@@ -593,8 +604,13 @@ def BuildRNAInfo():
if rna_struct is not None:
rna_type_list.append(rna_type)
yield (rna_type_name, rna_struct)
+ elif rna_type_name.startswith("_"):
+ # Ignore "__dir__", "__getattr__" .. etc.
+ pass
+ elif rna_type_name in suppress_warning:
+ pass
else:
- print("Ignoring", rna_type_name)
+ print("rna_info.BuildRNAInfo(..): ignoring type", repr(rna_type_name))
# Now, there are some sub-classes in add-ons we also want to include.
# Cycles for e.g. these are referenced from the Scene, but not part of
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 9c94029fa16..a4bac916946 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -2031,13 +2031,9 @@ def km_node_editor(params):
items.extend(_template_node_select(type='LEFTMOUSE', value='PRESS', select_passthrough=True))
else:
items.extend(_template_node_select(
- type='RIGHTMOUSE', value=params.select_mouse_value, select_passthrough=False))
- items.extend([
- ("node.select", {"type": 'LEFTMOUSE', "value": 'PRESS'},
- {"properties": [("deselect_all", False)]}),
- ("node.select", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
- {"properties": [("toggle", True)]}),
- ])
+ type='RIGHTMOUSE', value=params.select_mouse_value, select_passthrough=True))
+ items.extend(_template_node_select(
+ type='LEFTMOUSE', value='PRESS', select_passthrough=True))
items.extend([
("node.select_box", {"type": params.select_mouse, "value": 'CLICK_DRAG'},
@@ -4795,7 +4791,7 @@ def _template_view3d_gpencil_select(*, type, value, legacy, use_select_mouse=Tru
def _template_node_select(*, type, value, select_passthrough):
items = [
("node.select", {"type": type, "value": value},
- {"properties": [("deselect_all", True), ("select_passthrough", True)]}),
+ {"properties": [("deselect_all", True), ("select_passthrough", select_passthrough)]}),
("node.select", {"type": type, "value": value, "ctrl": True}, None),
("node.select", {"type": type, "value": value, "alt": True}, None),
("node.select", {"type": type, "value": value, "ctrl": True, "alt": True}, None),
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 0f063da40fb..37d7ef19a28 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -21,10 +21,68 @@ from bpy.props import (
)
from bpy.app.translations import pgettext_iface as iface_
+
+def _rna_path_prop_search_for_context_impl(context, edit_text, unique_attrs):
+ # Use the same logic as auto-completing in the Python console to expand the data-path.
+ from bl_console_utils.autocomplete import intellisense
+ context_prefix = "context."
+ line = context_prefix + edit_text
+ cursor = len(line)
+ namespace = {"context": context}
+ comp_prefix, _, comp_options = intellisense.expand(line=line, cursor=len(line), namespace=namespace, private=False)
+ prefix = comp_prefix[len(context_prefix):] # Strip "context."
+ for attr in comp_options.split("\n"):
+ if attr.endswith((
+ # Exclude function calls because they are generally not part of data-paths.
+ "(", ")",
+ # RNA properties for introspection, not useful to expand.
+ ".bl_rna", ".rna_type",
+ )):
+ continue
+ attr_full = prefix + attr.lstrip()
+ if attr_full in unique_attrs:
+ continue
+ unique_attrs.add(attr_full)
+ yield attr_full
+
+
+def rna_path_prop_search_for_context(self, context, edit_text):
+ # NOTE(@campbellbarton): Limiting data-path expansion is rather arbitrary.
+ # It's possible for e.g. that someone would want to set a shortcut in the preferences or
+ # in other region types than those currently expanded. Unless there is a reasonable likelihood
+ # users might expand these space-type/region-type combinations - exclude them from this search.
+ # After all, this list is mainly intended as a hint, users are not prevented from constructing
+ # the data-paths themselves.
+ unique_attrs = set()
+
+ for window in context.window_manager.windows:
+ for area in window.screen.areas:
+ # Users are very unlikely to be setting shortcuts in the preferences, skip this.
+ if area.type == 'PREFERENCES':
+ continue
+ space = area.spaces.active
+ # Ignore the same region type multiple times in an area.
+ # Prevents the 3D-viewport quad-view from attempting to expand 3 extra times for e.g.
+ region_type_unique = set()
+ for region in area.regions:
+ if region.type not in {'WINDOW', 'PREVIEW'}:
+ continue
+ if region.type in region_type_unique:
+ continue
+ region_type_unique.add(region.type)
+ with context.temp_override(window=window, area=area, region=region):
+ yield from _rna_path_prop_search_for_context_impl(context, edit_text, unique_attrs)
+
+ if not unique_attrs:
+ # Users *might* only have a preferences area shown, in that case just expand the current context.
+ yield from _rna_path_prop_search_for_context_impl(context, edit_text, unique_attrs)
+
+
rna_path_prop = StringProperty(
name="Context Attributes",
- description="RNA context string",
+ description="Context data-path (expanded using visible windows in the current .blend file)",
maxlen=1024,
+ search=rna_path_prop_search_for_context,
)
rna_reverse_prop = BoolProperty(
diff --git a/release/scripts/startup/bl_ui/properties_data_volume.py b/release/scripts/startup/bl_ui/properties_data_volume.py
index 678972a677c..98855d4b516 100644
--- a/release/scripts/startup/bl_ui/properties_data_volume.py
+++ b/release/scripts/startup/bl_ui/properties_data_volume.py
@@ -115,6 +115,9 @@ class DATA_PT_volume_render(DataButtonsPanel, Panel):
col = layout.column(align=True)
col.prop(render, "clipping")
+ col = layout.column()
+ col.prop(render, "precision")
+
col = layout.column(align=False)
col.prop(volume, "velocity_grid")
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 6b55683ee89..f186fca0849 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -245,7 +245,7 @@ class GPENCIL_MT_move_to_layer(Menu):
icon = 'GREASEPENCIL'
else:
icon = 'NONE'
- layout.operator("gpencil.move_to_layer", text=gpl.info, icon=icon).layer = i
+ layout.operator("gpencil.move_to_layer", text=gpl.info, icon=icon, translate=False).layer = i
i -= 1
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index 31552111276..92cfa7e8219 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -696,11 +696,12 @@ class ASSETBROWSEROLD_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
prefs = context.preferences
show_asset_debug_info = prefs.view.show_developer_ui and prefs.experimental.show_asset_debug_info
+ is_local_asset = bool(asset_file_handle.local_id)
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
- if asset_file_handle.local_id:
+ if is_local_asset:
# If the active file is an ID, use its name directly so renaming is possible from right here.
layout.prop(asset_file_handle.local_id, "name")
@@ -720,7 +721,7 @@ class ASSETBROWSEROLD_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
col.prop(asset_file_handle.asset_data, "catalog_simple_name", text="Simple Name")
row = layout.row(align=True)
- row.prop(wm, "asset_path_dummy", text="Source")
+ row.prop(wm, "asset_path_dummy", text="Source", icon='CURRENT_FILE' if is_local_asset else 'NONE')
row.operator("asset.open_containing_blend_file", text="", icon='TOOL_SETTINGS')
layout.prop(asset_file_handle.asset_data, "description")
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index bcc5976fb59..1af70895be9 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2295,6 +2295,8 @@ class VIEW3D_MT_object_relations(Menu):
layout = self.layout
layout.operator("object.make_override_library", text="Make Library Override...")
+ layout.operator("object.make_override_library",
+ text="Make Library Override - Fully Editable...").do_fully_editable = True
layout.operator("object.make_dupli_face")
diff --git a/release/scripts/templates_py/gizmo_operator.py b/release/scripts/templates_py/gizmo_operator.py
index 450f67ba3a4..75595b0c5ea 100644
--- a/release/scripts/templates_py/gizmo_operator.py
+++ b/release/scripts/templates_py/gizmo_operator.py
@@ -84,7 +84,7 @@ class SelectSideOfPlaneGizmoGroup(GizmoGroup):
bl_label = "Side of Plane Gizmo"
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
- bl_options = {'3D'}
+ bl_options = {'3D', 'EXCLUDE_MODAL'}
# Helper functions
@staticmethod
@@ -199,7 +199,8 @@ class SelectSideOfPlaneGizmoGroup(GizmoGroup):
matrix.col[0].xyz = no_x
matrix.col[1].xyz = no_y
matrix.col[2].xyz = no_z
- matrix.col[3].xyz = co
+ # The location callback handles the location.
+ # `matrix.col[3].xyz = co`.
# Dial
no_z = self.rotate_axis
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 8f33003fa9d..d22abd235df 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -157,25 +157,6 @@ BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
int tree_type,
int axis);
-/**
- * Builds a BVH-tree where nodes are the given tessellated faces
- * (NOTE: does not copy given mfaces!).
- * \param vert_allocated: if true, vert freeing will be done when freeing data.
- * \param face_allocated: if true, face freeing will be done when freeing data.
- * \param faces_mask: if not null, true elements give which faces to add to BVH-tree.
- * \param faces_num_active: if >= 0, number of active faces to add to BVH-tree
- * (else will be computed from mask).
- */
-BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
- const struct MVert *vert,
- const struct MFace *face,
- int numFaces,
- const BLI_bitmap *faces_mask,
- int faces_num_active,
- float epsilon,
- int tree_type,
- int axis);
-
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
@@ -192,8 +173,6 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
/**
* Builds a BVH-tree where nodes are the looptri faces of the given mesh.
- *
- * \note for edit-mesh this is currently a duplicate of #bvhtree_from_mesh_faces_ex
*/
BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index d32f754c6c0..a21d9141ac0 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -263,7 +263,9 @@ void BKE_defvert_extract_vgroup_to_polyweights(const struct MDeformVert *dvert,
void BKE_defvert_weight_to_rgb(float r_rgb[3], float weight);
-void BKE_defvert_blend_write(struct BlendWriter *writer, int count, struct MDeformVert *dvlist);
+void BKE_defvert_blend_write(struct BlendWriter *writer,
+ int count,
+ const struct MDeformVert *dvlist);
void BKE_defvert_blend_read(struct BlendDataReader *reader,
int count,
struct MDeformVert *mdverts);
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 06feb07aef2..96b6f7a53b0 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -81,6 +81,7 @@ typedef struct Global {
* * 1 - 30: EEVEE debug/stats values (01/2018).
* * 31: Enable the Select Debug Engine. Only available with #WITH_DRAW_DEBUG (08/2021).
* * 101: Enable UI debug drawing of fullscreen area's corner widget (10/2014).
+ * * 102: Enable extra items in string search UI (05/2022).
* * 666: Use quicker batch delete for outliners' delete hierarchy (01/2019).
* * 777: Enable UI node panel's sockets polling (11/2011).
* * 799: Enable some mysterious new depsgraph behavior (05/2015).
diff --git a/source/blender/blenkernel/BKE_image_partial_update.hh b/source/blender/blenkernel/BKE_image_partial_update.hh
index 393bf003caa..6611efe7a61 100644
--- a/source/blender/blenkernel/BKE_image_partial_update.hh
+++ b/source/blender/blenkernel/BKE_image_partial_update.hh
@@ -172,6 +172,11 @@ class ImageTileData : AbstractTileData {
if (image_user != nullptr) {
this->image_user = *image_user;
}
+ else {
+ /* When no image user is given the lastframe of the image should be used. This reflect the
+ * same logic when using a stencil image in the clone tool. */
+ this->image_user.framenr = image->lastframe;
+ }
}
void init_data(TileNumber new_tile_number) override
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index dfb2b900b10..38de4bebdbd 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -116,6 +116,8 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
* \param do_no_main: Create the new override data outside of Main database.
* Used for resyncing of linked overrides.
*
+ * \param do_fully_editable: if true, tag all created overrides as user-editable by default.
+ *
* \return \a true on success, \a false otherwise.
*/
bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
@@ -123,7 +125,8 @@ bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
const struct ID *id_root_reference,
struct ID *id_hierarchy_root,
const struct ID *id_hierarchy_root_reference,
- bool do_no_main);
+ bool do_no_main,
+ const bool do_fully_editable);
/**
* Advanced 'smart' function to create fully functional overrides.
*
@@ -154,6 +157,8 @@ bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
*
* \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
*
+ * \param do_fully_editable: if true, tag all created overrides as user-editable by default.
+ *
* \return true if override was successfully created.
*/
bool BKE_lib_override_library_create(struct Main *bmain,
@@ -163,7 +168,8 @@ bool BKE_lib_override_library_create(struct Main *bmain,
struct ID *id_root_reference,
struct ID *id_hierarchy_root_reference,
struct ID *id_instance_hint,
- struct ID **r_id_root_override);
+ struct ID **r_id_root_override,
+ const bool do_fully_editable);
/**
* Create a library override template.
*/
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
index be4b671ef75..ebf48acde0f 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -458,17 +458,6 @@ static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *ins
return NULL;
}
- if (item->action == LINK_APPEND_ACT_COPY_LOCAL) {
- BLI_assert(ID_IS_LINKED(id));
- id = id->newid;
- if (id == NULL) {
- return NULL;
- }
-
- BLI_assert(!ID_IS_LINKED(id));
- return id;
- }
-
BLI_assert(!ID_IS_LINKED(id));
return id;
}
@@ -1178,7 +1167,7 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
BlendfileLinkAppendContextItem *item = itemlink->link;
- if (item->action != LINK_APPEND_ACT_REUSE_LOCAL) {
+ if (!ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_REUSE_LOCAL)) {
continue;
}
@@ -1189,13 +1178,15 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
BLI_assert(ID_IS_LINKED(id));
BLI_assert(id->newid != NULL);
+ /* Calling code may want to access newly appended IDs from the link/append context items. */
+ item->new_id = id->newid;
+
/* Do NOT delete a linked data that was already linked before this append. */
if (id->tag & LIB_TAG_PRE_EXISTING) {
continue;
}
id->tag |= LIB_TAG_DOIT;
- item->new_id = id->newid;
}
BKE_id_multi_tagged_delete(bmain);
@@ -1204,26 +1195,6 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
.active_collection = NULL};
loose_data_instantiate(&instantiate_context);
- /* Attempt to deal with object proxies.
- *
- * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not
- * producing any useful result in any known use case), neither here nor in
- * `BKE_library_make_local` currently.
- * Proxies are end of life anyway, so not worth spending time on this. */
- for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
- BlendfileLinkAppendContextItem *item = itemlink->link;
-
- if (item->action != LINK_APPEND_ACT_COPY_LOCAL) {
- continue;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_assert(ID_IS_LINKED(id));
- }
-
BKE_main_id_newptr_and_tag_clear(bmain);
blendfile_link_append_proxies_convert(bmain, reports);
diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc
index 4d95cdd1e02..35c2039634a 100644
--- a/source/blender/blenkernel/intern/bvhutils.cc
+++ b/source/blender/blenkernel/intern/bvhutils.cc
@@ -967,31 +967,6 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon,
return tree;
}
-BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
- const MVert *vert,
- const MFace *face,
- const int numFaces,
- const BLI_bitmap *faces_mask,
- int faces_num_active,
- float epsilon,
- int tree_type,
- int axis)
-{
- BVHTree *tree = nullptr;
- tree = bvhtree_from_mesh_faces_create_tree(
- epsilon, tree_type, axis, vert, face, numFaces, faces_mask, faces_num_active);
-
- bvhtree_balance(tree, false);
-
- if (data) {
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_setup_data(
- tree, BVHTREE_FROM_FACES, vert, nullptr, face, nullptr, nullptr, nullptr, data);
- }
-
- return tree;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index ed11e5359ca..27e8bf96dc6 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -5149,12 +5149,12 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap,
/** \name Custom Data IO
* \{ */
-static void write_mdisps(BlendWriter *writer, int count, MDisps *mdlist, int external)
+static void write_mdisps(BlendWriter *writer, int count, const MDisps *mdlist, int external)
{
if (mdlist) {
BLO_write_struct_array(writer, MDisps, count, mdlist);
for (int i = 0; i < count; i++) {
- MDisps *md = &mdlist[i];
+ const MDisps *md = &mdlist[i];
if (md->disps) {
if (!external) {
BLO_write_float3_array(writer, md->totdisp, &md->disps[0][0]);
@@ -5168,12 +5168,14 @@ static void write_mdisps(BlendWriter *writer, int count, MDisps *mdlist, int ext
}
}
-static void write_grid_paint_mask(BlendWriter *writer, int count, GridPaintMask *grid_paint_mask)
+static void write_grid_paint_mask(BlendWriter *writer,
+ int count,
+ const GridPaintMask *grid_paint_mask)
{
if (grid_paint_mask) {
BLO_write_struct_array(writer, GridPaintMask, count, grid_paint_mask);
for (int i = 0; i < count; i++) {
- GridPaintMask *gpm = &grid_paint_mask[i];
+ const GridPaintMask *gpm = &grid_paint_mask[i];
if (gpm->data) {
const int gridsize = BKE_ccg_gridsize(gpm->level);
BLO_write_raw(writer, sizeof(*gpm->data) * gridsize * gridsize, gpm->data);
@@ -5201,11 +5203,11 @@ void CustomData_blend_write(BlendWriter *writer,
if (layer->type == CD_MDEFORMVERT) {
/* layer types that allocate own memory need special handling */
- BKE_defvert_blend_write(writer, count, static_cast<struct MDeformVert *>(layer->data));
+ BKE_defvert_blend_write(writer, count, static_cast<const MDeformVert *>(layer->data));
}
else if (layer->type == CD_MDISPS) {
write_mdisps(
- writer, count, static_cast<MDisps *>(layer->data), layer->flag & CD_FLAG_EXTERNAL);
+ writer, count, static_cast<const MDisps *>(layer->data), layer->flag & CD_FLAG_EXTERNAL);
}
else if (layer->type == CD_PAINT_MASK) {
const float *layer_data = static_cast<const float *>(layer->data);
@@ -5216,7 +5218,7 @@ void CustomData_blend_write(BlendWriter *writer,
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else if (layer->type == CD_GRID_PAINT_MASK) {
- write_grid_paint_mask(writer, count, static_cast<GridPaintMask *>(layer->data));
+ write_grid_paint_mask(writer, count, static_cast<const GridPaintMask *>(layer->data));
}
else if (layer->type == CD_FACEMAP) {
const int *layer_data = static_cast<const int *>(layer->data);
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index c7ac82e4b68..ebe06fa85eb 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -1561,7 +1561,7 @@ void BKE_defbase_blend_write(BlendWriter *writer, const ListBase *defbase)
}
}
-void BKE_defvert_blend_write(BlendWriter *writer, int count, MDeformVert *dvlist)
+void BKE_defvert_blend_write(BlendWriter *writer, int count, const MDeformVert *dvlist)
{
if (dvlist == NULL) {
return;
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
index d23918215ba..9b023d12a7d 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -135,12 +135,12 @@ const Curve *CurveComponent::get_curve_for_render() const
/** \} */
+namespace blender::bke {
+
/* -------------------------------------------------------------------- */
/** \name Curve Normals Access
* \{ */
-namespace blender::bke {
-
static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves)
{
const VArray<int8_t> types = curves.curve_types();
@@ -300,10 +300,10 @@ bool CurveLengthFieldInput::is_equal_to(const fn::FieldNode &other) const
return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr;
}
-} // namespace blender::bke
-
/** \} */
+} // namespace blender::bke
+
/* -------------------------------------------------------------------- */
/** \name Attribute Access Helper Functions
* \{ */
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index 041696fa8d3..dd22d64aee1 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -236,6 +236,7 @@ static int stroke_march_next_point(const bGPDstroke *gps,
}
else {
next_point_index = gps->totpoints - 1;
+ remaining_till_next = 0;
break;
}
}
@@ -263,15 +264,18 @@ static int stroke_march_next_point(const bGPDstroke *gps,
float ratio = remaining_march / remaining_till_next;
interp_v3_v3v3(result, step_start, point, ratio);
*ratio_result = ratio;
+ float d1 = len_v3v3(result, &gps->points[*index_from].x);
+ float d2 = len_v3v3(result, &gps->points[next_point_index].x);
+ float vratio = d1 / (d1 + d2);
*pressure = interpf(
- gps->points[next_point_index].pressure, gps->points[*index_from].pressure, ratio);
+ gps->points[next_point_index].pressure, gps->points[*index_from].pressure, vratio);
*strength = interpf(
- gps->points[next_point_index].strength, gps->points[*index_from].strength, ratio);
+ gps->points[next_point_index].strength, gps->points[*index_from].strength, vratio);
interp_v4_v4v4(vert_color,
gps->points[*index_from].vert_color,
gps->points[next_point_index].vert_color,
- ratio);
+ vratio);
return next_point_index == 0 ? gps->totpoints : next_point_index;
}
@@ -320,6 +324,7 @@ static int stroke_march_next_point_no_interp(const bGPDstroke *gps,
}
else {
next_point_index = gps->totpoints - 1;
+ remaining_till_next = 0;
break;
}
}
diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc
index 3d894f47ae0..bc21e706d1e 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -182,9 +182,7 @@ static void image_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- image_dst->gputexture[i][eye][resolution] = nullptr;
- }
+ image_dst->gputexture[i][eye] = nullptr;
}
}
@@ -236,24 +234,21 @@ static void image_foreach_cache(ID *id,
key.offset_in_ID = offsetof(Image, cache);
function_callback(id, &key, (void **)&image->cache, 0, user_data);
- auto gputexture_offset = [image](int target, int eye, int resolution) {
+ auto gputexture_offset = [image](int target, int eye) {
constexpr size_t base_offset = offsetof(Image, gputexture);
- struct GPUTexture **first = &image->gputexture[0][0][0];
- const size_t array_offset = sizeof(*first) *
- (&image->gputexture[target][eye][resolution] - first);
+ struct GPUTexture **first = &image->gputexture[0][0];
+ const size_t array_offset = sizeof(*first) * (&image->gputexture[target][eye] - first);
return base_offset + array_offset;
};
for (int eye = 0; eye < 2; eye++) {
for (int a = 0; a < TEXTARGET_COUNT; a++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- GPUTexture *texture = image->gputexture[a][eye][resolution];
- if (texture == nullptr) {
- continue;
- }
- key.offset_in_ID = gputexture_offset(a, eye, resolution);
- function_callback(id, &key, (void **)&image->gputexture[a][eye][resolution], 0, user_data);
+ GPUTexture *texture = image->gputexture[a][eye];
+ if (texture == nullptr) {
+ continue;
}
+ key.offset_in_ID = gputexture_offset(a, eye);
+ function_callback(id, &key, (void **)&image->gputexture[a][eye], 0, user_data);
}
}
@@ -335,9 +330,7 @@ static void image_blend_write(BlendWriter *writer, ID *id, const void *id_addres
ima->runtime.partial_update_user = nullptr;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- ima->gputexture[i][j][resolution] = nullptr;
- }
+ ima->gputexture[i][j] = nullptr;
}
}
@@ -784,10 +777,8 @@ bool BKE_image_has_opengl_texture(Image *ima)
{
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- if (ima->gputexture[i][eye][resolution] != nullptr) {
- return true;
- }
+ if (ima->gputexture[i][eye] != nullptr) {
+ return true;
}
}
}
@@ -2864,11 +2855,9 @@ static void image_free_tile(Image *ima, ImageTile *tile)
}
for (int eye = 0; eye < 2; eye++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- if (ima->gputexture[i][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[i][eye][resolution]);
- ima->gputexture[i][eye][resolution] = nullptr;
- }
+ if (ima->gputexture[i][eye] != nullptr) {
+ GPU_texture_free(ima->gputexture[i][eye]);
+ ima->gputexture[i][eye] = nullptr;
}
}
}
@@ -3208,16 +3197,14 @@ ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *la
}
for (int eye = 0; eye < 2; eye++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- /* Reallocate GPU tile array. */
- if (ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution]);
- ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] = nullptr;
- }
- if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution]);
- ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] = nullptr;
- }
+ /* Reallocate GPU tile array. */
+ if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != nullptr) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye]);
+ ima->gputexture[TEXTARGET_2D_ARRAY][eye] = nullptr;
+ }
+ if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != nullptr) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye]);
+ ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = nullptr;
}
}
BKE_image_partial_update_mark_full_update(ima);
@@ -3273,17 +3260,14 @@ void BKE_image_reassign_tile(struct Image *ima, ImageTile *tile, int new_tile_nu
}
for (int eye = 0; eye < 2; eye++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
-
- /* Reallocate GPU tile array. */
- if (ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution]);
- ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] = nullptr;
- }
- if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution]);
- ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] = nullptr;
- }
+ /* Reallocate GPU tile array. */
+ if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != nullptr) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye]);
+ ima->gputexture[TEXTARGET_2D_ARRAY][eye] = nullptr;
+ }
+ if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != nullptr) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye]);
+ ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = nullptr;
}
}
BKE_image_partial_update_mark_full_update(ima);
diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc
index 0d470c5b663..bed79a318e8 100644
--- a/source/blender/blenkernel/intern/image_gpu.cc
+++ b/source/blender/blenkernel/intern/image_gpu.cc
@@ -38,7 +38,6 @@ extern "C" {
/* Prototypes. */
static void gpu_free_unused_buffers();
static void image_free_gpu(Image *ima, const bool immediate);
-static void image_free_gpu_limited_scale(Image *ima);
static void image_update_gputexture_ex(
Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h);
@@ -68,22 +67,19 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
/** \name UDIM GPU Texture
* \{ */
-static bool is_over_resolution_limit(int w, int h, bool limit_gl_texture_size)
+static bool is_over_resolution_limit(int w, int h)
{
- return (w > GPU_texture_size_with_limit(w, limit_gl_texture_size) ||
- h > GPU_texture_size_with_limit(h, limit_gl_texture_size));
+ return (w > GPU_texture_size_with_limit(w) || h > GPU_texture_size_with_limit(h));
}
-static int smaller_power_of_2_limit(int num, bool limit_gl_texture_size)
+static int smaller_power_of_2_limit(int num)
{
- return power_of_2_min_i(GPU_texture_size_with_limit(num, limit_gl_texture_size));
+ return power_of_2_min_i(GPU_texture_size_with_limit(num));
}
-static GPUTexture *gpu_texture_create_tile_mapping(
- Image *ima, const int multiview_eye, const eImageTextureResolution texture_resolution)
+static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
{
- const int resolution = (texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED) ? 1 : 0;
- GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye][resolution];
+ GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye];
if (tilearray == nullptr) {
return nullptr;
@@ -105,7 +101,7 @@ static GPUTexture *gpu_texture_create_tile_mapping(
}
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
int i = tile->tile_number - 1001;
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
data[4 * i] = tile_runtime->tilearray_layer;
float *tile_info = &data[4 * width + 4 * i];
@@ -137,12 +133,8 @@ static int compare_packtile(const void *a, const void *b)
return tile_a->pack_score < tile_b->pack_score;
}
-static GPUTexture *gpu_texture_create_tile_array(Image *ima,
- ImBuf *main_ibuf,
- const eImageTextureResolution texture_resolution)
+static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
{
- const bool limit_gl_texture_size = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED;
- const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
int arraywidth = 0, arrayheight = 0;
ListBase boxes = {nullptr};
@@ -158,10 +150,9 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
packtile->boxpack.w = ibuf->x;
packtile->boxpack.h = ibuf->y;
- if (is_over_resolution_limit(
- packtile->boxpack.w, packtile->boxpack.h, limit_gl_texture_size)) {
- packtile->boxpack.w = smaller_power_of_2_limit(packtile->boxpack.w, limit_gl_texture_size);
- packtile->boxpack.h = smaller_power_of_2_limit(packtile->boxpack.h, limit_gl_texture_size);
+ if (is_over_resolution_limit(packtile->boxpack.w, packtile->boxpack.h)) {
+ packtile->boxpack.w = smaller_power_of_2_limit(packtile->boxpack.w);
+ packtile->boxpack.h = smaller_power_of_2_limit(packtile->boxpack.h);
}
arraywidth = max_ii(arraywidth, packtile->boxpack.w);
arrayheight = max_ii(arrayheight, packtile->boxpack.h);
@@ -188,7 +179,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
LISTBASE_FOREACH (PackTile *, packtile, &packed) {
ImageTile *tile = packtile->tile;
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
@@ -210,7 +201,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
/* Upload each tile one by one. */
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
int tilelayer = tile_runtime->tilearray_layer;
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
@@ -258,33 +249,16 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
/** \name Regular gpu texture
* \{ */
-static bool image_max_resolution_texture_fits_in_limited_scale(Image *ima,
- eGPUTextureTarget textarget,
- const int multiview_eye)
-{
- BLI_assert_msg(U.glreslimit != 0,
- "limited scale function called without limited scale being set.");
- GPUTexture *max_resolution_texture =
- ima->gputexture[textarget][multiview_eye][IMA_TEXTURE_RESOLUTION_FULL];
- if (max_resolution_texture && GPU_texture_width(max_resolution_texture) <= U.glreslimit &&
- GPU_texture_height(max_resolution_texture) <= U.glreslimit) {
- return true;
- }
- return false;
-}
-
static GPUTexture **get_image_gpu_texture_ptr(Image *ima,
eGPUTextureTarget textarget,
- const int multiview_eye,
- const eImageTextureResolution texture_resolution)
+ const int multiview_eye)
{
const bool in_range = (textarget >= 0) && (textarget < TEXTARGET_COUNT);
BLI_assert(in_range);
BLI_assert(ELEM(multiview_eye, 0, 1));
- const int resolution = (texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED) ? 1 : 0;
if (in_range) {
- return &(ima->gputexture[textarget][multiview_eye][resolution]);
+ return &(ima->gputexture[textarget][multiview_eye]);
}
return nullptr;
}
@@ -303,21 +277,6 @@ static GPUTexture *image_gpu_texture_error_create(eGPUTextureTarget textarget)
}
}
-static void image_update_reusable_textures(Image *ima,
- eGPUTextureTarget textarget,
- const int multiview_eye)
-{
- if ((ima->gpuflag & IMA_GPU_HAS_LIMITED_SCALE_TEXTURES) == 0) {
- return;
- }
-
- if (ELEM(textarget, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
- if (image_max_resolution_texture_fits_in_limited_scale(ima, textarget, multiview_eye)) {
- image_free_gpu_limited_scale(ima);
- }
- }
-}
-
static void image_gpu_texture_partial_update_changes_available(
Image *image, PartialUpdateChecker<ImageTileData>::CollectResult &changes)
{
@@ -412,14 +371,7 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
if (current_view >= 2) {
current_view = 0;
}
- const bool limit_resolution = U.glreslimit != 0 &&
- ((iuser && (iuser->flag & IMA_SHOW_MAX_RESOLUTION) == 0) ||
- (iuser == nullptr)) &&
- ((ima->gpuflag & IMA_GPU_REUSE_MAX_RESOLUTION) == 0);
- const eImageTextureResolution texture_resolution = limit_resolution ?
- IMA_TEXTURE_RESOLUTION_LIMITED :
- IMA_TEXTURE_RESOLUTION_FULL;
- GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, current_view, texture_resolution);
+ GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, current_view);
if (*tex) {
return *tex;
}
@@ -443,11 +395,10 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
if (textarget == TEXTARGET_2D_ARRAY) {
- *tex = gpu_texture_create_tile_array(ima, ibuf_intern, texture_resolution);
+ *tex = gpu_texture_create_tile_array(ima, ibuf_intern);
}
else if (textarget == TEXTARGET_TILE_MAPPING) {
- *tex = gpu_texture_create_tile_mapping(
- ima, iuser ? iuser->multiview_eye : 0, texture_resolution);
+ *tex = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
}
else {
const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH);
@@ -455,7 +406,7 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
ibuf_intern);
*tex = IMB_create_gpu_texture(
- ima->id.name + 2, ibuf_intern, use_high_bitdepth, store_premultiplied, limit_resolution);
+ ima->id.name + 2, ibuf_intern, use_high_bitdepth, store_premultiplied);
if (*tex) {
GPU_texture_wrap_mode(*tex, true, false);
@@ -473,20 +424,6 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
}
- switch (texture_resolution) {
- case IMA_TEXTURE_RESOLUTION_LIMITED:
- ima->gpuflag |= IMA_GPU_HAS_LIMITED_SCALE_TEXTURES;
- break;
-
- case IMA_TEXTURE_RESOLUTION_FULL:
- image_update_reusable_textures(ima, textarget, current_view);
- break;
-
- case IMA_TEXTURE_RESOLUTION_LEN:
- BLI_assert_unreachable();
- break;
- }
-
if (*tex) {
GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y);
}
@@ -558,39 +495,22 @@ static void image_free_gpu(Image *ima, const bool immediate)
{
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- if (ima->gputexture[i][eye][resolution] != nullptr) {
- if (immediate) {
- GPU_texture_free(ima->gputexture[i][eye][resolution]);
- }
- else {
- BLI_mutex_lock(&gpu_texture_queue_mutex);
- BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye][resolution]);
- BLI_mutex_unlock(&gpu_texture_queue_mutex);
- }
-
- ima->gputexture[i][eye][resolution] = nullptr;
+ if (ima->gputexture[i][eye] != nullptr) {
+ if (immediate) {
+ GPU_texture_free(ima->gputexture[i][eye]);
+ }
+ else {
+ BLI_mutex_lock(&gpu_texture_queue_mutex);
+ BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye]);
+ BLI_mutex_unlock(&gpu_texture_queue_mutex);
}
- }
- }
- }
-
- ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE | IMA_GPU_HAS_LIMITED_SCALE_TEXTURES);
-}
-static void image_free_gpu_limited_scale(Image *ima)
-{
- const eImageTextureResolution resolution = IMA_TEXTURE_RESOLUTION_LIMITED;
- for (int eye = 0; eye < 2; eye++) {
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->gputexture[i][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[i][eye][resolution]);
- ima->gputexture[i][eye][resolution] = nullptr;
+ ima->gputexture[i][eye] = nullptr;
}
}
}
- ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE | IMA_GPU_HAS_LIMITED_SCALE_TEXTURES);
+ ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
}
void BKE_image_free_gputextures(Image *ima)
@@ -767,20 +687,12 @@ static void gpu_texture_update_unscaled(GPUTexture *tex,
GPU_unpack_row_length_set(0);
}
-static void gpu_texture_update_from_ibuf(GPUTexture *tex,
- Image *ima,
- ImBuf *ibuf,
- ImageTile *tile,
- int x,
- int y,
- int w,
- int h,
- eImageTextureResolution texture_resolution)
+static void gpu_texture_update_from_ibuf(
+ GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h)
{
- const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
bool scaled;
if (tile != nullptr) {
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
int *tilesize = tile_runtime->tilearray_size;
scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
}
@@ -845,7 +757,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
if (scaled) {
/* Slower update where we first have to scale the input pixels. */
if (tile != nullptr) {
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
int tilelayer = tile_runtime->tilearray_layer;
@@ -860,7 +772,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
else {
/* Fast update at same resolution. */
if (tile != nullptr) {
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
int *tileoffset = tile_runtime->tilearray_offset;
int tilelayer = tile_runtime->tilearray_layer;
gpu_texture_update_unscaled(
@@ -894,19 +806,16 @@ static void image_update_gputexture_ex(
Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h)
{
const int eye = 0;
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- GPUTexture *tex = ima->gputexture[TEXTARGET_2D][eye][resolution];
- eImageTextureResolution texture_resolution = static_cast<eImageTextureResolution>(resolution);
- /* Check if we need to update the main gputexture. */
- if (tex != nullptr && tile == ima->tiles.first) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, nullptr, x, y, w, h, texture_resolution);
- }
+ GPUTexture *tex = ima->gputexture[TEXTARGET_2D][eye];
+ /* Check if we need to update the main gputexture. */
+ if (tex != nullptr && tile == ima->tiles.first) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, nullptr, x, y, w, h);
+ }
- /* Check if we need to update the array gputexture. */
- tex = ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution];
- if (tex != nullptr) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h, texture_resolution);
- }
+ /* Check if we need to update the array gputexture. */
+ tex = ima->gputexture[TEXTARGET_2D_ARRAY][eye];
+ if (tex != nullptr) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h);
}
}
@@ -946,11 +855,9 @@ void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
for (int a = 0; a < TEXTARGET_COUNT; a++) {
if (ELEM(a, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
for (int eye = 0; eye < 2; eye++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- GPUTexture *tex = ima->gputexture[a][eye][resolution];
- if (tex != nullptr) {
- GPU_texture_mipmap_mode(tex, mipmap, true);
- }
+ GPUTexture *tex = ima->gputexture[a][eye];
+ if (tex != nullptr) {
+ GPU_texture_mipmap_mode(tex, mipmap, true);
}
}
}
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index 0230cf89d06..b67d3490e03 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -143,7 +143,7 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
opts->im_format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE;
- if (ima->source == IMA_SRC_TILED) {
+ if (ibuf->name[0] == '\0' || ima->source == IMA_SRC_TILED) {
BLI_strncpy(opts->filepath, ima->filepath, sizeof(opts->filepath));
BLI_path_abs(opts->filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
}
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 904039d56c8..f14c11a949e 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -6,6 +6,8 @@
* Contains management of ID's for freeing & deletion.
*/
+#include "CLG_log.h"
+
#include "MEM_guardedalloc.h"
/* all types are needed here, in order to do memory operations */
@@ -35,8 +37,7 @@
# include "BPY_extern.h"
#endif
-/* Not used currently. */
-// static CLG_LogRef LOG = {.identifier = "bke.lib_id_delete"};
+static CLG_LogRef LOG = {.identifier = "bke.lib_id_delete"};
void BKE_libblock_free_data(ID *id, const bool do_id_user)
{
@@ -334,11 +335,13 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
for (id = do_tagged_deletion ? tagged_deleted_ids.first : lb->first; id; id = id_next) {
id_next = id->next;
if (id->tag & tag) {
- if (id->us != 0) {
-#ifdef DEBUG_PRINT
- printf("%s: deleting %s (%d)\n", __func__, id->name, id->us);
-#endif
- BLI_assert(id->us == 0);
+ if (((id->tag & LIB_TAG_EXTRAUSER_SET) == 0 && ID_REAL_USERS(id) != 0) ||
+ ((id->tag & LIB_TAG_EXTRAUSER_SET) != 0 && ID_REAL_USERS(id) != 1)) {
+ CLOG_ERROR(&LOG,
+ "Deleting %s which still has %d users (including %d 'extra' shallow users)\n",
+ id->name,
+ ID_REAL_USERS(id),
+ (id->tag & LIB_TAG_EXTRAUSER_SET) != 0 ? 1 : 0);
}
BKE_id_free_ex(bmain, id, free_flag, !do_tagged_deletion);
++num_datablocks_deleted;
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 6dd13952413..50c9514e810 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -398,7 +398,8 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
const ID *id_root_reference,
ID *id_hierarchy_root,
const ID *id_hierarchy_root_reference,
- const bool do_no_main)
+ const bool do_no_main,
+ const bool do_fully_editable)
{
BLI_assert(id_root_reference != NULL && ID_IS_LINKED(id_root_reference));
/* If we do not have any hierarchy root given, then the root reference must be tagged for
@@ -464,6 +465,9 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
success = false;
break;
}
+ if (do_fully_editable) {
+ reference_id->newid->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ }
}
/* We also tag the new IDs so that in next step we can remap their pointers too. */
reference_id->newid->tag |= LIB_TAG_DOIT;
@@ -993,7 +997,8 @@ static bool lib_override_library_create_do(Main *bmain,
Scene *scene,
Library *owner_library,
ID *id_root_reference,
- ID *id_hierarchy_root_reference)
+ ID *id_hierarchy_root_reference,
+ const bool do_fully_editable)
{
BKE_main_relations_create(bmain, 0);
LibOverrideGroupTagData data = {.bmain = bmain,
@@ -1017,12 +1022,22 @@ static bool lib_override_library_create_do(Main *bmain,
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
BLI_assert(id_hierarchy_root_reference->override_library->reference->lib ==
id_root_reference->lib);
- success = BKE_lib_override_library_create_from_tag(
- bmain, owner_library, id_root_reference, id_hierarchy_root_reference, NULL, false);
+ success = BKE_lib_override_library_create_from_tag(bmain,
+ owner_library,
+ id_root_reference,
+ id_hierarchy_root_reference,
+ NULL,
+ false,
+ do_fully_editable);
}
else {
- success = BKE_lib_override_library_create_from_tag(
- bmain, owner_library, id_root_reference, NULL, id_hierarchy_root_reference, false);
+ success = BKE_lib_override_library_create_from_tag(bmain,
+ owner_library,
+ id_root_reference,
+ NULL,
+ id_hierarchy_root_reference,
+ false,
+ do_fully_editable);
}
return success;
@@ -1180,7 +1195,8 @@ bool BKE_lib_override_library_create(Main *bmain,
ID *id_root_reference,
ID *id_hierarchy_root_reference,
ID *id_instance_hint,
- ID **r_id_root_override)
+ ID **r_id_root_override,
+ const bool do_fully_editable)
{
if (r_id_root_override != NULL) {
*r_id_root_override = NULL;
@@ -1190,8 +1206,12 @@ bool BKE_lib_override_library_create(Main *bmain,
id_hierarchy_root_reference = id_root_reference;
}
- const bool success = lib_override_library_create_do(
- bmain, scene, owner_library, id_root_reference, id_hierarchy_root_reference);
+ const bool success = lib_override_library_create_do(bmain,
+ scene,
+ owner_library,
+ id_root_reference,
+ id_hierarchy_root_reference,
+ do_fully_editable);
if (!success) {
return success;
@@ -1680,7 +1700,13 @@ static bool lib_override_library_resync(Main *bmain,
* override IDs (including within the old overrides themselves, since those are tagged too
* above). */
const bool success = BKE_lib_override_library_create_from_tag(
- bmain, NULL, id_root_reference, id_root->override_library->hierarchy_root, NULL, true);
+ bmain,
+ NULL,
+ id_root_reference,
+ id_root->override_library->hierarchy_root,
+ NULL,
+ true,
+ false);
if (!success) {
BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
diff --git a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
index 5e9d8e8c4d0..88f6fbb0ead 100644
--- a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
+++ b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
@@ -39,7 +39,8 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
/* `proxy_group`, if defined, is the empty instantiating the collection from which the proxy is
* coming. */
Object *ob_proxy_group = ob_proxy->proxy_group;
- const bool is_override_instancing_object = ob_proxy_group != NULL;
+ const bool is_override_instancing_object = (ob_proxy_group != NULL) &&
+ (ob_proxy_group->instance_collection != NULL);
ID *id_root = is_override_instancing_object ? &ob_proxy_group->instance_collection->id :
&ob_proxy->proxy->id;
ID *id_instance_hint = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id;
@@ -82,7 +83,7 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
FOREACH_MAIN_ID_END;
return BKE_lib_override_library_create(
- bmain, scene, view_layer, ob_proxy->id.lib, id_root, id_root, id_instance_hint, NULL);
+ bmain, scene, view_layer, ob_proxy->id.lib, id_root, id_root, id_instance_hint, NULL, false);
}
static void lib_override_library_proxy_convert_do(Main *bmain,
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index accbca42da6..19ee2ba6605 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -2085,8 +2085,7 @@ GPUTexture *BKE_movieclip_get_gpu_texture(MovieClip *clip, MovieClipUser *cuser)
/* This only means RGBA16F instead of RGBA32F. */
const bool high_bitdepth = false;
const bool store_premultiplied = ibuf->rect_float ? false : true;
- *tex = IMB_create_gpu_texture(
- clip->id.name + 2, ibuf, high_bitdepth, store_premultiplied, false);
+ *tex = IMB_create_gpu_texture(clip->id.name + 2, ibuf, high_bitdepth, store_premultiplied);
/* Do not generate mips for movieclips... too slow. */
GPU_texture_mipmap_mode(*tex, false, true);
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 5d804f53779..a5f6c453ed4 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -244,24 +244,38 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, const ListBase *src, const
}
}
-/* Set adt_dest->actstrip to the strip with the same index as adt_source->actstrip. */
-static void update_active_strip(AnimData *adt_dest,
- NlaTrack *track_dest,
- const AnimData *adt_source,
- NlaTrack *track_source)
+static void update_active_strip_from_listbase(AnimData *adt_dest,
+ NlaTrack *track_dest,
+ const NlaStrip *active_strip,
+ const ListBase /* NlaStrip */ *strips_source)
{
- BLI_assert(BLI_listbase_count(&track_source->strips) == BLI_listbase_count(&track_dest->strips));
-
NlaStrip *strip_dest = track_dest->strips.first;
- LISTBASE_FOREACH (NlaStrip *, strip_source, &track_source->strips) {
- if (strip_source == adt_source->actstrip) {
+ LISTBASE_FOREACH (const NlaStrip *, strip_source, strips_source) {
+ if (strip_source == active_strip) {
adt_dest->actstrip = strip_dest;
+ return;
+ }
+
+ if (strip_source->type == NLASTRIP_TYPE_META) {
+ update_active_strip_from_listbase(adt_dest, track_dest, active_strip, &strip_source->strips);
}
strip_dest = strip_dest->next;
}
}
+/* Set adt_dest->actstrip to the strip with the same index as adt_source->actstrip. */
+static void update_active_strip(AnimData *adt_dest,
+ NlaTrack *track_dest,
+ const AnimData *adt_source,
+ const NlaTrack *track_source)
+{
+ BLI_assert(BLI_listbase_count(&track_source->strips) == BLI_listbase_count(&track_dest->strips));
+
+ update_active_strip_from_listbase(
+ adt_dest, track_dest, adt_source->actstrip, &track_source->strips);
+}
+
/* Set adt_dest->act_track to the track with the same index as adt_source->act_track. */
static void update_active_track(AnimData *adt_dest, const AnimData *adt_source)
{
@@ -272,20 +286,20 @@ static void update_active_track(AnimData *adt_dest, const AnimData *adt_source)
LISTBASE_FOREACH (NlaTrack *, track_source, &adt_source->nla_tracks) {
if (track_source == adt_source->act_track) {
adt_dest->act_track = track_dest;
- /* Assumption: the active strip is on the active track. */
- update_active_strip(adt_dest, track_dest, adt_source, track_source);
}
+ update_active_strip(adt_dest, track_dest, adt_source, track_source);
track_dest = track_dest->next;
}
- /* If the above assumption failed to hold, do a more thorough search for the active strip. */
- if (adt_source->actstrip != NULL && adt_dest->actstrip == NULL) {
- nla_tweakmode_find_active(&adt_source->nla_tracks, &track_dest, &adt_dest->actstrip);
+#ifndef NDEBUG
+ {
+ const bool source_has_actstrip = adt_source->actstrip != NULL;
+ const bool dest_has_actstrip = adt_dest->actstrip != NULL;
+ BLI_assert_msg(source_has_actstrip == dest_has_actstrip,
+ "Active strip did not copy correctly");
}
-
- BLI_assert_msg((adt_source->actstrip == NULL) == (adt_dest->actstrip == NULL),
- "Active strip did not copy correctly");
+#endif
}
void BKE_nla_tracks_copy_from_adt(Main *bmain,
@@ -1171,26 +1185,35 @@ bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt)
/* NLA Strips -------------------------------------- */
-NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
+static NlaStrip *nlastrip_find_active(ListBase /* NlaStrip */ *strips)
{
- NlaStrip *strip;
-
- /* sanity check */
- if (ELEM(NULL, nlt, nlt->strips.first)) {
- return NULL;
- }
-
- /* try to find the first active strip */
- for (strip = nlt->strips.first; strip; strip = strip->next) {
+ LISTBASE_FOREACH (NlaStrip *, strip, strips) {
if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
return strip;
}
+
+ if (strip->type != NLASTRIP_TYPE_META) {
+ continue;
+ }
+
+ NlaStrip *inner_active = nlastrip_find_active(&strip->strips);
+ if (inner_active != NULL) {
+ return inner_active;
+ }
}
- /* none found */
return NULL;
}
+NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
+{
+ if (nlt == NULL) {
+ return NULL;
+ }
+
+ return nlastrip_find_active(&nlt->strips);
+}
+
void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
{
NlaTrack *nlt;
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
index 8afe7ce7520..68e4cccba00 100644
--- a/source/blender/blenkernel/intern/node_tree_update.cc
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -985,7 +985,7 @@ class NodeTreeMainUpdater {
this->remove_unused_previews_when_necessary(ntree);
this->ensure_tree_ref(ntree, tree_ref);
- this->update_has_image_animation(*tree_ref);
+ this->propagate_runtime_flags(*tree_ref);
if (ntree.type == NTREE_GEOMETRY) {
if (node_field_inferencing::update_field_inferencing(*tree_ref)) {
result.interface_changed = true;
@@ -1256,10 +1256,10 @@ class NodeTreeMainUpdater {
BKE_node_preview_remove_unused(&ntree);
}
- void update_has_image_animation(const NodeTreeRef &tree_ref)
+ void propagate_runtime_flags(const NodeTreeRef &tree_ref)
{
bNodeTree &ntree = *tree_ref.btree();
- ntree.runtime_flag &= ~NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
+ ntree.runtime_flag = 0;
if (ntree.type != NTREE_SHADER) {
return;
}
@@ -1268,21 +1268,30 @@ class NodeTreeMainUpdater {
for (const NodeRef *group_node : tree_ref.nodes_by_type("NodeGroup")) {
const bNodeTree *group = reinterpret_cast<bNodeTree *>(group_node->bnode()->id);
if (group != nullptr) {
- if (group->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
- ntree.runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
- return;
- }
+ ntree.runtime_flag |= group->runtime_flag;
}
}
/* Check if the tree itself has an animated image. */
- for (const StringRefNull idname : {"ShaderNodeTexImage", "ShaderNodeTexEnvironment"})
+ for (const StringRefNull idname : {"ShaderNodeTexImage", "ShaderNodeTexEnvironment"}) {
for (const NodeRef *node : tree_ref.nodes_by_type(idname)) {
Image *image = reinterpret_cast<Image *>(node->bnode()->id);
if (image != nullptr && BKE_image_is_animated(image)) {
ntree.runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
- return;
+ break;
}
}
+ }
+ /* Check if the tree has a material output. */
+ for (const StringRefNull idname : {"ShaderNodeOutputMaterial",
+ "ShaderNodeOutputLight",
+ "ShaderNodeOutputWorld",
+ "ShaderNodeOutputAOV"}) {
+ const Span<const NodeRef *> nodes = tree_ref.nodes_by_type(idname);
+ if (!nodes.is_empty()) {
+ ntree.runtime_flag |= NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT;
+ break;
+ }
+ }
}
void update_node_levels(bNodeTree &ntree)
@@ -1392,10 +1401,12 @@ class NodeTreeMainUpdater {
return true;
}
/* Assume node groups without output sockets are outputs. */
- /* TODO: Store whether a node group contains a top-level output node (e.g. Material Output) in
- * run-time information on the node group itself. */
- if (bnode.type == NODE_GROUP && node.outputs().is_empty()) {
- return true;
+ if (bnode.type == NODE_GROUP) {
+ const bNodeTree *node_group = reinterpret_cast<const bNodeTree *>(bnode.id);
+ if (node_group != nullptr &&
+ node_group->runtime_flag & NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT) {
+ return true;
+ }
}
return false;
}
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 02134623a31..30e02e5411b 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -268,7 +268,7 @@ static struct bUnitCollection buImperialAclCollection = {buImperialAclDef, 0, 0,
/* Time. */
static struct bUnitDef buNaturalTimeDef[] = {
/* Weeks? - probably not needed for Blender. */
- {"day", "days", "d", NULL, "Days", "DAYS", 90000.0, 0.0, B_UNIT_DEF_NONE},
+ {"day", "days", "d", NULL, "Days", "DAYS", 86400.0, 0.0, B_UNIT_DEF_NONE},
{"hour", "hours", "hr", "h", "Hours", "HOURS", 3600.0, 0.0, B_UNIT_DEF_NONE},
{"minute", "minutes", "min", "m", "Minutes", "MINUTES", 60.0, 0.0, B_UNIT_DEF_NONE},
{"second", "seconds", "sec", "s", "Seconds", "SECONDS", 1.0, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh
index 91dfc81ae27..813277d9968 100644
--- a/source/blender/blenlib/BLI_array.hh
+++ b/source/blender/blenlib/BLI_array.hh
@@ -64,10 +64,10 @@ class Array {
int64_t size_;
/** Used for allocations when the inline buffer is too small. */
- Allocator allocator_;
+ BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
/** A placeholder buffer that will remain uninitialized until it is used. */
- TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
+ BLI_NO_UNIQUE_ADDRESS TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
public:
/**
diff --git a/source/blender/blenlib/BLI_generic_array.hh b/source/blender/blenlib/BLI_generic_array.hh
index e1b6b29874a..4b917434264 100644
--- a/source/blender/blenlib/BLI_generic_array.hh
+++ b/source/blender/blenlib/BLI_generic_array.hh
@@ -33,7 +33,7 @@ class GArray {
void *data_ = nullptr;
int64_t size_ = 0;
- Allocator allocator_;
+ BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
public:
/**
diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh
index 6532c59a846..deb6ea3b5fd 100644
--- a/source/blender/blenlib/BLI_linear_allocator.hh
+++ b/source/blender/blenlib/BLI_linear_allocator.hh
@@ -18,7 +18,7 @@ namespace blender {
template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopyable, NonMovable {
private:
- Allocator allocator_;
+ BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
Vector<void *> owned_buffers_;
Vector<Span<char>> unused_borrowed_buffers_;
diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh
index d76aa46502d..55233676ed8 100644
--- a/source/blender/blenlib/BLI_map.hh
+++ b/source/blender/blenlib/BLI_map.hh
@@ -130,10 +130,10 @@ class Map {
uint64_t slot_mask_;
/** This is called to hash incoming keys. */
- Hash hash_;
+ BLI_NO_UNIQUE_ADDRESS Hash hash_;
/** This is called to check equality of two keys. */
- IsEqual is_equal_;
+ BLI_NO_UNIQUE_ADDRESS IsEqual is_equal_;
/** The max load factor is 1/2 = 50% by default. */
#define LOAD_FACTOR 1, 2
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index dcc00064e47..64b820a22b0 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -186,9 +186,6 @@ MINLINE void rgba_uchar_args_test_set(
unsigned char col[4], unsigned char r, unsigned char g, unsigned char b, unsigned char a);
MINLINE void cpack_cpy_3ub(unsigned char r_col[3], unsigned int pack);
-void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max);
-void wavelength_to_xyz_table(float *r_table, int width);
-
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index d7c41ae88a8..940542c9f1d 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -317,30 +317,36 @@ template<typename T> using destruct_ptr = std::unique_ptr<T, DestructValueAtAddr
* An `AlignedBuffer` is a byte array with at least the given size and alignment. The buffer will
* not be initialized by the default constructor.
*/
-template<size_t Size, size_t Alignment> class alignas(Alignment) AlignedBuffer {
- private:
- /* Don't create an empty array. This causes problems with some compilers. */
- char buffer_[(Size > 0) ? Size : 1];
+template<size_t Size, size_t Alignment> class AlignedBuffer {
+ struct Empty {
+ };
+ struct alignas(Alignment) Sized {
+ /* Don't create an empty array. This causes problems with some compilers. */
+ std::byte buffer_[Size > 0 ? Size : 1];
+ };
+
+ using BufferType = std::conditional_t<Size == 0, Empty, Sized>;
+ BLI_NO_UNIQUE_ADDRESS BufferType buffer_;
public:
operator void *()
{
- return buffer_;
+ return this;
}
operator const void *() const
{
- return buffer_;
+ return this;
}
void *ptr()
{
- return buffer_;
+ return this;
}
const void *ptr() const
{
- return buffer_;
+ return this;
}
};
@@ -351,7 +357,7 @@ template<size_t Size, size_t Alignment> class alignas(Alignment) AlignedBuffer {
*/
template<typename T, int64_t Size = 1> class TypedBuffer {
private:
- AlignedBuffer<sizeof(T) * (size_t)Size, alignof(T)> buffer_;
+ BLI_NO_UNIQUE_ADDRESS AlignedBuffer<sizeof(T) * (size_t)Size, alignof(T)> buffer_;
public:
operator T *()
diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh
index 391d31c2228..62de4b79e41 100644
--- a/source/blender/blenlib/BLI_set.hh
+++ b/source/blender/blenlib/BLI_set.hh
@@ -136,10 +136,10 @@ class Set {
uint64_t slot_mask_;
/** This is called to hash incoming keys. */
- Hash hash_;
+ BLI_NO_UNIQUE_ADDRESS Hash hash_;
/** This is called to check equality of two keys. */
- IsEqual is_equal_;
+ BLI_NO_UNIQUE_ADDRESS IsEqual is_equal_;
/** The max load factor is 1/2 = 50% by default. */
#define LOAD_FACTOR 1, 2
@@ -483,10 +483,10 @@ class Set {
* while iterating over the set. However, after this method has been called, the removed element
* must not be accessed anymore.
*/
- void remove(const Iterator &iterator)
+ void remove(const Iterator &it)
{
/* The const cast is valid because this method itself is not const. */
- Slot &slot = const_cast<Slot &>(iterator.current_slot());
+ Slot &slot = const_cast<Slot &>(it.current_slot());
BLI_assert(slot.is_occupied());
slot.remove();
removed_slots_++;
diff --git a/source/blender/blenlib/BLI_stack.hh b/source/blender/blenlib/BLI_stack.hh
index a06515a7781..ed123f43a6b 100644
--- a/source/blender/blenlib/BLI_stack.hh
+++ b/source/blender/blenlib/BLI_stack.hh
@@ -96,7 +96,7 @@ class Stack {
int64_t size_;
/** The buffer used to implement small object optimization. */
- TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
+ BLI_NO_UNIQUE_ADDRESS TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
/**
* A chunk referencing the inline buffer. This is always the bottom-most chunk.
@@ -105,7 +105,7 @@ class Stack {
Chunk inline_chunk_;
/** Used for allocations when the inline buffer is not large enough. */
- Allocator allocator_;
+ BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
public:
/**
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index b8407a5453f..7f9470a9111 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -843,6 +843,18 @@ extern bool BLI_memory_is_zero(const void *arr, size_t arr_size);
*/
#define BLI_ENABLE_IF(condition) typename std::enable_if_t<(condition)> * = nullptr
+#if defined(_MSC_VER)
+# define BLI_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
+#elif defined(__has_cpp_attribute)
+# if __has_cpp_attribute(no_unique_address)
+# define BLI_NO_UNIQUE_ADDRESS [[no_unique_address]]
+# else
+# define BLI_NO_UNIQUE_ADDRESS
+# endif
+#else
+# define BLI_NO_UNIQUE_ADDRESS [[no_unique_address]]
+#endif
+
/** \} */
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index acf47f67168..c23d846d277 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -84,10 +84,10 @@ class Vector {
T *capacity_end_;
/** Used for allocations when the inline buffer is too small. */
- Allocator allocator_;
+ BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
/** A placeholder buffer that will remain uninitialized until it is used. */
- TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
+ BLI_NO_UNIQUE_ADDRESS TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
/**
* Store the size of the vector explicitly in debug builds. Otherwise you'd always have to call
diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh
index 4ae1bf9000d..b0a3696f245 100644
--- a/source/blender/blenlib/BLI_vector_set.hh
+++ b/source/blender/blenlib/BLI_vector_set.hh
@@ -117,10 +117,10 @@ class VectorSet {
uint64_t slot_mask_;
/** This is called to hash incoming keys. */
- Hash hash_;
+ BLI_NO_UNIQUE_ADDRESS Hash hash_;
/** This is called to check equality of two keys. */
- IsEqual is_equal_;
+ BLI_NO_UNIQUE_ADDRESS IsEqual is_equal_;
/** The max load factor is 1/2 = 50% by default. */
#define LOAD_FACTOR 1, 2
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index 52cbda82268..bdcf52ec521 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -597,158 +597,3 @@ void BLI_init_srgb_conversion(void)
BLI_color_to_srgb_table[i] = (unsigned short)(b * 0x100);
}
}
-
-/* ****************************** blackbody ******************************** */
-
-/* Calculate color in range 800..12000 using an approximation
- * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
- * Max absolute error for RGB is (0.00095, 0.00077, 0.00057),
- * which is enough to get the same 8 bit/channel color.
- */
-
-static const float blackbody_table_r[6][3] = {
- {2.52432244e+03f, -1.06185848e-03f, 3.11067539e+00f},
- {3.37763626e+03f, -4.34581697e-04f, 1.64843306e+00f},
- {4.10671449e+03f, -8.61949938e-05f, 6.41423749e-01f},
- {4.66849800e+03f, 2.85655028e-05f, 1.29075375e-01f},
- {4.60124770e+03f, 2.89727618e-05f, 1.48001316e-01f},
- {3.78765709e+03f, 9.36026367e-06f, 3.98995841e-01f},
-};
-
-static const float blackbody_table_g[6][3] = {
- {-7.50343014e+02f, 3.15679613e-04f, 4.73464526e-01f},
- {-1.00402363e+03f, 1.29189794e-04f, 9.08181524e-01f},
- {-1.22075471e+03f, 2.56245413e-05f, 1.20753416e+00f},
- {-1.42546105e+03f, -4.01730887e-05f, 1.44002695e+00f},
- {-1.18134453e+03f, -2.18913373e-05f, 1.30656109e+00f},
- {-5.00279505e+02f, -4.59745390e-06f, 1.09090465e+00f},
-};
-
-static const float blackbody_table_b[6][4] = {
- {0.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
- {-2.02524603e-11f, 1.79435860e-07f, -2.60561875e-04f, -1.41761141e-02f},
- {-2.22463426e-13f, -1.55078698e-08f, 3.81675160e-04f, -7.30646033e-01f},
- {6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f},
-};
-
-static void blackbody_temperature_to_rgb(float rgb[3], float t)
-{
- if (t >= 12000.0f) {
- rgb[0] = 0.826270103f;
- rgb[1] = 0.994478524f;
- rgb[2] = 1.56626022f;
- }
- else if (t < 965.0f) {
- rgb[0] = 4.70366907f;
- rgb[1] = 0.0f;
- rgb[2] = 0.0f;
- }
- else {
- int i = (t >= 6365.0f) ? 5 :
- (t >= 3315.0f) ? 4 :
- (t >= 1902.0f) ? 3 :
- (t >= 1449.0f) ? 2 :
- (t >= 1167.0f) ? 1 :
- 0;
-
- const float *r = blackbody_table_r[i];
- const float *g = blackbody_table_g[i];
- const float *b = blackbody_table_b[i];
-
- const float t_inv = 1.0f / t;
- rgb[0] = r[0] * t_inv + r[1] * t + r[2];
- rgb[1] = g[0] * t_inv + g[1] * t + g[2];
- rgb[2] = ((b[0] * t + b[1]) * t + b[2]) * t + b[3];
- }
-}
-
-void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max)
-{
- for (int i = 0; i < width; i++) {
- float temperature = min + (max - min) / (float)width * (float)i;
-
- float rgb[3];
- blackbody_temperature_to_rgb(rgb, temperature);
-
- copy_v3_v3(&r_table[i * 4], rgb);
- r_table[i * 4 + 3] = 0.0f;
- }
-}
-
-/* ****************************** wavelength ******************************** */
-/* Wavelength to RGB. */
-
-/**
- * CIE color matching functions `xBar`, `yBar`, and `zBar` for
- * wavelengths from 380 through 780 nanometers, every 5 nanometers.
- *
- * For a wavelength lambda in this range:
- * \code{.txt}
- * cie_color_match[(lambda - 380) / 5][0] = xBar
- * cie_color_match[(lambda - 380) / 5][1] = yBar
- * cie_color_match[(lambda - 380) / 5][2] = zBar
- * \endcode
- */
-
-static float cie_colour_match[81][3] = {
- {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
- {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
- {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
- {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
- {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
- {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
- {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
- {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
- {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
- {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
- {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
- {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
- {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
- {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
- {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
- {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
- {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
- {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
- {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
- {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
- {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
- {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
- {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
- {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
- {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
- {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
- {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}};
-
-static void wavelength_to_xyz(float xyz[3], float lambda_nm)
-{
- float ii = (lambda_nm - 380.0f) * (1.0f / 5.0f); /* Scaled 0..80. */
- int i = (int)ii;
-
- if (i < 0 || i >= 80) {
- xyz[0] = 0.0f;
- xyz[1] = 0.0f;
- xyz[2] = 0.0f;
- }
- else {
- ii -= (float)i;
- const float *c = cie_colour_match[i];
- xyz[0] = c[0] + ii * (c[3] - c[0]);
- xyz[1] = c[1] + ii * (c[4] - c[1]);
- xyz[2] = c[2] + ii * (c[5] - c[2]);
- }
-}
-
-void wavelength_to_xyz_table(float *r_table, int width)
-{
- for (int i = 0; i < width; i++) {
- float temperature = 380 + 400 / (float)width * (float)i;
-
- float rgb[3];
- wavelength_to_xyz(rgb, temperature);
-
- copy_v3_v3(&r_table[i * 4], rgb);
- r_table[i * 4 + 3] = 0.0f;
- }
-}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 108aa80ab1e..585ada3b2d8 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1666,13 +1666,8 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
- /* UV/Image Max resolution images in image editor. */
- if (space->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)space;
- sima->iuser.flag |= IMA_SHOW_MAX_RESOLUTION;
- }
/* Enable Outliner render visibility column. */
- else if (space->spacetype == SPACE_OUTLINER) {
+ if (space->spacetype == SPACE_OUTLINER) {
SpaceOutliner *space_outliner = (SpaceOutliner *)space;
space_outliner->show_restrict_flags |= SO_RESTRICT_RENDER;
}
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index a5693cb0fd7..3d539018cef 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -40,6 +40,7 @@ set(SRC
intern/builder/deg_builder_relations_view_layer.cc
intern/builder/deg_builder_remove_noop.cc
intern/builder/deg_builder_rna.cc
+ intern/builder/deg_builder_stack.cc
intern/builder/deg_builder_transitive.cc
intern/builder/pipeline.cc
intern/builder/pipeline_all_objects.cc
@@ -103,6 +104,7 @@ set(SRC
intern/builder/deg_builder_relations_impl.h
intern/builder/deg_builder_remove_noop.h
intern/builder/deg_builder_rna.h
+ intern/builder/deg_builder_stack.h
intern/builder/deg_builder_transitive.h
intern/builder/pipeline.h
intern/builder/pipeline_all_objects.h
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 3eeab23823c..0d4f9103149 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -586,11 +586,12 @@ void DepsgraphRelationBuilder::build_id(ID *id)
void DepsgraphRelationBuilder::build_generic_id(ID *id)
{
-
if (built_map_.checkIsBuiltAndTag(id)) {
return;
}
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*id);
+
build_idproperties(id->properties);
build_animdata(id);
build_parameters(id);
@@ -621,6 +622,9 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll
* recurses into all the nested objects and collections. */
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(collection->id);
+
const bool group_done = built_map_.checkIsBuiltAndTag(collection);
OperationKey object_transform_final_key(object != nullptr ? &object->id : nullptr,
NodeType::TRANSFORM,
@@ -684,6 +688,9 @@ void DepsgraphRelationBuilder::build_object(Object *object)
if (built_map_.checkIsBuiltAndTag(object)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(object->id);
+
/* Object Transforms */
OperationCode base_op = (object->parent) ? OperationCode::TRANSFORM_PARENT :
OperationCode::TRANSFORM_LOCAL;
@@ -1133,6 +1140,9 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
if (cti == nullptr) {
continue;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*con);
+
/* Special case for camera tracking -- it doesn't use targets to
* define relations. */
/* TODO: we can now represent dependencies in a much richer manner,
@@ -1500,6 +1510,9 @@ void DepsgraphRelationBuilder::build_action(bAction *action)
if (built_map_.checkIsBuiltAndTag(action)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(action->id);
+
build_idproperties(action->id.properties);
if (!BLI_listbase_is_empty(&action->curves)) {
TimeSourceKey time_src_key;
@@ -1787,6 +1800,9 @@ void DepsgraphRelationBuilder::build_world(World *world)
if (built_map_.checkIsBuiltAndTag(world)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(world->id);
+
build_idproperties(world->id.properties);
/* animation */
build_animdata(&world->id);
@@ -2012,6 +2028,9 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part)
if (built_map_.checkIsBuiltAndTag(part)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(part->id);
+
/* Animation data relations. */
build_animdata(&part->id);
build_parameters(&part->id);
@@ -2070,6 +2089,9 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key)
if (built_map_.checkIsBuiltAndTag(key)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(key->id);
+
build_idproperties(key->id.properties);
/* Attach animdata to geometry. */
build_animdata(&key->id);
@@ -2131,6 +2153,8 @@ 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) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*md);
+
DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
mti->updateDepsgraph(md, &ctx);
@@ -2251,6 +2275,9 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*obdata);
+
build_idproperties(obdata->properties);
/* Animation. */
build_animdata(obdata);
@@ -2369,6 +2396,9 @@ void DepsgraphRelationBuilder::build_armature(bArmature *armature)
if (built_map_.checkIsBuiltAndTag(armature)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(armature->id);
+
build_idproperties(armature->id.properties);
build_animdata(&armature->id);
build_parameters(&armature->id);
@@ -2388,6 +2418,9 @@ void DepsgraphRelationBuilder::build_camera(Camera *camera)
if (built_map_.checkIsBuiltAndTag(camera)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(camera->id);
+
build_idproperties(camera->id.properties);
build_animdata(&camera->id);
build_parameters(&camera->id);
@@ -2405,6 +2438,9 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(lamp->id);
+
build_idproperties(lamp->id.properties);
build_animdata(&lamp->id);
build_parameters(&lamp->id);
@@ -2469,6 +2505,9 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
if (built_map_.checkIsBuiltAndTag(ntree)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(ntree->id);
+
build_idproperties(ntree->id.properties);
build_animdata(&ntree->id);
build_parameters(&ntree->id);
@@ -2574,6 +2613,9 @@ void DepsgraphRelationBuilder::build_material(Material *material)
if (built_map_.checkIsBuiltAndTag(material)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(material->id);
+
build_idproperties(material->id.properties);
/* animation */
build_animdata(&material->id);
@@ -2610,6 +2652,9 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
if (built_map_.checkIsBuiltAndTag(texture)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(texture->id);
+
/* texture itself */
ComponentKey texture_key(&texture->id, NodeType::GENERIC_DATABLOCK);
build_idproperties(texture->id.properties);
@@ -2651,6 +2696,9 @@ void DepsgraphRelationBuilder::build_image(Image *image)
if (built_map_.checkIsBuiltAndTag(image)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(image->id);
+
build_idproperties(image->id.properties);
build_parameters(&image->id);
}
@@ -2660,6 +2708,9 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file)
if (built_map_.checkIsBuiltAndTag(cache_file)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(cache_file->id);
+
build_idproperties(cache_file->id.properties);
/* Animation. */
build_animdata(&cache_file->id);
@@ -2689,6 +2740,9 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask)
if (built_map_.checkIsBuiltAndTag(mask)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(mask->id);
+
ID *mask_id = &mask->id;
build_idproperties(mask_id->properties);
/* F-Curve animation. */
@@ -2727,6 +2781,8 @@ void DepsgraphRelationBuilder::build_freestyle_linestyle(FreestyleLineStyle *lin
return;
}
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(linestyle->id);
+
ID *linestyle_id = &linestyle->id;
build_parameters(linestyle_id);
build_idproperties(linestyle_id->properties);
@@ -2739,6 +2795,9 @@ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
if (built_map_.checkIsBuiltAndTag(clip)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(clip->id);
+
/* Animation. */
build_idproperties(clip->id.properties);
build_animdata(&clip->id);
@@ -2750,6 +2809,9 @@ void DepsgraphRelationBuilder::build_lightprobe(LightProbe *probe)
if (built_map_.checkIsBuiltAndTag(probe)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(probe->id);
+
build_idproperties(probe->id.properties);
build_animdata(&probe->id);
build_parameters(&probe->id);
@@ -2760,6 +2822,9 @@ void DepsgraphRelationBuilder::build_speaker(Speaker *speaker)
if (built_map_.checkIsBuiltAndTag(speaker)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(speaker->id);
+
build_idproperties(speaker->id.properties);
build_animdata(&speaker->id);
build_parameters(&speaker->id);
@@ -2776,6 +2841,9 @@ void DepsgraphRelationBuilder::build_sound(bSound *sound)
if (built_map_.checkIsBuiltAndTag(sound)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(sound->id);
+
build_idproperties(sound->id.properties);
build_animdata(&sound->id);
build_parameters(&sound->id);
@@ -2786,6 +2854,9 @@ void DepsgraphRelationBuilder::build_simulation(Simulation *simulation)
if (built_map_.checkIsBuiltAndTag(simulation)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(simulation->id);
+
build_idproperties(simulation->id.properties);
build_animdata(&simulation->id);
build_parameters(&simulation->id);
@@ -2850,6 +2921,9 @@ void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_SCENE_SEQUENCER)) {
return;
}
+
+ /* TODO(sergey): Trace as a scene sequencer. */
+
build_scene_audio(scene);
ComponentKey scene_audio_key(&scene->id, NodeType::AUDIO);
/* Make sure dependencies from sequences data goes to the sequencer evaluation. */
@@ -2893,6 +2967,9 @@ void DepsgraphRelationBuilder::build_vfont(VFont *vfont)
if (built_map_.checkIsBuiltAndTag(vfont)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(vfont->id);
+
build_parameters(&vfont->id);
build_idproperties(vfont->id.properties);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 1ccecc9a3f2..64bdd2334d8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -23,6 +23,7 @@
#include "intern/builder/deg_builder.h"
#include "intern/builder/deg_builder_map.h"
#include "intern/builder/deg_builder_rna.h"
+#include "intern/builder/deg_builder_stack.h"
#include "intern/depsgraph.h"
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_component.h"
@@ -363,6 +364,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
BuilderMap built_map_;
RNANodeQuery rna_node_query_;
+ BuilderStack stack_;
};
struct DepsNodeHandle {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
index 5cbd8c8dd75..aba4a011e72 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
@@ -9,6 +9,8 @@
#include "intern/node/deg_node_id.h"
+#include <iostream>
+
#include "DNA_ID.h"
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
@@ -33,37 +35,30 @@ Relation *DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
Node *node_to = get_node(key_to);
OperationNode *op_from = node_from ? node_from->get_exit_operation() : nullptr;
OperationNode *op_to = node_to ? node_to->get_entry_operation() : nullptr;
+
if (op_from && op_to) {
return add_operation_relation(op_from, op_to, description, flags);
}
- else {
- if (!op_from) {
- /* XXX TODO: handle as error or report if needed. */
- fprintf(stderr,
- "add_relation(%s) - Could not find op_from (%s)\n",
- description,
- key_from.identifier().c_str());
- }
- else {
- fprintf(stderr,
- "add_relation(%s) - Failed, but op_from (%s) was ok\n",
- description,
- key_from.identifier().c_str());
- }
- if (!op_to) {
- /* XXX TODO: handle as error or report if needed. */
- fprintf(stderr,
- "add_relation(%s) - Could not find op_to (%s)\n",
- description,
- key_to.identifier().c_str());
- }
- else {
- fprintf(stderr,
- "add_relation(%s) - Failed, but op_to (%s) was ok\n",
- description,
- key_to.identifier().c_str());
- }
+
+ /* TODO(sergey): Report error in the interface. */
+
+ std::cerr << "--------------------------------------------------------------------\n";
+ std::cerr << "Failed to add relation \"" << description << "\"\n";
+
+ if (!op_from) {
+ std::cerr << "Could not find op_from: " << key_from.identifier() << "\n";
+ }
+
+ if (!op_to) {
+ std::cerr << "Could not find op_to: " << key_to.identifier() << "\n";
}
+
+ if (!stack_.is_empty()) {
+ std::cerr << "\nTrace:\n\n";
+ stack_.print_backtrace(std::cerr);
+ std::cerr << "\n";
+ }
+
return nullptr;
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index 65cf0e7d9df..2e491cd37a6 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -322,7 +322,11 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
RootPChanMap root_map;
bool pose_depends_on_local_transform = false;
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*pchan);
+
LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*con);
+
switch (con->type) {
case CONSTRAINT_TYPE_KINEMATIC:
build_ik_pose(object, pchan, con, &root_map);
@@ -356,6 +360,8 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
}
/* Links between operations for each bone. */
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*pchan);
+
build_idproperties(pchan->prop);
OperationKey bone_local_key(
&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
index cdb7361afc0..cd1917cb607 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
@@ -36,6 +36,9 @@ void DepsgraphRelationBuilder::build_scene_parameters(Scene *scene)
if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_PARAMETERS)) {
return;
}
+
+ /* TODO(sergey): Trace as a scene parameters. */
+
build_idproperties(scene->id.properties);
build_parameters(&scene->id);
OperationKey parameters_eval_key(
@@ -56,6 +59,9 @@ void DepsgraphRelationBuilder::build_scene_compositor(Scene *scene)
if (scene->nodetree == nullptr) {
return;
}
+
+ /* TODO(sergey): Trace as a scene compositor. */
+
build_nodetree(scene->nodetree);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_stack.cc b/source/blender/depsgraph/intern/builder/deg_builder_stack.cc
new file mode 100644
index 00000000000..de0a5198a8a
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_stack.cc
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/builder/deg_builder_stack.h"
+
+#include <iomanip>
+#include <ios>
+#include <iostream>
+
+#include "BKE_idtype.h"
+
+#include "DNA_ID.h"
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
+
+namespace blender::deg {
+
+/* Spacing between adjacent columns, in number of spaces. */
+constexpr int kColumnSpacing = 4;
+
+/* Width of table columns including column padding.
+ * The type column width is a guesstimate based on "Particle Settings" with some extra padding. */
+constexpr int kPrintDepthWidth = 5 + kColumnSpacing;
+constexpr int kPrintTypeWidth = 21 + kColumnSpacing;
+
+namespace {
+
+/* NOTE: Depth column printing is already taken care of. */
+
+void print(std::ostream &stream, const ID *id)
+{
+ const IDTypeInfo *id_type_info = BKE_idtype_get_info_from_id(id);
+ stream << std::setw(kPrintTypeWidth) << id_type_info->name << (id->name + 2) << "\n";
+}
+
+void print(std::ostream &stream, const bConstraint *constraint)
+{
+ stream << std::setw(kPrintTypeWidth) << ("Constraint") << constraint->name << "\n";
+}
+
+void print(std::ostream &stream, const ModifierData *modifier_data)
+{
+ stream << std::setw(kPrintTypeWidth) << ("Modifier") << modifier_data->name << "\n";
+}
+
+void print(std::ostream &stream, const bPoseChannel *pchan)
+{
+ stream << std::setw(kPrintTypeWidth) << ("Pose Channel") << pchan->name << "\n";
+}
+
+} // namespace
+
+void BuilderStack::print_backtrace(std::ostream &stream)
+{
+ const std::ios_base::fmtflags old_flags(stream.flags());
+
+ stream << std::left;
+
+ stream << std::setw(kPrintDepthWidth) << "Depth" << std::setw(kPrintTypeWidth) << "Type"
+ << "Name"
+ << "\n";
+
+ stream << std::setw(kPrintDepthWidth) << "-----" << std::setw(kPrintTypeWidth) << "----"
+ << "----"
+ << "\n";
+
+ int depth = 1;
+ for (const Entry &entry : stack_) {
+ stream << std::setw(kPrintDepthWidth) << depth;
+ ++depth;
+
+ if (entry.id_ != nullptr) {
+ print(stream, entry.id_);
+ }
+ else if (entry.constraint_ != nullptr) {
+ print(stream, entry.constraint_);
+ }
+ else if (entry.modifier_data_ != nullptr) {
+ print(stream, entry.modifier_data_);
+ }
+ else if (entry.pchan_ != nullptr) {
+ print(stream, entry.pchan_);
+ }
+ }
+
+ stream.flags(old_flags);
+}
+
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_stack.h b/source/blender/depsgraph/intern/builder/deg_builder_stack.h
new file mode 100644
index 00000000000..3f9cc83928a
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_stack.h
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
+
+struct ID;
+struct bConstraint;
+struct bPoseChannel;
+struct ModifierData;
+
+namespace blender::deg {
+
+/* This class keeps track of the builder calls nesting, allowing to unroll them back and provide a
+ * clue about how the builder made it to its current state.
+ *
+ * The tracing is based on the builder giving a trace clues to the stack. Typical usage is:
+ *
+ * void DepsgraphRelationBuilder::my_id_builder(ID *id)
+ * {
+ * if (built_map_.checkIsBuiltAndTag(id)) {
+ * return;
+ * }
+ *
+ * const BuilderStack::ScopedEntry stack_entry = stack_.trace(*id);
+ *
+ * ...
+ * }
+ */
+class BuilderStack {
+ public:
+ /* Entry of the backtrace.
+ * A cheap-to-construct wrapper which allows to gather a proper string representation whenever
+ * the stack is printed. */
+ class Entry {
+ public:
+ explicit Entry(const ID &id) : id_(&id)
+ {
+ }
+
+ explicit Entry(const bConstraint &constraint) : constraint_(&constraint)
+ {
+ }
+
+ explicit Entry(const bPoseChannel &pchan) : pchan_(&pchan)
+ {
+ }
+
+ explicit Entry(const ModifierData &modifier_data) : modifier_data_(&modifier_data)
+ {
+ }
+
+ private:
+ friend class BuilderStack;
+
+ const ID *id_ = nullptr;
+ const bConstraint *constraint_ = nullptr;
+ const ModifierData *modifier_data_ = nullptr;
+ const bPoseChannel *pchan_ = nullptr;
+ };
+
+ using Stack = Vector<Entry>;
+
+ /* A helper class to provide a RAII style of tracing. It is constructed by the
+ * `BuilderStack::trace` (which pushes entry to the stack), and upon destruction of this object
+ * the corresponding entry is popped from the stack.
+ *
+ * The goal of this `ScopedEntry` is to free developers from worrying about removing entries from
+ * the stack whenever leaving a builder step scope. */
+ class ScopedEntry {
+ public:
+ /* Delete copy constructor and operator: scoped entries are only supposed to be constructed
+ * once and never copied. */
+ ScopedEntry(const ScopedEntry &other) = delete;
+ ScopedEntry &operator=(const ScopedEntry &other) = delete;
+
+ /* Move semantic. */
+ ScopedEntry(ScopedEntry &&other) noexcept : stack_(other.stack_)
+ {
+ other.stack_ = nullptr;
+ }
+ ScopedEntry &operator=(ScopedEntry &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ stack_ = other.stack_;
+ other.stack_ = nullptr;
+
+ return *this;
+ }
+
+ ~ScopedEntry()
+ {
+ /* Stack will become nullptr when the entry was moved somewhere else. */
+ if (stack_ != nullptr) {
+ BLI_assert(!stack_->is_empty());
+ stack_->pop_last();
+ }
+ }
+
+ private:
+ friend BuilderStack;
+
+ explicit ScopedEntry(Stack &stack) : stack_(&stack)
+ {
+ }
+
+ Stack *stack_;
+ };
+
+ BuilderStack() = default;
+ ~BuilderStack() = default;
+
+ bool is_empty() const
+ {
+ return stack_.is_empty();
+ }
+
+ void print_backtrace(std::ostream &stream);
+
+ template<class... Args> ScopedEntry trace(const Args &...args)
+ {
+ stack_.append_as(args...);
+
+ return ScopedEntry(stack_);
+ }
+
+ private:
+ Stack stack_;
+};
+
+} // namespace blender::deg
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 3e90c2cb707..3381dbadbab 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -69,6 +69,7 @@ set(SRC
intern/mesh_extractors/extract_mesh_vbo_uv.cc
intern/mesh_extractors/extract_mesh_vbo_vcol.cc
intern/mesh_extractors/extract_mesh_vbo_weights.cc
+ intern/draw_attributes.cc
intern/draw_cache_impl_curve.cc
intern/draw_cache_impl_curves.cc
intern/draw_cache_impl_displist.c
@@ -198,6 +199,7 @@ set(SRC
DRW_select_buffer.h
intern/DRW_gpu_wrapper.hh
intern/DRW_render.h
+ intern/draw_attributes.h
intern/draw_cache.h
intern/draw_cache_extract.h
intern/draw_cache_impl.h
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index 105600d2333..6fd5d97089d 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -169,7 +169,6 @@ extern char datatoc_common_hair_lib_glsl[];
extern char datatoc_common_math_lib_glsl[];
extern char datatoc_common_math_geom_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
extern char datatoc_gpu_shader_codegen_lib_glsl[];
extern char datatoc_ambient_occlusion_lib_glsl[];
@@ -278,7 +277,6 @@ static void eevee_shader_library_ensure(void)
DRW_SHADER_LIB_ADD(e_data.lib, common_hair_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_uniforms_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib);
DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_codegen_lib);
DRW_SHADER_LIB_ADD(e_data.lib, random_lib);
DRW_SHADER_LIB_ADD(e_data.lib, renderpass_lib);
diff --git a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
index 05577944140..216a15de2b9 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
+++ b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
@@ -118,6 +118,10 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
info.vertex_inputs_.clear();
}
+ if (is_hair) {
+ info.additional_info("draw_curves_infos");
+ }
+
if (!is_volume) {
info.define("EEVEE_GENERATED_INTERFACE");
info.vertex_out(*stage_interface);
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
index 5295a05b965..2926f8c5a89 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
@@ -65,6 +65,22 @@ vec3 attr_load_orco(samplerBuffer cd_buf)
}
# endif
+/* Per attribute scope follows loading order. */
+int g_curves_attr_id = 0;
+
+/* Return the index to use for looking up the attribute value in the sampler
+ * based on the attribute scope (point or spline). */
+int curves_attribute_element_id()
+{
+ int id = hairStrandID;
+ if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+ id = hair_get_base_id();
+ }
+
+ g_curves_attr_id += 1;
+ return id;
+}
+
vec4 attr_load_tangent(samplerBuffer cd_buf)
{
/* Not supported. */
@@ -73,22 +89,22 @@ vec4 attr_load_tangent(samplerBuffer cd_buf)
vec4 attr_load_vec4(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgba;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgba;
}
vec3 attr_load_vec3(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgb;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgb;
}
vec2 attr_load_vec2(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rg;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rg;
}
float attr_load_float(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).r;
+ return texelFetch(cd_buf, curves_attribute_element_id()).r;
}
#else
diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
index 23324146b7e..8e1bafe8d92 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -108,9 +108,7 @@ GlobalData init_globals(void)
# endif
surf.barycentric_coords = vec2(0.0);
surf.barycentric_dists = vec3(0.0);
- if (!FrontFacing) {
- surf.N = -surf.N;
- }
+ surf.N = (FrontFacing) ? surf.N : -surf.N;
# ifdef HAIR_SHADER
vec3 V = cameraVec(surf.P);
/* Shade as a cylinder. */
diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
index 7cb4d7ac25c..a8e95e13b12 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
@@ -72,6 +72,22 @@ vec3 attr_load_orco(samplerBuffer cd_buf)
}
# endif
+/* Per attribute scope follows loading order. */
+int g_curves_attr_id = 0;
+
+/* Return the index to use for looking up the attribute value in the sampler
+ * based on the attribute scope (point or spline). */
+int curves_attribute_element_id()
+{
+ int id = hairStrandID;
+ if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+ id = hair_get_base_id();
+ }
+
+ g_curves_attr_id += 1;
+ return id;
+}
+
vec4 attr_load_tangent(samplerBuffer cd_buf)
{
return vec4(hairTangent, 1.0);
@@ -79,22 +95,22 @@ vec4 attr_load_tangent(samplerBuffer cd_buf)
vec4 attr_load_vec4(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgba;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgba;
}
vec3 attr_load_vec3(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgb;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgb;
}
vec2 attr_load_vec2(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rg;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rg;
}
float attr_load_float(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).r;
+ return texelFetch(cd_buf, curves_attribute_element_id()).r;
}
#else
@@ -117,7 +133,7 @@ vec3 attr_load_orco(vec4 orco)
vec4 attr_load_tangent(vec4 tangent)
{
- tangent.xyz = normal_object_to_world(tangent.xyz);
+ tangent.xyz = safe_normalize(normal_object_to_world(tangent.xyz));
return tangent;
}
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc
index 009eb54864c..09aa97e49e9 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc
@@ -161,6 +161,7 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
}
}
info.vertex_inputs_.clear();
+ info.additional_info("draw_curves_infos");
break;
case MAT_GEOM_WORLD:
/**
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
index 3c5acf62e30..1b113e529b6 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
@@ -112,6 +112,7 @@ float attr_load_float(float attr)
/** \name Curve
*
* Curve objects loads attributes from buffers through sampler buffers.
+ * Per attribute scope follows loading order.
* \{ */
# ifdef OBINFO_LIB
@@ -122,6 +123,22 @@ vec3 attr_load_orco(vec4 orco)
return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz;
}
# endif
+
+int g_curves_attr_id = 0;
+
+/* Return the index to use for looking up the attribute value in the sampler
+ * based on the attribute scope (point or spline). */
+int curves_attribute_element_id()
+{
+ int id = interp.curves_strand_id;
+ if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+ id = hair_get_base_id();
+ }
+
+ g_curves_attr_id += 1;
+ return id;
+}
+
vec4 attr_load_tangent(samplerBuffer cd_buf)
{
/* Not supported for the moment. */
@@ -137,19 +154,19 @@ vec4 attr_load_color(samplerBuffer cd_buf)
}
vec4 attr_load_vec4(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).rgba;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgba;
}
vec3 attr_load_vec3(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).rgb;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgb;
}
vec2 attr_load_vec2(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).rg;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rg;
}
float attr_load_float(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).r;
+ return texelFetch(cd_buf, curves_attribute_element_id()).r;
}
/** \} */
diff --git a/source/blender/draw/engines/overlay/overlay_shader_shared.h b/source/blender/draw/engines/overlay/overlay_shader_shared.h
index 99700cdcec4..339b6f02e1a 100644
--- a/source/blender/draw/engines/overlay/overlay_shader_shared.h
+++ b/source/blender/draw/engines/overlay/overlay_shader_shared.h
@@ -24,19 +24,19 @@ typedef struct OVERLAY_GridData OVERLAY_GridData;
#define BG_MASK 5
enum OVERLAY_GridBits {
- SHOW_AXIS_X = (1 << 0),
- SHOW_AXIS_Y = (1 << 1),
- SHOW_AXIS_Z = (1 << 2),
- SHOW_GRID = (1 << 3),
- PLANE_XY = (1 << 4),
- PLANE_XZ = (1 << 5),
- PLANE_YZ = (1 << 6),
- CLIP_ZPOS = (1 << 7),
- CLIP_ZNEG = (1 << 8),
- GRID_BACK = (1 << 9),
- GRID_CAMERA = (1 << 10),
- PLANE_IMAGE = (1 << 11),
- CUSTOM_GRID = (1 << 12),
+ SHOW_AXIS_X = (1u << 0u),
+ SHOW_AXIS_Y = (1u << 1u),
+ SHOW_AXIS_Z = (1u << 2u),
+ SHOW_GRID = (1u << 3u),
+ PLANE_XY = (1u << 4u),
+ PLANE_XZ = (1u << 5u),
+ PLANE_YZ = (1u << 6u),
+ CLIP_ZPOS = (1u << 7u),
+ CLIP_ZNEG = (1u << 8u),
+ GRID_BACK = (1u << 9u),
+ GRID_CAMERA = (1u << 10u),
+ PLANE_IMAGE = (1u << 11u),
+ CUSTOM_GRID = (1u << 12u),
};
/* Match: #SI_GRID_STEPS_LEN */
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
index 3e3c0e4e89f..472a589f441 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
@@ -36,7 +36,7 @@ bvec4 gather_edges(vec2 uv, uint ref)
#ifdef GPU_ARB_texture_gather
ids = textureGather(outlineId, uv);
#else
- vec3 ofs = vec3(0.5, 0.5, -0.5) * drw_view.viewport_size_inversey;
+ vec3 ofs = vec3(0.5, 0.5, -0.5) * drw_view.viewport_size_inverse.xyy;
ids.x = textureLod(outlineId, uv - ofs.xz, 0.0).r;
ids.y = textureLod(outlineId, uv + ofs.xy, 0.0).r;
ids.z = textureLod(outlineId, uv + ofs.xz, 0.0).r;
diff --git a/source/blender/draw/intern/draw_attributes.cc b/source/blender/draw/intern/draw_attributes.cc
new file mode 100644
index 00000000000..714f1dbb3d1
--- /dev/null
+++ b/source/blender/draw/intern/draw_attributes.cc
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+#include "draw_attributes.h"
+
+/* Return true if the given DRW_AttributeRequest is already in the requests. */
+static bool drw_attributes_has_request(const DRW_Attributes *requests, DRW_AttributeRequest req)
+{
+ for (int i = 0; i < requests->num_requests; i++) {
+ const DRW_AttributeRequest src_req = requests->requests[i];
+ if (src_req.domain != req.domain) {
+ continue;
+ }
+ if (src_req.layer_index != req.layer_index) {
+ continue;
+ }
+ if (src_req.cd_type != req.cd_type) {
+ continue;
+ }
+ return true;
+ }
+ return false;
+}
+
+static void drw_attributes_merge_requests(const DRW_Attributes *src_requests,
+ DRW_Attributes *dst_requests)
+{
+ for (int i = 0; i < src_requests->num_requests; i++) {
+ if (dst_requests->num_requests == GPU_MAX_ATTR) {
+ return;
+ }
+
+ if (drw_attributes_has_request(dst_requests, src_requests->requests[i])) {
+ continue;
+ }
+
+ dst_requests->requests[dst_requests->num_requests] = src_requests->requests[i];
+ dst_requests->num_requests += 1;
+ }
+}
+
+void drw_attributes_clear(DRW_Attributes *attributes)
+{
+ memset(attributes, 0, sizeof(DRW_Attributes));
+}
+
+void drw_attributes_merge(DRW_Attributes *dst,
+ const DRW_Attributes *src,
+ ThreadMutex *render_mutex)
+{
+ BLI_mutex_lock(render_mutex);
+ drw_attributes_merge_requests(src, dst);
+ BLI_mutex_unlock(render_mutex);
+}
+
+bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b)
+{
+ for (int i = 0; i < b->num_requests; i++) {
+ if (!drw_attributes_has_request(a, b->requests[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
+ CustomDataType type,
+ int layer,
+ AttributeDomain domain)
+{
+ if (attrs->num_requests >= GPU_MAX_ATTR) {
+ return nullptr;
+ }
+
+ DRW_AttributeRequest *req = &attrs->requests[attrs->num_requests];
+ req->cd_type = type;
+ req->layer_index = layer;
+ req->domain = domain;
+ attrs->num_requests += 1;
+ return req;
+}
+
+bool drw_custom_data_match_attribute(const CustomData *custom_data,
+ const char *name,
+ int *r_layer_index,
+ int *r_type)
+{
+ const int possible_attribute_types[7] = {
+ CD_PROP_BOOL,
+ CD_PROP_INT8,
+ CD_PROP_INT32,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT2,
+ CD_PROP_FLOAT3,
+ CD_PROP_COLOR,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) {
+ const int attr_type = possible_attribute_types[i];
+ int layer_index = CustomData_get_named_layer(custom_data, attr_type, name);
+ if (layer_index == -1) {
+ continue;
+ }
+
+ *r_layer_index = layer_index;
+ *r_type = attr_type;
+ return true;
+ }
+
+ return false;
+}
diff --git a/source/blender/draw/intern/draw_attributes.h b/source/blender/draw/intern/draw_attributes.h
new file mode 100644
index 00000000000..192ffa43337
--- /dev/null
+++ b/source/blender/draw/intern/draw_attributes.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup draw
+ *
+ * \brief Utilities for rendering attributes.
+ */
+
+#pragma once
+
+#include "DNA_customdata_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute.h"
+
+#include "BLI_sys_types.h"
+#include "BLI_threads.h"
+
+#include "GPU_shader.h"
+#include "GPU_vertex_format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DRW_AttributeRequest {
+ CustomDataType cd_type;
+ int layer_index;
+ AttributeDomain domain;
+ char attribute_name[64];
+} DRW_AttributeRequest;
+
+typedef struct DRW_Attributes {
+ DRW_AttributeRequest requests[GPU_MAX_ATTR];
+ int num_requests;
+} DRW_Attributes;
+
+void drw_attributes_clear(DRW_Attributes *attributes);
+
+void drw_attributes_merge(DRW_Attributes *dst,
+ const DRW_Attributes *src,
+ ThreadMutex *render_mutex);
+
+/* Return true if all requests in b are in a. */
+bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b);
+
+DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
+ CustomDataType type,
+ int layer,
+ AttributeDomain domain);
+
+bool drw_custom_data_match_attribute(const CustomData *custom_data,
+ const char *name,
+ int *r_layer_index,
+ int *r_type);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 67700a4274f..fb074cc728e 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -3400,6 +3400,9 @@ void DRW_batch_cache_free_old(Object *ob, int ctime)
case OB_MESH:
DRW_mesh_batch_cache_free_old((Mesh *)ob->data, ctime);
break;
+ case OB_CURVES:
+ DRW_curves_batch_cache_free_old((Curves *)ob->data, ctime);
+ break;
/* TODO: all cases. */
default:
break;
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index cb6006e303a..ce3ad9923da 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -20,6 +20,8 @@ struct TaskGraph;
#include "GPU_index_buffer.h"
#include "GPU_vertex_buffer.h"
+#include "draw_attributes.h"
+
/* Vertex Group Selection and display options */
typedef struct DRW_MeshWeightState {
int defgroup_active;
@@ -67,17 +69,6 @@ typedef enum eMRIterType {
} eMRIterType;
ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT)
-typedef struct DRW_AttributeRequest {
- CustomDataType cd_type;
- int layer_index;
- AttributeDomain domain;
-} DRW_AttributeRequest;
-
-typedef struct DRW_MeshAttributes {
- DRW_AttributeRequest requests[GPU_MAX_ATTR];
- int num_requests;
-} DRW_MeshAttributes;
-
typedef enum eMRDataType {
MR_DATA_NONE = 0,
MR_DATA_POLY_NOR = 1 << 1,
@@ -294,7 +285,7 @@ typedef struct MeshBatchCache {
DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
- DRW_MeshAttributes attr_used, attr_needed, attr_used_over_time;
+ DRW_Attributes attr_used, attr_needed, attr_used_over_time;
int lastmatch;
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index ec544d8e786..3d44d3d1b3f 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -793,7 +793,12 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
/* The order in which extractors are added to the list matters somewhat, as some buffers are
* reused when building others. */
EXTRACT_ADD_REQUESTED(ibo, tris);
- EXTRACT_ADD_REQUESTED(vbo, pos_nor);
+
+ /* Orcos are extracted at the same time as positions. */
+ if (DRW_vbo_requested(mbuflist->vbo.pos_nor) || DRW_vbo_requested(mbuflist->vbo.orco)) {
+ extractors.append(&extract_pos_nor);
+ }
+
EXTRACT_ADD_REQUESTED(vbo, lnor);
for (int i = 0; i < GPU_MAX_ATTR; i++) {
EXTRACT_ADD_REQUESTED(vbo, attr[i]);
@@ -843,7 +848,6 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
EXTRACT_ADD_REQUESTED(ibo, lines_paint_mask);
EXTRACT_ADD_REQUESTED(ibo, lines_adjacency);
- EXTRACT_ADD_REQUESTED(vbo, orco);
EXTRACT_ADD_REQUESTED(vbo, vcol);
EXTRACT_ADD_REQUESTED(vbo, weights);
EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index f877c94208f..0755d5967d5 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -83,6 +83,7 @@ void DRW_batch_cache_free_old(struct Object *ob, int ctime);
* \note For now this only free the shading batches / VBO if any cd layers is not needed anymore.
*/
void DRW_mesh_batch_cache_free_old(struct Mesh *me, int ctime);
+void DRW_curves_batch_cache_free_old(struct Curves *curves, int ctime);
/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc
index 1896df7c650..f9cf0021fcd 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -24,6 +24,7 @@
#include "DNA_scene_types.h"
#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
#include "GPU_batch.h"
#include "GPU_material.h"
@@ -31,10 +32,13 @@
#include "DRW_render.h"
+#include "draw_attributes.h"
#include "draw_cache_impl.h" /* own include */
#include "draw_cache_inline.h"
#include "draw_curves_private.h" /* own include */
+#include "draw_shader.h"
+using blender::ColorGeometry4f;
using blender::float3;
using blender::IndexRange;
using blender::MutableSpan;
@@ -50,6 +54,10 @@ struct CurvesBatchCache {
/* To determine if cache is invalid. */
bool is_dirty;
+
+ /** Needed when updating material data (e.g. attributes) as the same curves might be used for
+ * multiple objects with different materials. */
+ ThreadMutex render_mutex;
};
static bool curves_batch_cache_valid(const Curves &curves)
@@ -64,6 +72,7 @@ static void curves_batch_cache_init(Curves &curves)
if (!cache) {
cache = MEM_cnew<CurvesBatchCache>(__func__);
+ BLI_mutex_init(&cache->render_mutex);
curves.batch_cache = cache;
}
else {
@@ -73,6 +82,23 @@ static void curves_batch_cache_init(Curves &curves)
cache->is_dirty = false;
}
+static void curves_discard_attributes(CurvesEvalCache &curves_cache)
+{
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_attributes_buf[i]);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.proc_attributes_tex[i]);
+ }
+
+ for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ for (int j = 0; j < GPU_MAX_ATTR; j++) {
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].attributes_buf[j]);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].attributes_tex[j]);
+ }
+
+ drw_attributes_clear(&curves_cache.final[i].attr_used);
+ }
+}
+
static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache)
{
/* TODO: more granular update tagging. */
@@ -93,6 +119,8 @@ static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache)
GPU_BATCH_DISCARD_SAFE(curves_cache.final[i].proc_hairs[j]);
}
}
+
+ curves_discard_attributes(curves_cache);
}
static void curves_batch_cache_clear(Curves &curves)
@@ -139,9 +167,39 @@ void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode)
void DRW_curves_batch_cache_free(Curves *curves)
{
curves_batch_cache_clear(*curves);
+ CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
+ BLI_mutex_end(&cache->render_mutex);
MEM_SAFE_FREE(curves->batch_cache);
}
+void DRW_curves_batch_cache_free_old(Curves *curves, int ctime)
+{
+ CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
+ if (cache == nullptr) {
+ return;
+ }
+
+ bool do_discard = false;
+
+ for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ CurvesEvalFinalCache &final_cache = cache->curves_cache.final[i];
+
+ if (drw_attributes_overlap(&final_cache.attr_used_over_time, &final_cache.attr_used)) {
+ final_cache.last_attr_matching_time = ctime;
+ }
+
+ if (ctime - final_cache.last_attr_matching_time > U.vbotimeout) {
+ do_discard = true;
+ }
+
+ drw_attributes_clear(&final_cache.attr_used_over_time);
+ }
+
+ if (do_discard) {
+ curves_discard_attributes(cache->curves_cache);
+ }
+}
+
static void ensure_seg_pt_count(const Curves &curves, CurvesEvalCache &curves_cache)
{
if (curves_cache.proc_point_buf != nullptr) {
@@ -242,6 +300,88 @@ static void curves_batch_cache_ensure_procedural_pos(Curves &curves,
}
}
+void drw_curves_get_attribute_sampler_name(const char *layer_name, char r_sampler_name[32])
+{
+ char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+ /* Attributes use auto-name. */
+ BLI_snprintf(r_sampler_name, 32, "a%s", attr_safe_name);
+}
+
+static void curves_batch_cache_ensure_procedural_final_attr(
+ CurvesEvalCache &cache, GPUVertFormat *format, int subdiv, int index, const char *name)
+{
+ CurvesEvalFinalCache &final_cache = cache.final[subdiv];
+ final_cache.attributes_buf[index] = GPU_vertbuf_create_with_format_ex(format,
+ GPU_USAGE_DEVICE_ONLY);
+
+ /* Create a destination buffer for the transform feedback. Sized appropriately */
+ /* Those are points! not line segments. */
+ GPU_vertbuf_data_alloc(final_cache.attributes_buf[index],
+ final_cache.strands_res * cache.strands_len);
+
+ /* Create vbo immediately to bind to texture buffer. */
+ GPU_vertbuf_use(final_cache.attributes_buf[index]);
+
+ final_cache.attributes_tex[index] = GPU_texture_create_from_vertbuf(
+ name, final_cache.attributes_buf[index]);
+}
+
+static void curves_batch_ensure_attribute(const Curves &curves,
+ CurvesEvalCache &cache,
+ const DRW_AttributeRequest &request,
+ int subdiv,
+ int index)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache.proc_attributes_buf[index]);
+ DRW_TEXTURE_FREE_SAFE(cache.proc_attributes_tex[index]);
+
+ char sampler_name[32];
+ drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name);
+
+ GPUVertFormat format = {0};
+ GPU_vertformat_deinterleave(&format);
+ /* All attributes use vec4, see comment below. */
+ GPU_vertformat_attr_add(&format, sampler_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ cache.proc_attributes_buf[index] = GPU_vertbuf_create_with_format(&format);
+ GPUVertBuf *attr_vbo = cache.proc_attributes_buf[index];
+
+ GPU_vertbuf_data_alloc(attr_vbo,
+ request.domain == ATTR_DOMAIN_POINT ? curves.geometry.point_num :
+ curves.geometry.curve_num);
+
+ CurveComponent component;
+ component.replace(const_cast<Curves *>(&curves), GeometryOwnershipType::ReadOnly);
+
+ /* TODO(@kevindietrich): float4 is used for scalar attributes as the implicit conversion done
+ * by OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following
+ * the Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a
+ * similar texture state swizzle to map the attribute correctly as for volume attributes, so we
+ * can control the conversion ourselves. */
+ blender::VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>(
+ request.attribute_name, request.domain, {0.0f, 0.0f, 0.0f, 1.0f});
+
+ MutableSpan<ColorGeometry4f> vbo_span{
+ static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(attr_vbo)),
+ component.attribute_domain_num(request.domain)};
+
+ attribute.materialize(vbo_span);
+
+ GPU_vertbuf_use(attr_vbo);
+ cache.proc_attributes_tex[index] = GPU_texture_create_from_vertbuf(sampler_name, attr_vbo);
+
+ /* Existing final data may have been for a different attribute (with a different name or domain),
+ * free the data. */
+ GPU_VERTBUF_DISCARD_SAFE(cache.final[subdiv].attributes_buf[index]);
+ DRW_TEXTURE_FREE_SAFE(cache.final[subdiv].attributes_tex[index]);
+
+ /* Ensure final data for points. */
+ if (request.domain == ATTR_DOMAIN_POINT) {
+ curves_batch_cache_ensure_procedural_final_attr(cache, &format, subdiv, index, sampler_name);
+ }
+}
+
static void curves_batch_cache_fill_strands_data(const Curves &curves_id,
GPUVertBufRaw &data_step,
GPUVertBufRaw &seg_step)
@@ -358,6 +498,88 @@ static void curves_batch_cache_ensure_procedural_indices(Curves &curves,
prim_type, vbo, GPU_indexbuf_build(&elb), GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
}
+static bool curves_ensure_attributes(const Curves &curves,
+ CurvesBatchCache &cache,
+ GPUMaterial *gpu_material,
+ int subdiv)
+{
+ ThreadMutex *render_mutex = &cache.render_mutex;
+ const CustomData *cd_curve = &curves.geometry.curve_data;
+ const CustomData *cd_point = &curves.geometry.point_data;
+
+ DRW_Attributes attrs_needed;
+ drw_attributes_clear(&attrs_needed);
+ ListBase gpu_attrs = GPU_material_attributes(gpu_material);
+ LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
+ const char *name = gpu_attr->name;
+ int type = gpu_attr->type;
+ int layer = -1;
+ AttributeDomain domain;
+
+ if (drw_custom_data_match_attribute(cd_curve, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_CURVE;
+ }
+ else if (drw_custom_data_match_attribute(cd_point, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_POINT;
+ }
+ else {
+ continue;
+ }
+
+ switch (type) {
+ default:
+ break;
+ case CD_PROP_BOOL:
+ case CD_PROP_INT8:
+ case CD_PROP_INT32:
+ case CD_PROP_FLOAT:
+ case CD_PROP_FLOAT2:
+ case CD_PROP_FLOAT3:
+ case CD_PROP_COLOR: {
+ if (layer != -1) {
+ DRW_AttributeRequest *req = drw_attributes_add_request(
+ &attrs_needed, (CustomDataType)type, layer, domain);
+ if (req) {
+ BLI_strncpy(req->attribute_name, name, sizeof(req->attribute_name));
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv];
+
+ const bool attr_overlap = drw_attributes_overlap(&final_cache.attr_used, &attrs_needed);
+ if (attr_overlap == false) {
+ /* Some new attributes have been added, free all and start over. */
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ GPU_VERTBUF_DISCARD_SAFE(cache.curves_cache.proc_attributes_buf[i]);
+ DRW_TEXTURE_FREE_SAFE(cache.curves_cache.proc_attributes_tex[i]);
+ }
+ drw_attributes_merge(&final_cache.attr_used, &attrs_needed, render_mutex);
+ }
+ drw_attributes_merge(&final_cache.attr_used_over_time, &attrs_needed, render_mutex);
+
+ bool need_tf_update = false;
+
+ for (int i = 0; i < final_cache.attr_used.num_requests; i++) {
+ const DRW_AttributeRequest &request = final_cache.attr_used.requests[i];
+
+ if (cache.curves_cache.proc_attributes_buf[i] != nullptr) {
+ continue;
+ }
+
+ if (request.domain == ATTR_DOMAIN_POINT) {
+ need_tf_update = true;
+ }
+
+ curves_batch_ensure_attribute(curves, cache.curves_cache, request, subdiv, i);
+ }
+
+ return need_tf_update;
+}
+
bool curves_ensure_procedural_data(Object *object,
CurvesEvalCache **r_hair_cache,
GPUMaterial *gpu_material,
@@ -395,6 +617,10 @@ bool curves_ensure_procedural_data(Object *object,
curves, cache.curves_cache, thickness_res, subdiv);
}
+ if (gpu_material) {
+ need_ft_update |= curves_ensure_attributes(curves, cache, gpu_material, subdiv);
+ }
+
return need_ft_update;
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 7fdeaf34965..a6ab2176d16 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -281,91 +281,6 @@ static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *c
cd_used->edit_uv = 1;
}
-/** \name DRW_MeshAttributes
- *
- * Utilities for handling requested attributes.
- * \{ */
-
-/* Return true if the given DRW_AttributeRequest is already in the requests. */
-static bool has_request(const DRW_MeshAttributes *requests, DRW_AttributeRequest req)
-{
- for (int i = 0; i < requests->num_requests; i++) {
- const DRW_AttributeRequest src_req = requests->requests[i];
- if (src_req.domain != req.domain) {
- continue;
- }
- if (src_req.layer_index != req.layer_index) {
- continue;
- }
- if (src_req.cd_type != req.cd_type) {
- continue;
- }
- return true;
- }
- return false;
-}
-
-static void mesh_attrs_merge_requests(const DRW_MeshAttributes *src_requests,
- DRW_MeshAttributes *dst_requests)
-{
- for (int i = 0; i < src_requests->num_requests; i++) {
- if (dst_requests->num_requests == GPU_MAX_ATTR) {
- return;
- }
-
- if (has_request(dst_requests, src_requests->requests[i])) {
- continue;
- }
-
- dst_requests->requests[dst_requests->num_requests] = src_requests->requests[i];
- dst_requests->num_requests += 1;
- }
-}
-
-static void drw_mesh_attributes_clear(DRW_MeshAttributes *attributes)
-{
- memset(attributes, 0, sizeof(DRW_MeshAttributes));
-}
-
-static void drw_mesh_attributes_merge(DRW_MeshAttributes *dst,
- const DRW_MeshAttributes *src,
- ThreadMutex *mesh_render_mutex)
-{
- BLI_mutex_lock(mesh_render_mutex);
- mesh_attrs_merge_requests(src, dst);
- BLI_mutex_unlock(mesh_render_mutex);
-}
-
-/* Return true if all requests in b are in a. */
-static bool drw_mesh_attributes_overlap(DRW_MeshAttributes *a, DRW_MeshAttributes *b)
-{
- for (int i = 0; i < b->num_requests; i++) {
- if (!has_request(a, b->requests[i])) {
- return false;
- }
- }
-
- return true;
-}
-
-static void drw_mesh_attributes_add_request(DRW_MeshAttributes *attrs,
- CustomDataType type,
- int layer,
- AttributeDomain domain)
-{
- if (attrs->num_requests >= GPU_MAX_ATTR) {
- return;
- }
-
- DRW_AttributeRequest *req = &attrs->requests[attrs->num_requests];
- req->cd_type = type;
- req->layer_index = layer;
- req->domain = domain;
- attrs->num_requests += 1;
-}
-
-/** \} */
-
BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
@@ -475,36 +390,6 @@ static void mesh_cd_calc_active_mloopcol_layer(const Object *object,
}
}
-static bool custom_data_match_attribute(const CustomData *custom_data,
- const char *name,
- int *r_layer_index,
- int *r_type)
-{
- const int possible_attribute_types[7] = {
- CD_PROP_BOOL,
- CD_PROP_INT8,
- CD_PROP_INT32,
- CD_PROP_FLOAT,
- CD_PROP_FLOAT2,
- CD_PROP_FLOAT3,
- CD_PROP_COLOR,
- };
-
- for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) {
- const int attr_type = possible_attribute_types[i];
- int layer_index = CustomData_get_named_layer(custom_data, attr_type, name);
- if (layer_index == -1) {
- continue;
- }
-
- *r_layer_index = layer_index;
- *r_type = attr_type;
- return true;
- }
-
- return false;
-}
-
static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
const CustomData *cd_vdata,
const CustomData *cd_ldata,
@@ -556,7 +441,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
const Mesh *me,
struct GPUMaterial **gpumat_array,
int gpumat_array_len,
- DRW_MeshAttributes *attributes)
+ DRW_Attributes *attributes)
{
const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
@@ -636,16 +521,16 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
if (layer == -1) {
/* Try to match a generic attribute, we use the first attribute domain with a
* matching name. */
- if (custom_data_match_attribute(cd_vdata, name, &layer, &type)) {
+ if (drw_custom_data_match_attribute(cd_vdata, name, &layer, &type)) {
domain = ATTR_DOMAIN_POINT;
}
- else if (custom_data_match_attribute(cd_ldata, name, &layer, &type)) {
+ else if (drw_custom_data_match_attribute(cd_ldata, name, &layer, &type)) {
domain = ATTR_DOMAIN_CORNER;
}
- else if (custom_data_match_attribute(cd_pdata, name, &layer, &type)) {
+ else if (drw_custom_data_match_attribute(cd_pdata, name, &layer, &type)) {
domain = ATTR_DOMAIN_FACE;
}
- else if (custom_data_match_attribute(cd_edata, name, &layer, &type)) {
+ else if (drw_custom_data_match_attribute(cd_edata, name, &layer, &type)) {
domain = ATTR_DOMAIN_EDGE;
}
else {
@@ -718,7 +603,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
}
if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
- drw_mesh_attributes_add_request(attributes, type, layer, domain);
+ drw_attributes_add_request(attributes, type, layer, domain);
}
break;
}
@@ -729,7 +614,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
case CD_PROP_FLOAT:
case CD_PROP_FLOAT2: {
if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
- drw_mesh_attributes_add_request(attributes, type, layer, domain);
+ drw_attributes_add_request(attributes, type, layer, domain);
}
break;
}
@@ -1317,8 +1202,8 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object,
uint gpumat_array_len)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- DRW_MeshAttributes attrs_needed;
- drw_mesh_attributes_clear(&attrs_needed);
+ DRW_Attributes attrs_needed;
+ drw_attributes_clear(&attrs_needed);
DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers(
object, me, gpumat_array, gpumat_array_len, &attrs_needed);
@@ -1326,7 +1211,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object,
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
- drw_mesh_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
+ drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
mesh_batch_cache_request_surface_batches(cache);
return cache->surface_per_mat;
}
@@ -1596,7 +1481,7 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
cache->lastmatch = ctime;
}
- if (drw_mesh_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) {
+ if (drw_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) {
cache->lastmatch = ctime;
}
@@ -1605,12 +1490,12 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
}
mesh_cd_layers_type_clear(&cache->cd_used_over_time);
- drw_mesh_attributes_clear(&cache->attr_used_over_time);
+ drw_attributes_clear(&cache->attr_used_over_time);
}
static void drw_add_attributes_vbo(GPUBatch *batch,
MeshBufferList *mbuflist,
- DRW_MeshAttributes *attr_used)
+ DRW_Attributes *attr_used)
{
for (int i = 0; i < attr_used->num_requests; i++) {
DRW_vbo_request(batch, &mbuflist->vbo.attr[i]);
@@ -1721,7 +1606,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
/* TODO(fclem): We could be a bit smarter here and only do it per
* material. */
bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed);
- bool attr_overlap = drw_mesh_attributes_overlap(&cache->attr_used, &cache->attr_needed);
+ bool attr_overlap = drw_attributes_overlap(&cache->attr_used, &cache->attr_needed);
if (cd_overlap == false || attr_overlap == false) {
FOREACH_MESH_BUFFER_CACHE (cache, mbc) {
if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv) {
@@ -1741,7 +1626,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol);
}
- if (!drw_mesh_attributes_overlap(&cache->attr_used, &cache->attr_needed)) {
+ if (!drw_attributes_overlap(&cache->attr_used, &cache->attr_needed)) {
for (int i = 0; i < GPU_MAX_ATTR; i++) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.attr[i]);
}
@@ -1756,13 +1641,13 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
cache->batch_ready &= ~(MBC_SURFACE);
mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed);
- drw_mesh_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex);
+ drw_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex);
}
mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed);
mesh_cd_layers_type_clear(&cache->cd_needed);
- drw_mesh_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex);
- drw_mesh_attributes_clear(&cache->attr_needed);
+ drw_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex);
+ drw_attributes_clear(&cache->attr_needed);
}
if (batch_requested & MBC_EDITUV) {
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index cfdf059ca37..a0c7e064e00 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -69,6 +69,8 @@ enum {
SHADER_PATCH_EVALUATION,
SHADER_PATCH_EVALUATION_FVAR,
SHADER_PATCH_EVALUATION_FACE_DOTS,
+ SHADER_PATCH_EVALUATION_FACE_DOTS_WITH_NORMALS,
+ SHADER_PATCH_EVALUATION_ORCO,
SHADER_COMP_CUSTOM_DATA_INTERP_1D,
SHADER_COMP_CUSTOM_DATA_INTERP_2D,
SHADER_COMP_CUSTOM_DATA_INTERP_3D,
@@ -107,7 +109,9 @@ static const char *get_shader_code(int shader_type)
}
case SHADER_PATCH_EVALUATION:
case SHADER_PATCH_EVALUATION_FVAR:
- case SHADER_PATCH_EVALUATION_FACE_DOTS: {
+ case SHADER_PATCH_EVALUATION_FACE_DOTS:
+ case SHADER_PATCH_EVALUATION_FACE_DOTS_WITH_NORMALS:
+ case SHADER_PATCH_EVALUATION_ORCO: {
return datatoc_common_subdiv_patch_evaluation_comp_glsl;
}
case SHADER_COMP_CUSTOM_DATA_INTERP_1D:
@@ -163,6 +167,12 @@ static const char *get_shader_name(int shader_type)
case SHADER_PATCH_EVALUATION_FACE_DOTS: {
return "subdiv patch evaluation face dots";
}
+ case SHADER_PATCH_EVALUATION_FACE_DOTS_WITH_NORMALS: {
+ return "subdiv patch evaluation face dots with normals";
+ }
+ case SHADER_PATCH_EVALUATION_ORCO: {
+ return "subdiv patch evaluation orco";
+ }
case SHADER_COMP_CUSTOM_DATA_INTERP_1D: {
return "subdiv custom data interp 1D";
}
@@ -206,6 +216,19 @@ static GPUShader *get_patch_evaluation_shader(int shader_type)
"#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
"#define FDOTS_EVALUATION\n";
}
+ else if (shader_type == SHADER_PATCH_EVALUATION_FACE_DOTS_WITH_NORMALS) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define FDOTS_EVALUATION\n"
+ "#define FOTS_NORMALS\n";
+ }
+ else if (shader_type == SHADER_PATCH_EVALUATION_ORCO) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define ORCO_EVALUATION\n";
+ }
else {
defines =
"#define OSD_PATCH_BASIS_GLSL\n"
@@ -236,7 +259,8 @@ static GPUShader *get_subdiv_shader(int shader_type, const char *defines)
if (ELEM(shader_type,
SHADER_PATCH_EVALUATION,
SHADER_PATCH_EVALUATION_FVAR,
- SHADER_PATCH_EVALUATION_FACE_DOTS)) {
+ SHADER_PATCH_EVALUATION_FACE_DOTS,
+ SHADER_PATCH_EVALUATION_ORCO)) {
return get_patch_evaluation_shader(shader_type);
}
if (g_subdiv_shaders[shader_type] == nullptr) {
@@ -588,8 +612,9 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache)
#define SUBDIV_COARSE_FACE_FLAG_SMOOTH 1u
#define SUBDIV_COARSE_FACE_FLAG_SELECT 2u
#define SUBDIV_COARSE_FACE_FLAG_ACTIVE 4u
+#define SUBDIV_COARSE_FACE_FLAG_HIDDEN 8u
-#define SUBDIV_COARSE_FACE_FLAG_OFFSET 29u
+#define SUBDIV_COARSE_FACE_FLAG_OFFSET 28u
#define SUBDIV_COARSE_FACE_FLAG_SMOOTH_MASK \
(SUBDIV_COARSE_FACE_FLAG_SMOOTH << SUBDIV_COARSE_FACE_FLAG_OFFSET)
@@ -597,10 +622,12 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache)
(SUBDIV_COARSE_FACE_FLAG_SELECT << SUBDIV_COARSE_FACE_FLAG_OFFSET)
#define SUBDIV_COARSE_FACE_FLAG_ACTIVE_MASK \
(SUBDIV_COARSE_FACE_FLAG_ACTIVE << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+#define SUBDIV_COARSE_FACE_FLAG_HIDDEN_MASK \
+ (SUBDIV_COARSE_FACE_FLAG_HIDDEN << SUBDIV_COARSE_FACE_FLAG_OFFSET)
#define SUBDIV_COARSE_FACE_LOOP_START_MASK \
~((SUBDIV_COARSE_FACE_FLAG_SMOOTH | SUBDIV_COARSE_FACE_FLAG_SELECT | \
- SUBDIV_COARSE_FACE_FLAG_ACTIVE) \
+ SUBDIV_COARSE_FACE_FLAG_ACTIVE | SUBDIV_COARSE_FACE_FLAG_HIDDEN) \
<< SUBDIV_COARSE_FACE_FLAG_OFFSET)
static uint32_t compute_coarse_face_flag(BMFace *f, BMFace *efa_act)
@@ -617,6 +644,9 @@ static uint32_t compute_coarse_face_flag(BMFace *f, BMFace *efa_act)
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
flag |= SUBDIV_COARSE_FACE_FLAG_SELECT;
}
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_HIDDEN;
+ }
if (f == efa_act) {
flag |= SUBDIV_COARSE_FACE_FLAG_ACTIVE;
}
@@ -647,6 +677,9 @@ static void draw_subdiv_cache_extra_coarse_face_data_mesh(Mesh *mesh, uint32_t *
if ((mesh->mpoly[i].flag & ME_FACE_SEL) != 0) {
flag |= SUBDIV_COARSE_FACE_FLAG_SELECT;
}
+ if ((mesh->mpoly[i].flag & ME_HIDE) != 0) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_HIDDEN;
+ }
flags_data[i] = (uint)(mesh->mpoly[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
}
}
@@ -710,6 +743,23 @@ static DRWSubdivCache *mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache *mbc)
return subdiv_cache;
}
+static void draw_subdiv_invalidate_evaluator_for_orco(Subdiv *subdiv, Mesh *mesh)
+{
+ const bool has_orco = CustomData_has_layer(&mesh->vdata, CD_ORCO);
+ if (has_orco && subdiv->evaluator && !subdiv->evaluator->hasVertexData(subdiv->evaluator)) {
+ /* If we suddenly have/need original coordinates, recreate the evaluator if the extra
+ * source was not created yet. The refiner also has to be recreated as refinement for source
+ * and vertex data is done only once. */
+ openSubdiv_deleteEvaluator(subdiv->evaluator);
+ subdiv->evaluator = nullptr;
+
+ if (subdiv->topology_refiner != nullptr) {
+ openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
+ subdiv->topology_refiner = nullptr;
+ }
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1119,12 +1169,17 @@ struct DRWSubdivUboStorage {
uint coarse_face_select_mask;
uint coarse_face_smooth_mask;
uint coarse_face_active_mask;
+ uint coarse_face_hidden_mask;
uint coarse_face_loopstart_mask;
/* Number of elements to process in the compute shader (can be the coarse quad count, or the
* final vertex count, depending on which compute pass we do). This is used to early out in case
* of out of bond accesses as compute dispatch are of fixed size. */
uint total_dispatch_size;
+
+ int _pad0;
+ int _pad2;
+ int _pad3;
};
static_assert((sizeof(DRWSubdivUboStorage) % 16) == 0,
@@ -1151,6 +1206,7 @@ static void draw_subdiv_init_ubo_storage(const DRWSubdivCache *cache,
ubo->coarse_face_smooth_mask = SUBDIV_COARSE_FACE_FLAG_SMOOTH_MASK;
ubo->coarse_face_select_mask = SUBDIV_COARSE_FACE_FLAG_SELECT_MASK;
ubo->coarse_face_active_mask = SUBDIV_COARSE_FACE_FLAG_ACTIVE_MASK;
+ ubo->coarse_face_hidden_mask = SUBDIV_COARSE_FACE_FLAG_HIDDEN_MASK;
ubo->coarse_face_loopstart_mask = SUBDIV_COARSE_FACE_LOOP_START_MASK;
ubo->total_dispatch_size = total_dispatch_size;
}
@@ -1230,7 +1286,9 @@ static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache,
GPU_compute_dispatch(shader, dispatch_rx, dispatch_ry, 1);
}
-void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor)
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *orco)
{
if (!draw_subdiv_cache_need_polygon_data(cache)) {
/* Happens on meshes with only loose geometry. */
@@ -1245,6 +1303,14 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
get_subdiv_vertex_format());
evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface);
+ GPUVertBuf *src_extra_buffer = nullptr;
+ if (orco) {
+ OpenSubdiv_Buffer src_extra_buffer_interface;
+ src_extra_buffer = create_buffer_and_interface(&src_extra_buffer_interface,
+ get_subdiv_vertex_format());
+ evaluator->wrapSrcVertexDataBuffer(evaluator, &src_extra_buffer_interface);
+ }
+
OpenSubdiv_Buffer patch_arrays_buffer_interface;
GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
get_patch_array_format());
@@ -1260,7 +1326,8 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
get_patch_param_format());
evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
- GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION);
+ GPUShader *shader = get_patch_evaluation_shader(orco ? SHADER_PATCH_EVALUATION_ORCO :
+ SHADER_PATCH_EVALUATION);
GPU_shader_bind(shader);
int binding_point = 0;
@@ -1273,6 +1340,10 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_param_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ if (orco) {
+ GPU_vertbuf_bind_as_ssbo(src_extra_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(orco, binding_point++);
+ }
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
@@ -1289,6 +1360,7 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
GPU_vertbuf_discard(patch_param_buffer);
GPU_vertbuf_discard(patch_arrays_buffer);
GPU_vertbuf_discard(src_buffer);
+ GPU_VERTBUF_DISCARD_SAFE(src_extra_buffer);
}
void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
@@ -1552,12 +1624,11 @@ void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
do_single_material ? SHADER_BUFFER_TRIS : SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS, defines);
GPU_shader_bind(shader);
- if (!do_single_material) {
- /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
- GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
- }
+ int binding_point = 0;
- int binding_point = 1;
+ /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
/* Outputs */
GPU_indexbuf_bind_as_ssbo(subdiv_tris, binding_point++);
@@ -1611,7 +1682,9 @@ void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
get_patch_param_format());
evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
- GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION_FACE_DOTS);
+ GPUShader *shader = get_patch_evaluation_shader(
+ fdots_nor ? SHADER_PATCH_EVALUATION_FACE_DOTS_WITH_NORMALS :
+ SHADER_PATCH_EVALUATION_FACE_DOTS);
GPU_shader_bind(shader);
int binding_point = 0;
@@ -1624,7 +1697,11 @@ void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_param_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(fdots_pos, binding_point++);
- GPU_vertbuf_bind_as_ssbo(fdots_nor, binding_point++);
+ /* F-dots normals may not be requested, still reserve the binding point. */
+ if (fdots_nor) {
+ GPU_vertbuf_bind_as_ssbo(fdots_nor, binding_point);
+ }
+ binding_point++;
GPU_indexbuf_bind_as_ssbo(fdots_indices, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
@@ -1646,11 +1723,13 @@ void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache, GPUIndexBuf *lines_indices)
{
- GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES, nullptr);
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES, "#define SUBDIV_POLYGON_OFFSET\n");
GPU_shader_bind(shader);
int binding_point = 0;
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->edges_orig_index, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
GPU_indexbuf_bind_as_ssbo(lines_indices, binding_point++);
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
@@ -1665,12 +1744,14 @@ void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache, GPUIndexBuf *li
void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
GPUIndexBuf *lines_indices,
+ GPUVertBuf *lines_flags,
uint num_loose_edges)
{
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES_LOOSE, "#define LINES_LOOSE\n");
GPU_shader_bind(shader);
- GPU_indexbuf_bind_as_ssbo(lines_indices, 1);
+ GPU_indexbuf_bind_as_ssbo(lines_indices, 3);
+ GPU_vertbuf_bind_as_ssbo(lines_flags, 4);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, num_loose_edges);
@@ -1905,7 +1986,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
const bool do_final,
const bool do_uvedit,
const ToolSettings *ts,
- const bool /*use_hide*/,
+ const bool use_hide,
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>(
@@ -1935,6 +2016,8 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
return false;
}
+ draw_subdiv_invalidate_evaluator_for_orco(subdiv, mesh_eval);
+
if (!BKE_subdiv_eval_begin_from_mesh(
subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) {
/* This could happen in two situations:
@@ -1981,6 +2064,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
MeshRenderData *mr = mesh_render_data_create(
ob, mesh, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts);
+ mr->use_hide = use_hide;
draw_subdiv_cache_update_extra_coarse_face_data(draw_cache, mesh_eval, mr);
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 84e79cd8be9..b6b0c94f4bf 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -13,6 +13,7 @@
extern "C" {
#endif
+struct CurvesUniformBufPool;
struct DRWShadingGroup;
struct FluidModifierData;
struct GPUMaterial;
@@ -82,7 +83,8 @@ struct DRWShadingGroup *DRW_shgroup_curves_create_sub(struct Object *object,
struct DRWShadingGroup *shgrp,
struct GPUMaterial *gpu_material);
-void DRW_curves_init(void);
+void DRW_curves_init(struct DRWData *drw_data);
+void DRW_curves_ubos_pool_free(struct CurvesUniformBufPool *pool);
void DRW_curves_update(void);
void DRW_curves_free(void);
diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc
index 2edf596ac63..d90c63b680e 100644
--- a/source/blender/draw/intern/draw_curves.cc
+++ b/source/blender/draw/intern/draw_curves.cc
@@ -10,6 +10,7 @@
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
+#include "DNA_curves_types.h"
#include "DNA_customdata_types.h"
#include "GPU_batch.h"
@@ -20,9 +21,13 @@
#include "GPU_texture.h"
#include "GPU_vertex_buffer.h"
+#include "DRW_gpu_wrapper.hh"
#include "DRW_render.h"
+#include "draw_cache_impl.h"
+#include "draw_curves_private.h"
#include "draw_hair_private.h"
+#include "draw_manager.h"
#include "draw_shader.h"
#ifndef __APPLE__
@@ -61,16 +66,43 @@ static GPUVertBuf *g_dummy_vbo = nullptr;
static GPUTexture *g_dummy_texture = nullptr;
static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
+using CurvesInfosBuf = blender::draw::UniformBuffer<CurvesInfos>;
+
+struct CurvesUniformBufPool {
+ blender::Vector<std::unique_ptr<CurvesInfosBuf>> ubos;
+ int used = 0;
+
+ void reset()
+ {
+ used = 0;
+ }
+
+ CurvesInfosBuf &alloc()
+ {
+ if (used >= ubos.size()) {
+ ubos.append(std::make_unique<CurvesInfosBuf>());
+ return *ubos.last().get();
+ }
+ return *ubos[used++].get();
+ }
+};
+
static GPUShader *curves_eval_shader_get(CurvesEvalShader type)
{
return DRW_shader_curves_refine_get(type, drw_curves_shader_type_get());
}
-void DRW_curves_init(void)
+void DRW_curves_init(DRWData *drw_data)
{
/* Initialize legacy hair too, to avoid verbosity in callers. */
DRW_hair_init();
+ if (drw_data->curves_ubos == nullptr) {
+ drw_data->curves_ubos = MEM_new<CurvesUniformBufPool>("CurvesUniformBufPool");
+ }
+ CurvesUniformBufPool *pool = drw_data->curves_ubos;
+ pool->reset();
+
#if defined(USE_TRANSFORM_FEEDBACK) || defined(USE_COMPUTE_SHADERS)
g_tf_pass = DRW_pass_create("Update Curves Pass", (DRWState)0);
#else
@@ -94,63 +126,120 @@ void DRW_curves_init(void)
}
}
+void DRW_curves_ubos_pool_free(CurvesUniformBufPool *pool)
+{
+ MEM_delete(pool);
+}
+
static void drw_curves_cache_shgrp_attach_resources(DRWShadingGroup *shgrp,
CurvesEvalCache *cache,
+ GPUTexture *tex,
const int subdiv)
{
- DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", cache->point_tex);
+ DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", tex);
DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex);
DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex);
DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1);
}
+static void drw_curves_cache_update_compute(CurvesEvalCache *cache,
+ const int subdiv,
+ const int strands_len,
+ GPUVertBuf *buffer,
+ GPUTexture *tex)
+{
+ GPUShader *shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
+ DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass);
+ drw_curves_cache_shgrp_attach_resources(shgrp, cache, tex, subdiv);
+ DRW_shgroup_vertex_buffer(shgrp, "posTime", buffer);
+
+ const int max_strands_per_call = GPU_max_work_group_count(0);
+ int strands_start = 0;
+ while (strands_start < strands_len) {
+ int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call);
+ DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp);
+ DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start);
+ DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1);
+ strands_start += batch_strands_len;
+ }
+}
+
static void drw_curves_cache_update_compute(CurvesEvalCache *cache, const int subdiv)
{
const int strands_len = cache->strands_len;
const int final_points_len = cache->final[subdiv].strands_res * strands_len;
- if (final_points_len > 0) {
- GPUShader *shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
- DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass);
- drw_curves_cache_shgrp_attach_resources(shgrp, cache, subdiv);
- DRW_shgroup_vertex_buffer(shgrp, "posTime", cache->final[subdiv].proc_buf);
-
- const int max_strands_per_call = GPU_max_work_group_count(0);
- int strands_start = 0;
- while (strands_start < strands_len) {
- int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call);
- DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp);
- DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start);
- DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1);
- strands_start += batch_strands_len;
+ if (final_points_len == 0) {
+ return;
+ }
+
+ drw_curves_cache_update_compute(
+ cache, subdiv, strands_len, cache->final[subdiv].proc_buf, cache->point_tex);
+
+ const DRW_Attributes &attrs = cache->final[subdiv].attr_used;
+ for (int i = 0; i < attrs.num_requests; i++) {
+ /* Only refine point attributes. */
+ if (attrs.requests[i].domain == ATTR_DOMAIN_CURVE) {
+ continue;
}
+
+ drw_curves_cache_update_compute(cache,
+ subdiv,
+ strands_len,
+ cache->final[subdiv].attributes_buf[i],
+ cache->proc_attributes_tex[i]);
}
}
-static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, const int subdiv)
+static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache,
+ GPUVertBuf *vbo,
+ GPUTexture *tex,
+ const int subdiv,
+ const int final_points_len)
{
- const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len;
- if (final_points_len > 0) {
- GPUShader *tf_shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
+ GPUShader *tf_shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
#ifdef USE_TRANSFORM_FEEDBACK
- DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
- tf_shader, g_tf_pass, cache->final[subdiv].proc_buf);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(tf_shader, g_tf_pass, vbo);
#else
- DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
-
- CurvesEvalCall *pr_call = MEM_new<CurvesEvalCall>(__func__);
- pr_call->next = g_tf_calls;
- pr_call->vbo = cache->final[subdiv].proc_buf;
- pr_call->shgrp = tf_shgrp;
- pr_call->vert_len = final_points_len;
- g_tf_calls = pr_call;
- DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
+
+ CurvesEvalCall *pr_call = MEM_new<CurvesEvalCall>(__func__);
+ pr_call->next = g_tf_calls;
+ pr_call->vbo = vbo;
+ pr_call->shgrp = tf_shgrp;
+ pr_call->vert_len = final_points_len;
+ g_tf_calls = pr_call;
+ DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
#endif
- drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, subdiv);
- DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len);
+ drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, tex, subdiv);
+ DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len);
+}
+
+static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, const int subdiv)
+{
+ const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len;
+ if (final_points_len == 0) {
+ return;
+ }
+
+ drw_curves_cache_update_transform_feedback(
+ cache, cache->final[subdiv].proc_buf, cache->point_tex, subdiv, final_points_len);
+
+ const DRW_Attributes &attrs = cache->final[subdiv].attr_used;
+ for (int i = 0; i < attrs.num_requests; i++) {
+ /* Only refine point attributes. */
+ if (attrs.requests[i].domain == ATTR_DOMAIN_CURVE) {
+ continue;
+ }
+
+ drw_curves_cache_update_transform_feedback(cache,
+ cache->final[subdiv].attributes_buf[i],
+ cache->proc_attributes_tex[i],
+ subdiv,
+ final_points_len);
}
}
@@ -186,12 +275,34 @@ GPUVertBuf *DRW_curves_pos_buffer_get(Object *object)
return cache->final[subdiv].proc_buf;
}
+static int attribute_index_in_material(GPUMaterial *gpu_material, const char *name)
+{
+ if (!gpu_material) {
+ return -1;
+ }
+
+ int index = 0;
+
+ ListBase gpu_attrs = GPU_material_attributes(gpu_material);
+ LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
+ if (STREQ(gpu_attr->name, name)) {
+ return index;
+ }
+
+ index++;
+ }
+
+ return -1;
+}
+
DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
DRWShadingGroup *shgrp_parent,
GPUMaterial *gpu_material)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
+ CurvesUniformBufPool *pool = DST.vmempool->curves_ubos;
+ CurvesInfosBuf &curves_infos = pool->alloc();
int subdiv = scene->r.hair_subdiv;
int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
@@ -218,6 +329,43 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
if (curves_cache->length_tex) {
DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex);
}
+
+ const DRW_Attributes &attrs = curves_cache->final[subdiv].attr_used;
+ for (int i = 0; i < attrs.num_requests; i++) {
+ const DRW_AttributeRequest &request = attrs.requests[i];
+
+ char sampler_name[32];
+ drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name);
+
+ if (request.domain == ATTR_DOMAIN_CURVE) {
+ if (!curves_cache->proc_attributes_tex[i]) {
+ continue;
+ }
+
+ DRW_shgroup_uniform_texture(shgrp, sampler_name, curves_cache->proc_attributes_tex[i]);
+ }
+ else {
+ if (!curves_cache->final[subdiv].attributes_tex[i]) {
+ continue;
+ }
+ DRW_shgroup_uniform_texture(
+ shgrp, sampler_name, curves_cache->final[subdiv].attributes_tex[i]);
+ }
+
+ /* Some attributes may not be used in the shader anymore and were not garbage collected yet, so
+ * we need to find the right index for this attribute as uniforms defining the scope of the
+ * attributes are based on attribute loading order, which is itself based on the material's
+ * attributes. */
+ const int index = attribute_index_in_material(gpu_material, request.attribute_name);
+ if (index != -1) {
+ curves_infos.is_point_attribute[index] = request.domain == ATTR_DOMAIN_POINT;
+ }
+ }
+
+ curves_infos.push_update();
+
+ DRW_shgroup_uniform_block(shgrp, "drw_curves", curves_infos);
+
DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &curves_cache->final[subdiv].strands_res, 1);
DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape);
diff --git a/source/blender/draw/intern/draw_curves_private.h b/source/blender/draw/intern/draw_curves_private.h
index 76d5f15319d..ed4dd50dfbe 100644
--- a/source/blender/draw/intern/draw_curves_private.h
+++ b/source/blender/draw/intern/draw_curves_private.h
@@ -7,6 +7,11 @@
#pragma once
+#include "BKE_attribute.h"
+#include "GPU_shader.h"
+
+#include "draw_attributes.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -35,6 +40,23 @@ typedef struct CurvesEvalFinalCache {
/* Points per curve, at least 2. */
int strands_res;
+
+ /* Attributes currently being or about to be drawn. */
+ DRW_Attributes attr_used;
+
+ /* Attributes which were used at some point. This is used for garbage collection, to remove
+ * attributes which are not used in shaders anymore due to user edits. */
+ DRW_Attributes attr_used_over_time;
+
+ /* Last time, in seconds, the `attr_used` and `attr_used_over_time` were exactly the same.
+ * If the delta between this time and the current scene time is greater than the timeout set in
+ * user preferences (`U.vbotimeout`) then garbage collection is performed. */
+ int last_attr_matching_time;
+
+ /* Output of the subdivision stage: vertex buffers sized to subdiv level. This is only attributes
+ * on point domain. */
+ GPUVertBuf *attributes_buf[GPU_MAX_ATTR];
+ GPUTexture *attributes_tex[GPU_MAX_ATTR];
} CurvesEvalFinalCache;
/* Curves procedural display: Evaluation is done on the GPU. */
@@ -56,6 +78,11 @@ typedef struct CurvesEvalCache {
CurvesEvalFinalCache final[MAX_HAIR_SUBDIV];
+ /* For point attributes, which need subdivision, these are the input data.
+ * For spline attributes, which need not subdivision, these are the final data. */
+ GPUVertBuf *proc_attributes_buf[GPU_MAX_ATTR];
+ GPUTexture *proc_attributes_tex[GPU_MAX_ATTR];
+
int strands_len;
int elems_len;
int point_len;
@@ -70,6 +97,8 @@ bool curves_ensure_procedural_data(struct Object *object,
int subdiv,
int thickness_res);
+void drw_curves_get_attribute_sampler_name(const char *layer_name, char r_sampler_name[32]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/intern/draw_fluid.c b/source/blender/draw/intern/draw_fluid.c
index d3d4bbf505e..c34025ebe52 100644
--- a/source/blender/draw/intern/draw_fluid.c
+++ b/source/blender/draw/intern/draw_fluid.c
@@ -20,6 +20,8 @@
#include "BKE_colorband.h"
+#include "IMB_colormanagement.h"
+
#include "GPU_texture.h"
#include "draw_manager.h"
@@ -52,7 +54,7 @@ static void create_flame_spectrum_texture(float *data)
float *spec_pixels = (float *)MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float),
"spec_pixels");
- blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
+ IMB_colormanagement_blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index b3c4e21639d..1372b843442 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -479,6 +479,7 @@ void DRW_viewport_data_free(DRWData *drw_data)
MEM_freeN(drw_data->obinfos_ubo);
}
DRW_volume_ubos_pool_free(drw_data->volume_grids_ubos);
+ DRW_curves_ubos_pool_free(drw_data->curves_ubos);
MEM_freeN(drw_data);
}
@@ -1650,7 +1651,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
DRW_globals_update();
drw_debug_init();
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2022,7 +2023,7 @@ void DRW_render_object_iter(
void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph))
{
const DRWContextState *draw_ctx = DRW_context_state_get();
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2079,7 +2080,7 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
drw_manager_init(&DST, NULL, NULL);
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2114,7 +2115,7 @@ void DRW_cache_restart(void)
DST.buffer_finish_called = false;
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
}
@@ -2433,7 +2434,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
/* Init engines */
drw_engines_init();
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2607,7 +2608,7 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
/* Init engines */
drw_engines_init();
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index aa0c472be04..6d384c599d8 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -538,6 +538,8 @@ typedef struct DRWData {
struct DRWTexturePool *texture_pool;
/** Per stereo view data. Contains engine data and default framebuffers. */
struct DRWViewData *view_data[2];
+ /** Per draw-call curves object data. */
+ struct CurvesUniformBufPool *curves_ubos;
} DRWData;
/* ------------- DRAW MANAGER ------------ */
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
index db128fffde7..94c0c53dab7 100644
--- a/source/blender/draw/intern/draw_shader_shared.h
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -1,12 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef GPU_SHADER
+# include "GPU_shader.h"
# include "GPU_shader_shared_utils.h"
typedef struct ViewInfos ViewInfos;
typedef struct ObjectMatrices ObjectMatrices;
typedef struct ObjectInfos ObjectInfos;
typedef struct VolumeInfos VolumeInfos;
+typedef struct CurvesInfos CurvesInfos;
#endif
#define DRW_SHADER_SHARED_H
@@ -16,6 +18,10 @@ typedef struct VolumeInfos VolumeInfos;
/* Define the maximum number of grid we allow in a volume UBO. */
#define DRW_GRID_PER_VOLUME_MAX 16
+/* Define the maximum number of attribute we allow in a curves UBO.
+ * This should be kept in sync with `GPU_ATTR_MAX` */
+#define DRW_ATTRIBUTE_PER_CURVES_MAX 15
+
struct ViewInfos {
/* View matrices */
float4x4 persmat;
@@ -79,6 +85,14 @@ struct VolumeInfos {
};
BLI_STATIC_ASSERT_ALIGN(VolumeInfos, 16)
+struct CurvesInfos {
+ /* Per attribute scope, follows loading order.
+ * NOTE: uint as bool in GLSL is 4 bytes. */
+ uint is_point_attribute[DRW_ATTRIBUTE_PER_CURVES_MAX];
+ int _pad;
+};
+BLI_STATIC_ASSERT_ALIGN(CurvesInfos, 16)
+
#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
#define ObjectInfo (drw_infos[resource_id].drw_Infos)
#define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
index 2d24d07e037..15c770a51c4 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -235,7 +235,9 @@ void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache,
GPUVertBuf *src_custom_normals,
GPUVertBuf *pos_nor);
-void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, struct GPUVertBuf *pos_nor);
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *orco);
void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
struct GPUVertBuf *src_data,
@@ -263,6 +265,7 @@ void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache,
void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
struct GPUIndexBuf *lines_indices,
+ GPUVertBuf *lines_flags,
uint num_loose_edges);
void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
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 ce3ca428469..3cecaf81b8a 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
@@ -160,7 +160,7 @@ static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
}
static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *UNUSED(mr),
+ const MeshRenderData *mr,
void *buffer,
void *UNUSED(data))
{
@@ -169,8 +169,31 @@ static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
return;
}
+ /* Update flags for loose edges, points are already handled. */
+ static GPUVertFormat format;
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+
+ GPUVertBuf *flags = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(flags, &format);
+
+ Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(subdiv_cache);
+ GPU_vertbuf_data_alloc(flags, loose_edges.size());
+
+ uint *flags_data = static_cast<uint *>(GPU_vertbuf_get_data(flags));
+
+ const MEdge *medge = mr->medge;
+
+ for (DRWSubdivLooseEdge edge : loose_edges) {
+ *flags_data++ = (medge[edge.coarse_edge_index].flag & ME_HIDE) != 0;
+ }
+
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
- draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom.edge_len));
+ draw_subdiv_build_lines_loose_buffer(
+ subdiv_cache, ibo, flags, static_cast<uint>(loose_geom.edge_len));
+
+ GPU_vertbuf_discard(flags);
}
constexpr MeshExtract create_extractor_lines()
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
index 272963f3fd5..503ce0e79e9 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
@@ -156,7 +156,8 @@ static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
static void extract_points_iter_subdiv_common(GPUIndexBufBuilder *elb,
const MeshRenderData *mr,
const DRWSubdivCache *subdiv_cache,
- uint subdiv_quad_index)
+ uint subdiv_quad_index,
+ bool for_bmesh)
{
int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
uint start_loop_idx = subdiv_quad_index * 4;
@@ -172,6 +173,21 @@ static void extract_points_iter_subdiv_common(GPUIndexBufBuilder *elb,
continue;
}
+ if (for_bmesh) {
+ const BMVert *mv = BM_vert_at_index(mr->bm, coarse_vertex_index);
+ if (BM_elem_flag_test(mv, BM_ELEM_HIDDEN)) {
+ GPU_indexbuf_set_point_restart(elb, coarse_vertex_index);
+ continue;
+ }
+ }
+ else {
+ const MVert *mv = &mr->mvert[coarse_vertex_index];
+ if (mr->use_hide && (mv->flag & ME_HIDE)) {
+ GPU_indexbuf_set_point_restart(elb, coarse_vertex_index);
+ continue;
+ }
+ }
+
GPU_indexbuf_set_point_vert(elb, coarse_vertex_index, i);
}
}
@@ -183,7 +199,7 @@ static void extract_points_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
const BMFace *UNUSED(coarse_quad))
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
- extract_points_iter_subdiv_common(elb, mr, subdiv_cache, subdiv_quad_index);
+ extract_points_iter_subdiv_common(elb, mr, subdiv_cache, subdiv_quad_index, true);
}
static void extract_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
@@ -193,7 +209,7 @@ static void extract_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
const MPoly *UNUSED(coarse_quad))
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
- extract_points_iter_subdiv_common(elb, mr, subdiv_cache, subdiv_quad_index);
+ extract_points_iter_subdiv_common(elb, mr, subdiv_cache, subdiv_quad_index, false);
}
static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
index d275b672366..d595abc6dd3 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -14,6 +14,7 @@
#include "BKE_attribute.h"
+#include "draw_attributes.h"
#include "draw_subdivision.h"
#include "extract_mesh.h"
@@ -284,7 +285,7 @@ static void extract_attr_init(const MeshRenderData *mr,
void *UNUSED(tls_data),
int index)
{
- const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_Attributes *attrs_used = &cache->attr_used;
const DRW_AttributeRequest &request = attrs_used->requests[index];
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
@@ -337,7 +338,7 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
void *UNUSED(tls_data),
int index)
{
- const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_Attributes *attrs_used = &cache->attr_used;
const DRW_AttributeRequest &request = attrs_used->requests[index];
Mesh *coarse_mesh = subdiv_cache->mesh;
@@ -346,7 +347,7 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
/* Prepare VBO for coarse data. The compute shader only expects floats. */
GPUVertBuf *src_data = GPU_vertbuf_calloc();
- static GPUVertFormat coarse_format = {0};
+ GPUVertFormat coarse_format = {0};
GPU_vertformat_attr_add(&coarse_format, "data", GPU_COMP_F32, dimensions, GPU_FETCH_FLOAT);
GPU_vertbuf_init_with_format_ex(src_data, &coarse_format, GPU_USAGE_STATIC);
GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop));
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
index 14f61dcd739..fb4b95885fc 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
@@ -236,7 +236,7 @@ static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdi
draw_subdiv_get_pos_nor_format(),
subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
- draw_subdiv_extract_pos_nor(subdiv_cache, pos_nor);
+ draw_subdiv_extract_pos_nor(subdiv_cache, pos_nor, nullptr);
}
/* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
index c2b4d389b7c..1671a1cd1e7 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
@@ -110,8 +110,11 @@ static void extract_fdots_init_subdiv(const DRWSubdivCache *subdiv_cache,
GPUVertBuf *fdots_nor_vbo = cache->final.buff.vbo.fdots_nor;
GPUIndexBuf *fdots_pos_ibo = cache->final.buff.ibo.fdots;
- GPU_vertbuf_init_build_on_device(
- fdots_nor_vbo, get_fdots_nor_format_subdiv(), subdiv_cache->num_coarse_poly);
+ /* The normals may not be requested. */
+ if (fdots_nor_vbo) {
+ GPU_vertbuf_init_build_on_device(
+ fdots_nor_vbo, get_fdots_nor_format_subdiv(), subdiv_cache->num_coarse_poly);
+ }
GPU_vertbuf_init_build_on_device(
fdots_pos_vbo, get_fdots_pos_format(), subdiv_cache->num_coarse_poly);
GPU_indexbuf_init_build_on_device(fdots_pos_ibo, subdiv_cache->num_coarse_poly);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
index b45a73a27c0..94674a54f12 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
@@ -7,8 +7,6 @@
#include "extract_mesh.h"
-#include "draw_subdivision.h"
-
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -79,77 +77,12 @@ static void extract_orco_iter_poly_mesh(const MeshRenderData *mr,
}
}
-static void extract_orco_init_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buffer,
- void *UNUSED(data))
-{
- static GPUVertFormat format = {0};
- if (format.attr_len == 0) {
- /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
- * attributes. This is a substantial waste of video-ram and should be done another way.
- * Unfortunately, at the time of writing, I did not found any other "non disruptive"
- * alternative. */
- GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
- GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops);
-
- GPUVertBuf *coarse_vbo = GPU_vertbuf_calloc();
- /* Dynamic as we upload and interpolate layers one at a time. */
- GPU_vertbuf_init_with_format_ex(coarse_vbo, &format, GPU_USAGE_DYNAMIC);
- GPU_vertbuf_data_alloc(coarse_vbo, mr->loop_len);
-
- float(*coarse_vbo_data)[4] = static_cast<float(*)[4]>(GPU_vertbuf_get_data(coarse_vbo));
-
- CustomData *cd_vdata = &mr->me->vdata;
- const float(*orco)[3] = static_cast<const float(*)[3]>(CustomData_get_layer(cd_vdata, CD_ORCO));
-
- if (mr->extract_type == MR_EXTRACT_MESH) {
- const MLoop *mloop = mr->mloop;
- const MPoly *mp = mr->mpoly;
-
- int ml_index = 0;
- for (int i = 0; i < mr->poly_len; i++, mp++) {
- const MLoop *ml = &mloop[mp->loopstart];
-
- for (int j = 0; j < mp->totloop; j++, ml++, ml_index++) {
- float *loop_orco = coarse_vbo_data[ml_index];
- copy_v3_v3(loop_orco, orco[ml->v]);
- loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
- }
- }
- }
- else {
- BMIter iter;
- BMFace *f;
- BM_ITER_MESH (f, &iter, mr->bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter;
- BMLoop *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- const int l_index = BM_elem_index_get(l_iter);
- float *loop_orco = coarse_vbo_data[l_index];
- copy_v3_v3(loop_orco, orco[BM_elem_index_get(l_iter->v)]);
- loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
- } while ((l_iter = l_iter->next) != l_first);
- }
- }
-
- draw_subdiv_interp_custom_data(subdiv_cache, coarse_vbo, dst_buffer, 4, 0, false);
-
- GPU_vertbuf_discard(coarse_vbo);
-}
-
constexpr MeshExtract create_extractor_orco()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_orco_init;
extractor.iter_poly_bm = extract_orco_iter_poly_bm;
extractor.iter_poly_mesh = extract_orco_iter_poly_mesh;
- extractor.init_subdiv = extract_orco_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_Orco_Data);
extractor.use_threading = true;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
index c8c91d45542..f80b33e28f2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
@@ -201,7 +201,7 @@ static GPUVertFormat *get_custom_normals_format()
static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ struct MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -216,7 +216,21 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
return;
}
- draw_subdiv_extract_pos_nor(subdiv_cache, vbo);
+ GPUVertBuf *orco_vbo = cache->final.buff.vbo.orco;
+
+ if (orco_vbo) {
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
+ * attributes. This is a substantial waste of video-ram and should be done another way.
+ * Unfortunately, at the time of writing, I did not found any other "non disruptive"
+ * alternative. */
+ GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ GPU_vertbuf_init_build_on_device(orco_vbo, &format, subdiv_cache->num_subdiv_loops);
+ }
+
+ draw_subdiv_extract_pos_nor(subdiv_cache, vbo, orco_vbo);
if (subdiv_cache->use_custom_loop_normals) {
Mesh *coarse_mesh = subdiv_cache->mesh;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
index e5dd025787d..fa5bf35198b 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
@@ -271,8 +271,6 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
- gpuMeshVcol *vcol = mesh_vcol;
-
/* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in
* a single buffer. */
int pack_layer_index = 0;
@@ -287,10 +285,10 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
if (layer_i == -1) {
printf("%s: missing color layer %s\n", __func__, ref.layer->name);
- vcol += coarse_mesh->totloop;
continue;
}
+ gpuMeshVcol *vcol = mesh_vcol;
MLoopCol *mcol = nullptr;
MPropCol *pcol = nullptr;
diff --git a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
index e58cfaae40d..123c493b572 100644
--- a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
@@ -393,7 +393,7 @@ vec4 gpencil_vertex(ivec4 ma,
col2,
fcol1,
viewport_size,
- 0,
+ 0u,
vec2(1.0, 0.0),
out_P,
out_N,
diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl
index 1ac26c91b93..51f3c890df8 100644
--- a/source/blender/draw/intern/shaders/common_math_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_lib.glsl
@@ -110,6 +110,7 @@ float len_squared(vec3 a) { return dot(a, a); }
float len_squared(vec2 a) { return dot(a, a); }
bool flag_test(uint flag, uint val) { return (flag & val) != 0u; }
+bool flag_test(int flag, uint val) { return flag_test(uint(flag), val); }
bool flag_test(int flag, int val) { return (flag & val) != 0; }
void set_flag_from_test(inout uint value, bool test, uint flag) { if (test) { value |= flag; } else { value &= ~flag; } }
diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
index 3cbb9f980f3..3244b7960d8 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
@@ -1,22 +1,42 @@
/* To be compiled with common_subdiv_lib.glsl */
-layout(std430, binding = 0) readonly buffer inputEdgeOrigIndex
+layout(std430, binding = 1) readonly buffer inputEdgeOrigIndex
{
int input_origindex[];
};
-layout(std430, binding = 1) writeonly buffer outputLinesIndices
+layout(std430, binding = 2) readonly restrict buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+
+layout(std430, binding = 3) writeonly buffer outputLinesIndices
{
uint output_lines[];
};
+layout(std430, binding = 4) readonly buffer LinesLooseFlags
+{
+ uint lines_loose_flags[];
+};
+
#ifndef LINES_LOOSE
-void emit_line(uint line_offset, uint start_loop_index, uint corner_index)
+
+bool is_face_hidden(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_hidden_mask) != 0;
+}
+
+void emit_line(uint line_offset, uint quad_index, uint start_loop_index, uint corner_index)
{
uint vertex_index = start_loop_index + corner_index;
- if (input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display) {
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+
+ if (is_face_hidden(coarse_quad_index) ||
+ (input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display)) {
output_lines[line_offset + 0] = 0xffffffff;
output_lines[line_offset + 1] = 0xffffffff;
}
@@ -41,8 +61,17 @@ void main()
/* In the loose lines case, we execute for each line, with two vertices per line. */
uint line_offset = edge_loose_offset + index * 2;
uint loop_index = num_subdiv_loops + index * 2;
- output_lines[line_offset] = loop_index;
- output_lines[line_offset + 1] = loop_index + 1;
+
+ if (lines_loose_flags[index] != 0) {
+ /* Line is hidden. */
+ output_lines[line_offset] = 0xffffffff;
+ output_lines[line_offset + 1] = 0xffffffff;
+ }
+ else {
+ output_lines[line_offset] = loop_index;
+ output_lines[line_offset + 1] = loop_index + 1;
+ }
+
#else
/* We execute for each quad, so the start index of the loop is quad_index * 4. */
uint start_loop_index = index * 4;
@@ -51,7 +80,7 @@ void main()
uint start_line_index = index * 8;
for (int i = 0; i < 4; i++) {
- emit_line(start_line_index + i * 2, start_loop_index, i);
+ emit_line(start_line_index + i * 2, index, start_loop_index, i);
}
#endif
}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
index 3dccc82541e..ce3c8478d3f 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
@@ -3,18 +3,28 @@
/* Generate triangles from subdivision quads indices. */
-layout(std430, binding = 1) writeonly buffer outputTriangles
+layout(std430, binding = 1) readonly restrict buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+
+layout(std430, binding = 2) writeonly buffer outputTriangles
{
uint output_tris[];
};
#ifndef SINGLE_MATERIAL
-layout(std430, binding = 2) readonly buffer inputPolygonMatOffset
+layout(std430, binding = 3) readonly buffer inputPolygonMatOffset
{
int polygon_mat_offset[];
};
#endif
+bool is_face_hidden(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_hidden_mask) != 0;
+}
+
void main()
{
uint quad_index = get_global_invocation_index();
@@ -24,20 +34,31 @@ void main()
uint loop_index = quad_index * 4;
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+
#ifdef SINGLE_MATERIAL
uint triangle_loop_index = quad_index * 6;
#else
- uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
- coarse_poly_count);
int mat_offset = polygon_mat_offset[coarse_quad_index];
int triangle_loop_index = (int(quad_index) + mat_offset) * 6;
#endif
- output_tris[triangle_loop_index + 0] = loop_index + 0;
- output_tris[triangle_loop_index + 1] = loop_index + 1;
- output_tris[triangle_loop_index + 2] = loop_index + 2;
- output_tris[triangle_loop_index + 3] = loop_index + 0;
- output_tris[triangle_loop_index + 4] = loop_index + 2;
- output_tris[triangle_loop_index + 5] = loop_index + 3;
+ if (is_face_hidden(coarse_quad_index)) {
+ output_tris[triangle_loop_index + 0] = 0xffffffff;
+ output_tris[triangle_loop_index + 1] = 0xffffffff;
+ output_tris[triangle_loop_index + 2] = 0xffffffff;
+ output_tris[triangle_loop_index + 3] = 0xffffffff;
+ output_tris[triangle_loop_index + 4] = 0xffffffff;
+ output_tris[triangle_loop_index + 5] = 0xffffffff;
+ }
+ else {
+ output_tris[triangle_loop_index + 0] = loop_index + 0;
+ output_tris[triangle_loop_index + 1] = loop_index + 1;
+ output_tris[triangle_loop_index + 2] = loop_index + 2;
+ output_tris[triangle_loop_index + 3] = loop_index + 0;
+ output_tris[triangle_loop_index + 4] = loop_index + 2;
+ output_tris[triangle_loop_index + 5] = loop_index + 3;
+ }
}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
index ce324249446..55e4ac20271 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
@@ -31,6 +31,7 @@ layout(std140) uniform shader_data
uint coarse_face_select_mask;
uint coarse_face_smooth_mask;
uint coarse_face_active_mask;
+ uint coarse_face_hidden_mask;
uint coarse_face_loopstart_mask;
/* Total number of elements to process. */
diff --git a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
index 65cf4ebb90f..0ffb216fc6f 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
@@ -70,10 +70,12 @@ layout(std430, binding = 8) writeonly buffer outputVertices
FDotVert output_verts[];
};
+# ifdef FDOTS_NORMALS
layout(std430, binding = 9) writeonly buffer outputNormals
{
FDotNor output_nors[];
};
+# endif
layout(std430, binding = 10) writeonly buffer outputFdotsIndices
{
@@ -89,6 +91,16 @@ layout(std430, binding = 8) writeonly buffer outputVertexData
{
PosNorLoop output_verts[];
};
+# if defined(ORCO_EVALUATION)
+layout(std430, binding = 9) buffer src_extra_buffer
+{
+ float srcExtraVertexBuffer[];
+};
+layout(std430, binding = 10) writeonly buffer outputOrcoData
+{
+ vec4 output_orcos[];
+};
+# endif
#endif
vec2 read_vec2(int index)
@@ -108,6 +120,17 @@ vec3 read_vec3(int index)
return result;
}
+#if defined(ORCO_EVALUATION)
+vec3 read_vec3_extra(int index)
+{
+ vec3 result;
+ result.x = srcExtraVertexBuffer[index * 3];
+ result.y = srcExtraVertexBuffer[index * 3 + 1];
+ result.z = srcExtraVertexBuffer[index * 3 + 2];
+ return result;
+}
+#endif
+
OsdPatchArray GetPatchArray(int arrayIndex)
{
return patchArrayBuffer[arrayIndex];
@@ -290,6 +313,31 @@ void evaluate_patches_limits(
dv += src_vertex * wDv[cv];
}
}
+
+# if defined(ORCO_EVALUATION)
+/* Evaluate the patches limits from the extra source vertex buffer. */
+void evaluate_patches_limits_extra(int patch_index, float u, float v, inout vec3 dst)
+{
+ OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
+ OsdPatchArray array = GetPatchArray(coord.arrayIndex);
+ OsdPatchParam param = GetPatchParam(coord.patchIndex);
+
+ int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
+
+ float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
+ int nPoints = OsdEvaluatePatchBasis(
+ patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
+
+ int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
+
+ for (int cv = 0; cv < nPoints; ++cv) {
+ int index = patchIndexBuffer[indexBase + cv];
+ vec3 src_vertex = read_vec3_extra(index);
+
+ dst += src_vertex * wP[cv];
+ }
+}
+# endif
#endif
/* ------------------------------------------------------------------------------
@@ -341,6 +389,11 @@ float get_face_flag(uint coarse_quad_index)
return 0.0;
}
+bool is_face_hidden(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_hidden_mask) != 0;
+}
+
void main()
{
/* We execute for each coarse quad. */
@@ -370,8 +423,16 @@ void main()
fnor.flag = get_face_flag(coarse_quad_index);
output_verts[coarse_quad_index] = vert;
+# ifdef FDOTS_NORMALS
output_nors[coarse_quad_index] = fnor;
- output_indices[coarse_quad_index] = coarse_quad_index;
+# endif
+
+ if (is_face_hidden(coarse_quad_index)) {
+ output_indices[coarse_quad_index] = 0xffffffff;
+ }
+ else {
+ output_indices[coarse_quad_index] = coarse_quad_index;
+ }
}
#else
void main()
@@ -407,6 +468,16 @@ void main()
set_vertex_pos(vertex_data, pos);
set_vertex_nor(vertex_data, nor, flag);
output_verts[loop_index] = vertex_data;
+
+# if defined(ORCO_EVALUATION)
+ pos = vec3(0.0);
+ evaluate_patches_limits_extra(patch_co.patch_index, uv.x, uv.y, pos);
+
+ /* Set w = 0.0 to indicate that this is not a generic attribute.
+ * See comments in `extract_mesh_vbo_orco.cc`. */
+ vec4 orco_data = vec4(pos, 0.0);
+ output_orcos[loop_index] = orco_data;
+# endif
}
}
#endif
diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
index c74a043ec97..8fd55ea351f 100644
--- a/source/blender/draw/intern/shaders/draw_object_infos_info.hh
+++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
@@ -10,3 +10,7 @@ GPU_SHADER_CREATE_INFO(draw_object_infos)
GPU_SHADER_CREATE_INFO(draw_volume_infos)
.typedef_source("draw_shader_shared.h")
.uniform_buf(2, "VolumeInfos", "drw_volume", Frequency::BATCH);
+
+GPU_SHADER_CREATE_INFO(draw_curves_infos)
+ .typedef_source("draw_shader_shared.h")
+ .uniform_buf(2, "CurvesInfos", "drw_curves", Frequency::BATCH);
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 1a3ab100768..8519b2061f2 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -543,6 +543,9 @@ void ED_markers_draw(const bContext *C, int flag)
View2D *v2d = UI_view2d_fromcontext(C);
int cfra = CTX_data_scene(C)->r.cfra;
+ const float line_width = GPU_line_width_get();
+ GPU_line_width(1.0f);
+
rctf markers_region_rect;
get_marker_region_rect(v2d, &markers_region_rect);
@@ -575,6 +578,7 @@ void ED_markers_draw(const bContext *C, int flag)
}
}
+ GPU_line_width(line_width);
GPU_matrix_pop();
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 14a3b958ea6..941125b9ad5 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -2051,6 +2051,8 @@ void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot)
/* keyingset to use (idname) */
prop = RNA_def_string(
ot->srna, "type", NULL, MAX_ID_NAME - 2, "Keying Set", "The Keying Set to use");
+ RNA_def_property_string_search_func_runtime(
+ prop, ANIM_keyingset_visit_for_search_no_poll, PROP_STRING_SEARCH_SUGGESTION);
RNA_def_property_flag(prop, PROP_HIDDEN);
ot->prop = prop;
}
@@ -2246,6 +2248,8 @@ void ANIM_OT_keyframe_delete_by_name(wmOperatorType *ot)
/* keyingset to use (idname) */
prop = RNA_def_string(
ot->srna, "type", NULL, MAX_ID_NAME - 2, "Keying Set", "The Keying Set to use");
+ RNA_def_property_string_search_func_runtime(
+ prop, ANIM_keyingset_visit_for_search_no_poll, PROP_STRING_SEARCH_SUGGESTION);
RNA_def_property_flag(prop, PROP_HIDDEN);
ot->prop = prop;
}
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index 6fcdd21bad8..97b81277008 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -708,6 +708,72 @@ KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *tra
return ANIM_builtin_keyingset_get_named(NULL, transformKSName);
}
+static void anim_keyingset_visit_for_search_impl(const bContext *C,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data,
+ const bool use_poll)
+{
+ /* Poll requires context. */
+ if (use_poll && (C == NULL)) {
+ return;
+ }
+
+ Scene *scene = C ? CTX_data_scene(C) : NULL;
+ KeyingSet *ks;
+
+ /* Active Keying Set. */
+ if (!use_poll || (scene && scene->active_keyingset)) {
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = "__ACTIVE__";
+ visit_params.info = "Active Keying Set";
+ visit_fn(visit_user_data, &visit_params);
+ }
+
+ /* User-defined Keying Sets. */
+ if (scene && scene->keyingsets.first) {
+ for (ks = scene->keyingsets.first; ks; ks = ks->next) {
+ if (use_poll && !ANIM_keyingset_context_ok_poll((bContext *)C, ks)) {
+ continue;
+ }
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = ks->idname;
+ visit_params.info = ks->name;
+ visit_fn(visit_user_data, &visit_params);
+ }
+ }
+
+ /* Builtin Keying Sets. */
+ for (ks = builtin_keyingsets.first; ks; ks = ks->next) {
+ if (use_poll && !ANIM_keyingset_context_ok_poll((bContext *)C, ks)) {
+ continue;
+ }
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = ks->idname;
+ visit_params.info = ks->name;
+ visit_fn(visit_user_data, &visit_params);
+ }
+}
+
+void ANIM_keyingset_visit_for_search(const bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ const char *UNUSED(edit_text),
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ anim_keyingset_visit_for_search_impl(C, visit_fn, visit_user_data, false);
+}
+
+void ANIM_keyingset_visit_for_search_no_poll(const bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ const char *UNUSED(edit_text),
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ anim_keyingset_visit_for_search_impl(C, visit_fn, visit_user_data, true);
+}
+
/* Menu of All Keying Sets ----------------------------- */
const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C,
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 9bedfb6ee58..59370b53995 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -777,6 +777,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.curves.sculpt_cut
ops.curves.sculpt_delete
ops.curves.sculpt_grow_shrink
+ ops.curves.sculpt_pinch
ops.curves.sculpt_puff
ops.curves.sculpt_snake_hook
ops.generic.cursor
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 6a730225da9..8c0147612fb 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -351,6 +351,19 @@ int ANIM_scene_get_keyingset_index(struct Scene *scene, struct KeyingSet *ks);
struct KeyingSet *ANIM_get_keyingset_for_autokeying(const struct Scene *scene,
const char *transformKSName);
+void ANIM_keyingset_visit_for_search(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
+void ANIM_keyingset_visit_for_search_no_poll(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
/**
* Dynamically populate an enum of Keying Sets.
*/
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index d69b2a47552..30a98129ee6 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -536,12 +536,12 @@ void ED_mesh_geometry_clear(struct Mesh *mesh);
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, bool calc_edges, bool calc_edges_loose);
-void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name);
-int ED_mesh_uv_texture_add(
+void ED_mesh_uv_ensure(struct Mesh *me, const char *name);
+int ED_mesh_uv_add(
struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
-bool ED_mesh_uv_texture_remove_index(struct Mesh *me, int n);
-bool ED_mesh_uv_texture_remove_active(struct Mesh *me);
-bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name);
+bool ED_mesh_uv_remove_index(struct Mesh *me, int n);
+bool ED_mesh_uv_remove_active(struct Mesh *me);
+bool ED_mesh_uv_remove_named(struct Mesh *me, const char *name);
void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me);
/**
* Without a #bContext, called when UV-editing.
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 28452ba8db9..0078c1087a0 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -234,7 +234,7 @@ struct Base *ED_object_add_duplicate(struct Main *bmain,
void ED_object_parent(struct Object *ob, struct Object *parent, int type, const char *substr);
char *ED_object_ot_drop_named_material_tooltip(struct bContext *C,
- struct PointerRNA *properties,
+ const char *name,
const int mval[2]);
/* bitflags for enter/exit editmode */
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index b35911791b7..8503779f629 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -207,7 +207,7 @@ enum {
UI_BUT_INACTIVE = 1 << 18,
UI_BUT_LAST_ACTIVE = 1 << 19,
UI_BUT_UNDO = 1 << 20,
- UI_BUT_IMMEDIATE = 1 << 21,
+ /* UNUSED = 1 << 21, */
UI_BUT_NO_UTF8 = 1 << 22,
/** For popups, pressing return activates this button, overriding the highlighted button.
@@ -461,7 +461,6 @@ void UI_draw_safe_areas(uint pos,
enum {
UI_SCROLL_PRESSED = 1 << 0,
UI_SCROLL_ARROWS = 1 << 1,
- UI_SCROLL_NO_OUTLINE = 1 << 2,
};
/**
* Function in use for buttons and for view2d sliders.
@@ -1656,15 +1655,16 @@ void UI_but_func_identity_compare_set(uiBut *but, uiButIdentityCompareFunc cmp_f
* \param name: Text to display for the item.
* \param poin: Opaque pointer (for use by the caller).
* \param iconid: The icon, #ICON_NONE for no icon.
- * \param state: The buttons state flag, compatible with #uiBut.flag,
- * typically #UI_BUT_DISABLED / #UI_BUT_INACTIVE.
+ * \param but_flag: Button flags (#uiBut.flag) indicating the state of the item, typically
+ * #UI_BUT_DISABLED, #UI_BUT_INACTIVE or #UI_BUT_HAS_SEP_CHAR.
+ *
* \return false if there is nothing to add.
*/
bool UI_search_item_add(uiSearchItems *items,
const char *name,
void *poin,
int iconid,
- int state,
+ int but_flag,
uint8_t name_prefix_offset);
/**
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 926d1664b5e..d1a92da3853 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -542,7 +542,7 @@ static bool but_copypaste_profile_alive = false;
bool ui_but_is_editing(const uiBut *but)
{
- uiHandleButtonData *data = but->active;
+ const uiHandleButtonData *data = but->active;
return (data && ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING));
}
@@ -660,21 +660,23 @@ static bool ui_but_dragedit_update_mval(uiHandleButtonData *data, int mx)
static bool ui_rna_is_userdef(PointerRNA *ptr, PropertyRNA *prop)
{
/* Not very elegant, but ensures preference changes force re-save. */
- bool tag = false;
- if (prop && !(RNA_property_flag(prop) & PROP_NO_DEG_UPDATE)) {
- StructRNA *base = RNA_struct_base(ptr->type);
- if (base == NULL) {
- base = ptr->type;
- }
- if (ELEM(base,
- &RNA_AddonPreferences,
- &RNA_KeyConfigPreferences,
- &RNA_KeyMapItem,
- &RNA_UserAssetLibrary)) {
- tag = true;
- }
+
+ if (!prop) {
+ return false;
}
- return tag;
+ if (RNA_property_flag(prop) & PROP_NO_DEG_UPDATE) {
+ return false;
+ }
+
+ StructRNA *base = RNA_struct_base(ptr->type);
+ if (base == NULL) {
+ base = ptr->type;
+ }
+ return ELEM(base,
+ &RNA_AddonPreferences,
+ &RNA_KeyConfigPreferences,
+ &RNA_KeyMapItem,
+ &RNA_UserAssetLibrary);
}
bool UI_but_is_userdef(const uiBut *but)
@@ -900,64 +902,66 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
/* typically call ui_apply_but_undo(), ui_apply_but_autokey() */
static void ui_apply_but_undo(uiBut *but)
{
- if (but->flag & UI_BUT_UNDO) {
- const char *str = NULL;
- size_t str_len_clip = SIZE_MAX - 1;
- bool skip_undo = false;
+ if (!(but->flag & UI_BUT_UNDO)) {
+ return;
+ }
- /* define which string to use for undo */
- if (but->type == UI_BTYPE_MENU) {
- str = but->drawstr;
- str_len_clip = ui_but_drawstr_len_without_sep_char(but);
- }
- else if (but->drawstr[0]) {
- str = but->drawstr;
- str_len_clip = ui_but_drawstr_len_without_sep_char(but);
- }
- else {
- str = but->tip;
- str_len_clip = ui_but_tip_len_only_first_line(but);
- }
+ const char *str = NULL;
+ size_t str_len_clip = SIZE_MAX - 1;
+ bool skip_undo = false;
- /* fallback, else we don't get an undo! */
- if (str == NULL || str[0] == '\0' || str_len_clip == 0) {
- str = "Unknown Action";
- str_len_clip = strlen(str);
- }
+ /* define which string to use for undo */
+ if (but->type == UI_BTYPE_MENU) {
+ str = but->drawstr;
+ str_len_clip = ui_but_drawstr_len_without_sep_char(but);
+ }
+ else if (but->drawstr[0]) {
+ str = but->drawstr;
+ str_len_clip = ui_but_drawstr_len_without_sep_char(but);
+ }
+ else {
+ str = but->tip;
+ str_len_clip = ui_but_tip_len_only_first_line(but);
+ }
- /* Optionally override undo when undo system doesn't support storing properties. */
- if (but->rnapoin.owner_id) {
- /* Exception for renaming ID data, we always need undo pushes in this case,
- * because undo systems track data by their ID, see: T67002. */
- /* Exception for active shape-key, since changing this in edit-mode updates
- * the shape key from object mode data. */
- if (ELEM(but->rnaprop, &rna_ID_name, &rna_Object_active_shape_key_index)) {
- /* pass */
- }
- else {
- ID *id = but->rnapoin.owner_id;
- if (!ED_undo_is_legacy_compatible_for_property(but->block->evil_C, id)) {
- skip_undo = true;
- }
- }
- }
+ /* fallback, else we don't get an undo! */
+ if (str == NULL || str[0] == '\0' || str_len_clip == 0) {
+ str = "Unknown Action";
+ str_len_clip = strlen(str);
+ }
- if (skip_undo == false) {
- /* XXX: disable all undo pushes from UI changes from sculpt mode as they cause memfile undo
- * steps to be written which cause lag: T71434. */
- if (BKE_paintmode_get_active_from_context(but->block->evil_C) == PAINT_MODE_SCULPT) {
+ /* Optionally override undo when undo system doesn't support storing properties. */
+ if (but->rnapoin.owner_id) {
+ /* Exception for renaming ID data, we always need undo pushes in this case,
+ * because undo systems track data by their ID, see: T67002. */
+ /* Exception for active shape-key, since changing this in edit-mode updates
+ * the shape key from object mode data. */
+ if (ELEM(but->rnaprop, &rna_ID_name, &rna_Object_active_shape_key_index)) {
+ /* pass */
+ }
+ else {
+ ID *id = but->rnapoin.owner_id;
+ if (!ED_undo_is_legacy_compatible_for_property(but->block->evil_C, id)) {
skip_undo = true;
}
}
+ }
- if (skip_undo) {
- str = "";
+ if (skip_undo == false) {
+ /* XXX: disable all undo pushes from UI changes from sculpt mode as they cause memfile undo
+ * steps to be written which cause lag: T71434. */
+ if (BKE_paintmode_get_active_from_context(but->block->evil_C) == PAINT_MODE_SCULPT) {
+ skip_undo = true;
}
+ }
- /* delayed, after all other funcs run, popups are closed, etc */
- uiAfterFunc *after = ui_afterfunc_new();
- BLI_strncpy(after->undostr, str, min_zz(str_len_clip + 1, sizeof(after->undostr)));
+ if (skip_undo) {
+ str = "";
}
+
+ /* delayed, after all other funcs run, popups are closed, etc */
+ uiAfterFunc *after = ui_afterfunc_new();
+ BLI_strncpy(after->undostr, str, min_zz(str_len_clip + 1, sizeof(after->undostr)));
}
static void ui_apply_but_autokey(bContext *C, uiBut *but)
@@ -967,21 +971,21 @@ static void ui_apply_but_autokey(bContext *C, uiBut *but)
/* try autokey */
ui_but_anim_autokey(C, but, scene, scene->r.cfra);
- /* make a little report about what we've done! */
- if (but->rnaprop) {
- char *buf;
+ if (!but->rnaprop) {
+ return;
+ }
- if (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD) {
- return;
- }
+ if (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD) {
+ return;
+ }
- buf = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex);
- if (buf) {
- BKE_report(CTX_wm_reports(C), RPT_PROPERTY, buf);
- MEM_freeN(buf);
+ /* make a little report about what we've done! */
+ char *buf = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex);
+ if (buf) {
+ BKE_report(CTX_wm_reports(C), RPT_PROPERTY, buf);
+ MEM_freeN(buf);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
- }
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
}
}
@@ -1631,29 +1635,34 @@ static bool ui_drag_toggle_set_xy_xy(
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
/* NOTE: ctrl is always true here because (at least for now)
* we always want to consider text control in this case, even when not embossed. */
- if (ui_but_is_interactive(but, true)) {
- if (BLI_rctf_isect_segment(&but->rect, xy_a_block, xy_b_block)) {
-
- /* execute the button */
- if (ui_drag_toggle_but_is_supported(but)) {
- /* is it pressed? */
- const int pushed_state_but = ui_drag_toggle_but_pushed_state(but);
- if (pushed_state_but != pushed_state) {
- UI_but_execute(C, region, but);
- if (do_check) {
- ui_but_update_edited(but);
- }
- if (U.runtime.is_dirty == false) {
- ui_but_update_preferences_dirty(but);
- }
- changed = true;
- }
- }
- /* done */
- }
+
+ if (!ui_but_is_interactive(but, true)) {
+ continue;
+ }
+ if (!BLI_rctf_isect_segment(&but->rect, xy_a_block, xy_b_block)) {
+ continue;
+ }
+ if (!ui_drag_toggle_but_is_supported(but)) {
+ continue;
}
+ /* is it pressed? */
+ const int pushed_state_but = ui_drag_toggle_but_pushed_state(but);
+ if (pushed_state_but == pushed_state) {
+ continue;
+ }
+
+ /* execute the button */
+ UI_but_execute(C, region, but);
+ if (do_check) {
+ ui_but_update_edited(but);
+ }
+ if (U.runtime.is_dirty == false) {
+ ui_but_update_preferences_dirty(but);
+ }
+ changed = true;
}
}
+
if (changed) {
/* apply now, not on release (or if handlers are canceled for whatever reason) */
ui_apply_but_funcs_after(C);
@@ -4514,7 +4523,8 @@ static int ui_do_but_HOTKEYEVT(bContext *C,
BLI_assert(but->type == UI_BTYPE_HOTKEY_EVENT);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM(event->type, LEFTMOUSE, EVT_PADENTER, EVT_RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, EVT_PADENTER, EVT_RETKEY, EVT_BUT_OPEN) &&
+ (event->val == KM_PRESS)) {
but->drawstr[0] = 0;
hotkey_but->modifier_key = 0;
button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
@@ -4537,13 +4547,9 @@ static int ui_do_but_HOTKEYEVT(bContext *C,
if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
/* only cancel if click outside the button */
if (ui_but_contains_point_px(but, but->active->region, event->xy) == false) {
- /* data->cancel doesn't work, this button opens immediate */
- if (but->flag & UI_BUT_IMMEDIATE) {
- ui_but_value_set(but, 0);
- }
- else {
- data->cancel = true;
- }
+ data->cancel = true;
+ /* Close the containing popup (if any). */
+ data->escapecancel = true;
button_activate_state(C, but, BUTTON_STATE_EXIT);
return WM_UI_HANDLER_BREAK;
}
@@ -6328,7 +6334,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
- IMB_colormanagement_srgb_to_scene_linear_v3(target);
+ IMB_colormanagement_srgb_to_scene_linear_v3(target, target);
}
else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
@@ -6345,7 +6351,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
- IMB_colormanagement_scene_linear_to_srgb_v3(color);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color, color);
BKE_brush_color_set(scene, brush, color);
updated = true;
}
@@ -8552,14 +8558,6 @@ static void button_activate_init(bContext *C,
}
button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT);
- /* activate right away */
- if (but->flag & UI_BUT_IMMEDIATE) {
- if (but->type == UI_BTYPE_HOTKEY_EVENT) {
- button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
- }
- /* .. more to be added here */
- }
-
if (type == BUTTON_ACTIVATE_OPEN) {
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index a79d96caeca..4221959a430 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -1225,24 +1225,24 @@ typedef enum {
/**
* Helper call to draw a menu item without a button.
*
- * \param state: The state of the button,
- * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
+ * \param but_flag: Button flags (#uiBut.flag) indicating the state of the item, typically
+ * #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
* \param separator_type: The kind of separator which controls if and how the string is clipped.
- * \param r_xmax: The right hand position of the text, this takes into the icon,
- * padding and text clipping when there is not enough room to display the full text.
+ * \param r_xmax: The right hand position of the text, this takes into the icon, padding and text
+ * clipping when there is not enough room to display the full text.
*/
void ui_draw_menu_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ int but_flag,
uiMenuItemSeparatorType separator_type,
int *r_xmax);
void ui_draw_preview_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ int but_flag,
eFontStyle_Align text_align);
/**
* Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 19b425d585b..0df62c8f082 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1107,7 +1107,7 @@ static uiBut *ui_item_with_label(uiLayout *layout,
NULL);
UI_but_func_set(but, ui_keymap_but_cb, but, NULL);
if (flag & UI_ITEM_R_IMMEDIATE) {
- UI_but_flag_enable(but, UI_BUT_IMMEDIATE);
+ UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
}
}
else {
@@ -2338,7 +2338,14 @@ void uiItemFullR(uiLayout *layout,
/* property with separate label */
else if (ELEM(type, PROP_ENUM, PROP_STRING, PROP_POINTER)) {
but = ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag);
- but = ui_but_add_search(but, ptr, prop, NULL, NULL, false);
+ bool results_are_suggestions = false;
+ if (type == PROP_STRING) {
+ const eStringPropertySearchFlag search_flag = RNA_property_string_search_flag(prop);
+ if (search_flag & PROP_STRING_SEARCH_SUGGESTION) {
+ results_are_suggestions = true;
+ }
+ }
+ but = ui_but_add_search(but, ptr, prop, NULL, NULL, results_are_suggestions);
if (layout->redalert) {
UI_but_flag_enable(but, UI_BUT_REDALERT);
@@ -2711,11 +2718,16 @@ uiBut *ui_but_add_search(uiBut *but,
PropertyRNA *prop,
PointerRNA *searchptr,
PropertyRNA *searchprop,
- bool results_are_suggestions)
+ const bool results_are_suggestions)
{
/* for ID's we do automatic lookup */
+ bool has_search_fn = false;
+
PointerRNA sptr;
if (!searchprop) {
+ if (RNA_property_type(prop) == PROP_STRING) {
+ has_search_fn = (RNA_property_string_search_flag(prop) != 0);
+ }
if (RNA_property_type(prop) == PROP_POINTER) {
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
search_id_collection(ptype, &sptr, &searchprop);
@@ -2724,14 +2736,18 @@ uiBut *ui_but_add_search(uiBut *but,
}
/* turn button into search button */
- if (searchprop) {
+ if (has_search_fn || searchprop) {
uiRNACollectionSearch *coll_search = MEM_mallocN(sizeof(*coll_search), __func__);
uiButSearch *search_but;
but = ui_but_change_type(but, UI_BTYPE_SEARCH_MENU);
search_but = (uiButSearch *)but;
- search_but->rnasearchpoin = *searchptr;
- search_but->rnasearchprop = searchprop;
+
+ if (searchptr) {
+ search_but->rnasearchpoin = *searchptr;
+ search_but->rnasearchprop = searchprop;
+ }
+
but->hardmax = MAX2(but->hardmax, 256.0f);
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
if (RNA_property_is_unlink(prop)) {
@@ -2740,8 +2756,17 @@ uiBut *ui_but_add_search(uiBut *but,
coll_search->target_ptr = *ptr;
coll_search->target_prop = prop;
- coll_search->search_ptr = *searchptr;
- coll_search->search_prop = searchprop;
+
+ if (searchptr) {
+ coll_search->search_ptr = *searchptr;
+ coll_search->search_prop = searchprop;
+ }
+ else {
+ /* Rely on `has_search_fn`. */
+ coll_search->search_ptr = PointerRNA_NULL;
+ coll_search->search_prop = NULL;
+ }
+
coll_search->search_but = but;
coll_search->butstore_block = but->block;
coll_search->butstore = UI_butstore_create(coll_search->butstore_block);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 5b97a80d513..c066ced21cb 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1895,14 +1895,14 @@ static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
if (!gamma) {
- IMB_colormanagement_scene_linear_to_srgb_v3(color);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color, color);
}
RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
RNA_property_update(C, &but->rnapoin, but->rnaprop);
}
else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
if (gamma) {
- IMB_colormanagement_srgb_to_scene_linear_v3(color);
+ IMB_colormanagement_srgb_to_scene_linear_v3(color, color);
}
RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
RNA_property_update(C, &but->rnapoin, but->rnaprop);
@@ -2142,11 +2142,8 @@ static int ui_drop_material_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- if (!RNA_struct_property_is_set(op->ptr, "session_uuid")) {
- return OPERATOR_CANCELLED;
- }
- const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
- Material *ma = (Material *)BKE_libblock_find_session_uuid(bmain, ID_MA, session_uuid);
+ Material *ma = (Material *)WM_operator_properties_id_lookup_from_name_or_session_uuid(
+ bmain, op->ptr, ID_MA);
if (ma == NULL) {
return OPERATOR_CANCELLED;
}
@@ -2184,16 +2181,7 @@ static void UI_OT_drop_material(wmOperatorType *ot)
ot->exec = ui_drop_material_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- PropertyRNA *prop = RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ WM_operator_properties_id_lookup(ot, false);
}
/** \} */
diff --git a/source/blender/editors/interface/interface_region_color_picker.cc b/source/blender/editors/interface/interface_region_color_picker.cc
index ab0a6039cdc..db1e5e653de 100644
--- a/source/blender/editors/interface/interface_region_color_picker.cc
+++ b/source/blender/editors/interface/interface_region_color_picker.cc
@@ -116,7 +116,7 @@ void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3])
* assuming it is more perceptually linear than the scene linear
* space for intuitive color picking. */
if (!ui_but_is_color_gamma(but)) {
- IMB_colormanagement_scene_linear_to_color_picking_v3(rgb);
+ IMB_colormanagement_scene_linear_to_color_picking_v3(rgb, rgb);
ui_color_picker_rgb_round(rgb);
}
}
@@ -124,7 +124,7 @@ void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3])
void ui_perceptual_to_scene_linear_space(uiBut *but, float rgb[3])
{
if (!ui_but_is_color_gamma(but)) {
- IMB_colormanagement_color_picking_to_scene_linear_v3(rgb);
+ IMB_colormanagement_color_picking_to_scene_linear_v3(rgb, rgb);
ui_color_picker_rgb_round(rgb);
}
}
@@ -208,7 +208,7 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but,
* (coming from other applications, web, etc) */
copy_v3_v3(rgb_hex, rgb_scene_linear);
if (from_but && !ui_but_is_color_gamma(from_but)) {
- IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex);
+ IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex, rgb_hex);
ui_color_picker_rgb_round(rgb_hex);
}
@@ -291,7 +291,7 @@ static void ui_colorpicker_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexc
/* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
if (!ui_but_is_color_gamma(but)) {
- IMB_colormanagement_srgb_to_scene_linear_v3(rgb);
+ IMB_colormanagement_srgb_to_scene_linear_v3(rgb, rgb);
ui_color_picker_rgb_round(rgb);
}
@@ -777,7 +777,7 @@ static void ui_block_colorpicker(uiBlock *block,
copy_v3_v3(rgb_hex, rgba_scene_linear);
if (!ui_but_is_color_gamma(from_but)) {
- IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex);
+ IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex, rgb_hex);
ui_color_picker_rgb_round(rgb_hex);
}
diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index bc497e2647c..64de31dfe6a 100644
--- a/source/blender/editors/interface/interface_region_search.cc
+++ b/source/blender/editors/interface/interface_region_search.cc
@@ -58,7 +58,7 @@ struct uiSearchItems {
char **names;
void **pointers;
int *icons;
- int *states;
+ int *but_flags;
uint8_t *name_prefix_offsets;
/** Is there any item with an icon? */
@@ -94,7 +94,7 @@ bool UI_search_item_add(uiSearchItems *items,
const char *name,
void *poin,
int iconid,
- int state,
+ const int but_flag,
const uint8_t name_prefix_offset)
{
/* hijack for autocomplete */
@@ -148,10 +148,10 @@ bool UI_search_item_add(uiSearchItems *items,
/* Limit flags that can be set so flags such as 'UI_SELECT' aren't accidentally set
* which will cause problems, add others as needed. */
- BLI_assert(
- (state & ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)) == 0);
- if (items->states) {
- items->states[items->totitem] = state;
+ BLI_assert((but_flag &
+ ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)) == 0);
+ if (items->but_flags) {
+ items->but_flags[items->totitem] = but_flag;
}
items->totitem++;
@@ -556,7 +556,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
if (data->preview) {
/* draw items */
for (int a = 0; a < data->items.totitem; a++) {
- const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
+ const int but_flag = ((a == data->active) ? UI_ACTIVE : 0) | data->items.but_flags[a];
/* ensure icon is up-to-date */
ui_icon_ensure_deferred(C, data->items.icons[a], data->preview);
@@ -568,7 +568,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
&rect,
data->items.names[a],
data->items.icons[a],
- state,
+ but_flag,
UI_STYLE_TEXT_LEFT);
}
@@ -590,7 +590,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
const int search_sep_len = data->sep_string ? strlen(data->sep_string) : 0;
/* draw items */
for (int a = 0; a < data->items.totitem; a++) {
- const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
+ const int but_flag = ((a == data->active) ? UI_ACTIVE : 0) | data->items.but_flags[a];
char *name = data->items.names[a];
int icon = data->items.icons[a];
char *name_sep_test = nullptr;
@@ -600,7 +600,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
separator_type = UI_MENU_ITEM_SEPARATOR_SHORTCUT;
}
/* Only set for displaying additional hint (e.g. library name of a linked data-block). */
- else if (state & UI_BUT_HAS_SEP_CHAR) {
+ else if (but_flag & UI_BUT_HAS_SEP_CHAR) {
separator_type = UI_MENU_ITEM_SEPARATOR_HINT;
}
@@ -615,7 +615,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
}
/* Simple menu item. */
- ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, nullptr);
+ ui_draw_menu_item(&data->fstyle, &rect, name, icon, but_flag, separator_type, nullptr);
}
else {
/* Split menu item, faded text before the separator. */
@@ -633,7 +633,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
&rect,
name,
0,
- state | UI_BUT_INACTIVE,
+ but_flag | UI_BUT_INACTIVE,
UI_MENU_ITEM_SEPARATOR_NONE,
&name_width);
*name_sep = name_sep_prev;
@@ -646,7 +646,8 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
}
/* The previous menu item draws the active selection. */
- ui_draw_menu_item(&data->fstyle, &rect, name_sep, icon, state, separator_type, nullptr);
+ ui_draw_menu_item(
+ &data->fstyle, &rect, name_sep, icon, but_flag, separator_type, nullptr);
}
}
/* indicate more */
@@ -677,7 +678,7 @@ static void ui_searchbox_region_free_fn(ARegion *region)
MEM_freeN(data->items.names);
MEM_freeN(data->items.pointers);
MEM_freeN(data->items.icons);
- MEM_freeN(data->items.states);
+ MEM_freeN(data->items.but_flags);
if (data->items.name_prefix_offsets != nullptr) {
MEM_freeN(data->items.name_prefix_offsets);
@@ -847,7 +848,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
data->items.names = (char **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__);
data->items.pointers = (void **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__);
data->items.icons = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__);
- data->items.states = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__);
+ data->items.but_flags = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__);
data->items.name_prefix_offsets = nullptr; /* Lazy initialized as needed. */
for (int i = 0; i < data->items.maxitem; i++) {
data->items.names[i] = (char *)MEM_callocN(data->items.maxstrlen + 1, __func__);
@@ -913,7 +914,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
/* widget itself */
/* NOTE: i18n messages extracting tool does the same, please keep it in sync. */
{
- const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
+ const int but_flag = ((a == data->active) ? UI_ACTIVE : 0) | data->items.but_flags[a];
wmOperatorType *ot = static_cast<wmOperatorType *>(data->items.pointers[a]);
char text_pre[128];
@@ -936,14 +937,14 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
&rect_pre,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre),
data->items.icons[a],
- state,
+ but_flag,
UI_MENU_ITEM_SEPARATOR_NONE,
nullptr);
ui_draw_menu_item(&data->fstyle,
&rect_post,
data->items.names[a],
0,
- state,
+ but_flag,
data->use_shortcut_sep ? UI_MENU_ITEM_SEPARATOR_SHORTCUT :
UI_MENU_ITEM_SEPARATOR_NONE,
nullptr);
diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc
index 384e9d1794e..dc8f568d025 100644
--- a/source/blender/editors/interface/interface_template_attribute_search.cc
+++ b/source/blender/editors/interface/interface_template_attribute_search.cc
@@ -40,8 +40,8 @@ static StringRef attribute_domain_string(const AttributeDomain domain)
static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttributeInfo &item)
{
- const StringRef data_type_name = attribute_data_type_string(item.data_type);
- const StringRef domain_name = attribute_domain_string(item.domain);
+ const StringRef data_type_name = attribute_data_type_string(*item.data_type);
+ const StringRef domain_name = attribute_domain_string(*item.domain);
std::string search_item_text = domain_name + " " + UI_MENU_ARROW_SEP + item.name + UI_SEP_CHAR +
data_type_name;
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 4e6437e043a..a02e8a3ac49 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -742,7 +742,7 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
object_active->id.tag |= LIB_TAG_DOIT;
}
BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override);
+ bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override, false);
}
else if (object_active != NULL && !ID_IS_LINKED(object_active) &&
&object_active->instance_collection->id == id) {
@@ -754,7 +754,8 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
id,
&object_active->id,
&object_active->id,
- &id_override);
+ &id_override,
+ false);
}
break;
case ID_OB:
@@ -765,7 +766,7 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
object_active->id.tag |= LIB_TAG_DOIT;
}
BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override);
+ bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override, false);
}
break;
case ID_ME:
@@ -787,13 +788,20 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
if (object_active != NULL) {
object_active->id.tag |= LIB_TAG_DOIT;
}
- BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override);
+ BKE_lib_override_library_create(bmain,
+ scene,
+ view_layer,
+ NULL,
+ id,
+ &collection_active->id,
+ NULL,
+ &id_override,
+ false);
}
else {
object_active->id.tag |= LIB_TAG_DOIT;
BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, &object_active->id, NULL, &id_override);
+ bmain, scene, view_layer, NULL, id, &object_active->id, NULL, &id_override, false);
}
}
break;
@@ -812,8 +820,11 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
id_override->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
*r_undo_push_label = "Make Library Override Hierarchy";
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- DEG_relations_tag_update(bmain);
+ /* Given `idptr` is re-assigned to owner property by caller to ensure proper updates etc. Here
+ * we also use it to ensure remapping of the owner property from the linked data to the newly
+ * created liboverride (note that in theory this remapping has already been done by code
+ * above). */
+ RNA_id_pointer_create(id_override, idptr);
}
}
diff --git a/source/blender/editors/interface/interface_utils.cc b/source/blender/editors/interface/interface_utils.cc
index 993ccdf92f7..b7ca2d9aa11 100644
--- a/source/blender/editors/interface/interface_utils.cc
+++ b/source/blender/editors/interface/interface_utils.cc
@@ -24,6 +24,7 @@
#include "BLT_translation.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_report.h"
@@ -516,71 +517,136 @@ void ui_rna_collection_search_update_fn(
StringSearch *search = skip_filter ? nullptr : BLI_string_search_new();
- /* build a temporary list of relevant items first */
- int item_index = 0;
- RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) {
+ if (data->search_prop != nullptr) {
+ /* build a temporary list of relevant items first */
+ int item_index = 0;
+ RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) {
- if (flag & PROP_ID_SELF_CHECK) {
- if (itemptr.data == data->target_ptr.owner_id) {
- continue;
+ if (flag & PROP_ID_SELF_CHECK) {
+ if (itemptr.data == data->target_ptr.owner_id) {
+ continue;
+ }
}
- }
- /* use filter */
- if (is_ptr_target) {
- if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0) {
- continue;
+ /* use filter */
+ if (is_ptr_target) {
+ if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0) {
+ continue;
+ }
}
- }
- int name_prefix_offset = 0;
- int iconid = ICON_NONE;
- bool has_sep_char = false;
- const bool is_id = itemptr.type && RNA_struct_is_ID(itemptr.type);
+ int name_prefix_offset = 0;
+ int iconid = ICON_NONE;
+ bool has_sep_char = false;
+ const bool is_id = itemptr.type && RNA_struct_is_ID(itemptr.type);
- if (is_id) {
- iconid = ui_id_icon_get(C, static_cast<ID *>(itemptr.data), false);
- if (!ELEM(iconid, 0, ICON_BLANK1)) {
- has_id_icon = true;
- }
+ if (is_id) {
+ iconid = ui_id_icon_get(C, static_cast<ID *>(itemptr.data), false);
+ if (!ELEM(iconid, 0, ICON_BLANK1)) {
+ has_id_icon = true;
+ }
- if (requires_exact_data_name) {
- name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
+ if (requires_exact_data_name) {
+ name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
+ }
+ else {
+ const ID *id = static_cast<ID *>(itemptr.data);
+ BKE_id_full_name_ui_prefix_get(name_buf, id, true, UI_SEP_CHAR, &name_prefix_offset);
+ BLI_STATIC_ASSERT(sizeof(name_buf) >= MAX_ID_FULL_NAME_UI,
+ "Name string buffer should be big enough to hold full UI ID name");
+ name = name_buf;
+ has_sep_char = ID_IS_LINKED(id);
+ }
}
else {
- const ID *id = static_cast<ID *>(itemptr.data);
- BKE_id_full_name_ui_prefix_get(name_buf, id, true, UI_SEP_CHAR, &name_prefix_offset);
- BLI_STATIC_ASSERT(sizeof(name_buf) >= MAX_ID_FULL_NAME_UI,
- "Name string buffer should be big enough to hold full UI ID name");
- name = name_buf;
- has_sep_char = ID_IS_LINKED(id);
+ name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
}
- }
- else {
- name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
- }
- if (name) {
- CollItemSearch *cis = MEM_cnew<CollItemSearch>(__func__);
- cis->data = itemptr.data;
- cis->name = BLI_strdup(name);
- cis->index = item_index;
- cis->iconid = iconid;
- cis->is_id = is_id;
- cis->name_prefix_offset = name_prefix_offset;
- cis->has_sep_char = has_sep_char;
- if (!skip_filter) {
- BLI_string_search_add(search, name, cis, 0);
+ if (name) {
+ CollItemSearch *cis = MEM_cnew<CollItemSearch>(__func__);
+ cis->data = itemptr.data;
+ cis->name = BLI_strdup(name);
+ cis->index = item_index;
+ cis->iconid = iconid;
+ cis->is_id = is_id;
+ cis->name_prefix_offset = name_prefix_offset;
+ cis->has_sep_char = has_sep_char;
+ if (!skip_filter) {
+ BLI_string_search_add(search, name, cis, 0);
+ }
+ BLI_addtail(items_list, cis);
+ if (name != name_buf) {
+ MEM_freeN(name);
+ }
}
- BLI_addtail(items_list, cis);
- if (name != name_buf) {
- MEM_freeN(name);
+
+ item_index++;
+ }
+ RNA_PROP_END;
+ }
+ else {
+ BLI_assert(RNA_property_type(data->target_prop) == PROP_STRING);
+ const eStringPropertySearchFlag search_flag = RNA_property_string_search_flag(
+ data->target_prop);
+ BLI_assert(search_flag & PROP_STRING_SEARCH_SUPPORTED);
+
+ struct SearchVisitUserData {
+ StringSearch *search;
+ bool skip_filter;
+ int item_index;
+ ListBase *items_list;
+ const char *func_id;
+ } user_data = {nullptr};
+
+ user_data.search = search;
+ user_data.skip_filter = skip_filter;
+ user_data.items_list = items_list;
+ user_data.func_id = __func__;
+
+ RNA_property_string_search(
+ C,
+ &data->target_ptr,
+ data->target_prop,
+ str,
+ [](void *user_data, const StringPropertySearchVisitParams *visit_params) {
+ const bool show_extra_info = (G.debug_value == 102);
+
+ SearchVisitUserData *search_data = (struct SearchVisitUserData *)user_data;
+ CollItemSearch *cis = MEM_cnew<CollItemSearch>(search_data->func_id);
+ cis->data = nullptr;
+ if (visit_params->info && show_extra_info) {
+ cis->name = BLI_sprintfN(
+ "%s" UI_SEP_CHAR_S "%s", visit_params->text, visit_params->info);
+ }
+ else {
+ cis->name = BLI_strdup(visit_params->text);
+ }
+ cis->index = search_data->item_index;
+ cis->iconid = ICON_NONE;
+ cis->is_id = false;
+ cis->name_prefix_offset = 0;
+ cis->has_sep_char = visit_params->info != nullptr;
+ if (!search_data->skip_filter) {
+ BLI_string_search_add(search_data->search, visit_params->text, cis, 0);
+ }
+ BLI_addtail(search_data->items_list, cis);
+ search_data->item_index++;
+ },
+ (void *)&user_data);
+
+ if (search_flag & PROP_STRING_SEARCH_SORT) {
+ BLI_listbase_sort(items_list, [](const void *a_, const void *b_) -> int {
+ const CollItemSearch *cis_a = (const CollItemSearch *)a_;
+ const CollItemSearch *cis_b = (const CollItemSearch *)b_;
+ return BLI_strcasecmp_natural(cis_a->name, cis_b->name);
+ });
+ int i = 0;
+ LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
+ cis->index = i;
+ i++;
}
}
-
- item_index++;
}
- RNA_PROP_END;
if (skip_filter) {
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 1c9cf27fd09..110f8146c7f 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -108,22 +108,22 @@ typedef enum {
UI_WTYPE_GRID_TILE,
} uiWidgetTypeEnum;
-/* Button state argument shares bits with 'uiBut.flag'.
- * reuse flags that aren't needed for drawing to avoid collision. */
-enum {
- /* Show that holding the button opens a menu. */
- UI_STATE_HOLD_ACTION = UI_BUT_UPDATE_DELAY,
- UI_STATE_TEXT_INPUT = UI_BUT_UNDO,
- UI_STATE_ACTIVE_LEFT = UI_BUT_VALUE_CLEAR,
- UI_STATE_ACTIVE_RIGHT = UI_BUT_TEXTEDIT_UPDATE,
- UI_STATE_TEXT_BEFORE_WIDGET = UI_BUT_IMMEDIATE,
-
- UI_STATE_FLAGS_ALL = (UI_STATE_HOLD_ACTION | UI_STATE_TEXT_INPUT | UI_STATE_ACTIVE_LEFT |
- UI_STATE_ACTIVE_RIGHT | UI_STATE_TEXT_BEFORE_WIDGET),
-};
-/* Prevent accidental use. */
-#define UI_BUT_UPDATE_DELAY ((void)0)
-#define UI_BUT_UNDO ((void)0)
+/**
+ * The button's state information adapted for drawing. Use #STATE_INFO_NULL for empty state.
+ */
+typedef struct {
+ /** Copy of #uiBut.flag (possibly with overrides for drawing). */
+ int but_flag;
+ /** Copy of #uiBut.drawflag (possibly with overrides for drawing). */
+ int but_drawflag;
+
+ /** Show that holding the button opens a menu. */
+ bool has_hold_action : 1;
+ /** The button is in text input mode. */
+ bool is_text_input : 1;
+} uiWidgetStateInfo;
+
+static const uiWidgetStateInfo STATE_INFO_NULL = {0};
/** \} */
@@ -257,10 +257,21 @@ typedef struct uiWidgetType {
/* converted colors for state */
uiWidgetColors wcol;
- void (*state)(struct uiWidgetType *, int state, int drawflag, eUIEmbossType emboss);
- void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign, const float zoom);
- void (*custom)(
- uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign, const float zoom);
+ void (*state)(struct uiWidgetType *, const uiWidgetStateInfo *state, eUIEmbossType emboss)
+ ATTR_NONNULL();
+ void (*draw)(uiWidgetColors *,
+ rcti *,
+ const uiWidgetStateInfo *,
+ int roundboxalign,
+ const float zoom) ATTR_NONNULL();
+ void (*custom)(uiBut *,
+ uiWidgetColors *,
+ rcti *,
+ const uiWidgetStateInfo *,
+ int roundboxalign,
+ const float zoom) ATTR_NONNULL();
+ void (*draw_block)(
+ uiWidgetColors *, rcti *, int block_flag, int roundboxalign, const float zoom);
void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *);
} uiWidgetType;
@@ -1290,16 +1301,16 @@ static void widgetbase_draw(uiWidgetBase *wtb, const uiWidgetColors *wcol)
#define PREVIEW_PAD 4
-static float widget_alpha_factor(const int state)
+static float widget_alpha_factor(const uiWidgetStateInfo *state)
{
- if (state & (UI_BUT_INACTIVE | UI_BUT_DISABLED)) {
- if (state & UI_SEARCH_FILTER_NO_MATCH) {
+ if (state->but_flag & (UI_BUT_INACTIVE | UI_BUT_DISABLED)) {
+ if (state->but_flag & UI_SEARCH_FILTER_NO_MATCH) {
return 0.25f;
}
return 0.5f;
}
- if (state & UI_SEARCH_FILTER_NO_MATCH) {
+ if (state->but_flag & UI_SEARCH_FILTER_NO_MATCH) {
return 0.5f;
}
@@ -1368,7 +1379,10 @@ static void widget_draw_icon(
}
}
else if (ELEM(but->type, UI_BTYPE_BUT, UI_BTYPE_DECORATOR)) {
- alpha *= widget_alpha_factor(but->flag);
+ uiWidgetStateInfo state = {0};
+ state.but_flag = but->flag;
+ state.but_drawflag = but->drawflag;
+ alpha *= widget_alpha_factor(&state);
}
GPU_blend(GPU_BLEND_ALPHA);
@@ -2447,7 +2461,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
* \{ */
/* put all widget colors on half alpha, use local storage */
-static void ui_widget_color_disabled(uiWidgetType *wt, const int state)
+static void ui_widget_color_disabled(uiWidgetType *wt, const uiWidgetStateInfo *state)
{
static uiWidgetColors wcol_theme_s;
@@ -2474,8 +2488,7 @@ static void widget_active_color(uiWidgetColors *wcol)
}
static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wcol_state,
- int state,
- int drawflag,
+ const uiWidgetStateInfo *state,
const eUIEmbossType emboss)
{
/* Explicitly require #UI_EMBOSS_NONE_OR_STATUS for color blending with no emboss. */
@@ -2483,44 +2496,44 @@ static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wco
return NULL;
}
- if (drawflag & UI_BUT_ANIMATED_CHANGED) {
+ if (state->but_drawflag & UI_BUT_ANIMATED_CHANGED) {
return wcol_state->inner_changed_sel;
}
- if (state & UI_BUT_ANIMATED_KEY) {
+ if (state->but_flag & UI_BUT_ANIMATED_KEY) {
return wcol_state->inner_key_sel;
}
- if (state & UI_BUT_ANIMATED) {
+ if (state->but_flag & UI_BUT_ANIMATED) {
return wcol_state->inner_anim_sel;
}
- if (state & UI_BUT_DRIVEN) {
+ if (state->but_flag & UI_BUT_DRIVEN) {
return wcol_state->inner_driven_sel;
}
- if (state & UI_BUT_OVERRIDDEN) {
+ if (state->but_flag & UI_BUT_OVERRIDDEN) {
return wcol_state->inner_overridden_sel;
}
return NULL;
}
/* copy colors from theme, and set changes in it based on state */
-static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss)
+static void widget_state(uiWidgetType *wt, const uiWidgetStateInfo *state, eUIEmbossType emboss)
{
uiWidgetStateColors *wcol_state = wt->wcol_state;
- if (state & UI_BUT_LIST_ITEM) {
+ if (state->but_flag & UI_BUT_LIST_ITEM) {
/* Override default widget's colors. */
bTheme *btheme = UI_GetTheme();
wt->wcol_theme = &btheme->tui.wcol_list_item;
- if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
+ if (state->but_flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
ui_widget_color_disabled(wt, state);
}
}
wt->wcol = *(wt->wcol_theme);
- const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag, emboss);
+ const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, emboss);
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
if (color_blend != NULL) {
color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
@@ -2528,12 +2541,12 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossTyp
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
}
}
else {
- if (state & UI_BUT_ACTIVE_DEFAULT) {
+ if (state->but_flag & UI_BUT_ACTIVE_DEFAULT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
copy_v4_v4_uchar(wt->wcol.text, wt->wcol.text_sel);
}
@@ -2545,12 +2558,12 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossTyp
* even if UI_SELECT. But currently this causes some flickering
* as buttons can be created and updated without respect to mouse
* position and so can draw without UI_ACTIVE set. See D6503. */
- if (state & UI_ACTIVE) {
+ if (state->but_flag & UI_ACTIVE) {
widget_active_color(&wt->wcol);
}
}
- if (state & UI_BUT_REDALERT) {
+ if (state->but_flag & UI_BUT_REDALERT) {
const uchar red[4] = {255, 0, 0};
if (wt->draw && emboss != UI_EMBOSS_NONE) {
color_blend_v3_v3(wt->wcol.inner, red, 0.4f);
@@ -2560,14 +2573,14 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossTyp
}
}
- if (state & UI_BUT_DRAG_MULTI) {
+ if (state->but_flag & UI_BUT_DRAG_MULTI) {
/* the button isn't SELECT but we're editing this so draw with sel color */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.85f);
}
- if (state & UI_BUT_NODE_ACTIVE) {
+ if (state->but_flag & UI_BUT_NODE_ACTIVE) {
const uchar blue[4] = {86, 128, 194};
color_blend_v3_v3(wt->wcol.inner, blue, 0.3f);
}
@@ -2601,14 +2614,16 @@ static float widget_radius_from_rcti(const rcti *rect, const uiWidgetColors *wco
* \{ */
/* sliders use special hack which sets 'item' as inner when drawing filling */
-static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss)
+static void widget_state_numslider(uiWidgetType *wt,
+ const uiWidgetStateInfo *state,
+ eUIEmbossType emboss)
{
uiWidgetStateColors *wcol_state = wt->wcol_state;
/* call this for option button */
- widget_state(wt, state, drawflag, emboss);
+ widget_state(wt, state, emboss);
- const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag, emboss);
+ const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, emboss);
if (color_blend != NULL) {
/* Set the slider 'item' so that it reflects state settings too.
* De-saturate so the color of the slider doesn't conflict with the blend color,
@@ -2618,15 +2633,14 @@ static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, eU
color_ensure_contrast_v3(wt->wcol.item, wt->wcol.inner, 30);
}
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
}
}
/* labels use theme colors for text */
static void widget_state_option_menu(uiWidgetType *wt,
- int state,
- int drawflag,
+ const uiWidgetStateInfo *state,
eUIEmbossType emboss)
{
const bTheme *btheme = UI_GetTheme();
@@ -2639,14 +2653,13 @@ static void widget_state_option_menu(uiWidgetType *wt,
copy_v3_v3_uchar(wcol_menu_option.text_sel, btheme->tui.wcol_menu_back.text_sel);
wt->wcol_theme = &wcol_menu_option;
- widget_state(wt, state, drawflag, emboss);
+ widget_state(wt, state, emboss);
wt->wcol_theme = old_wcol;
}
static void widget_state_nothing(uiWidgetType *wt,
- int UNUSED(state),
- int UNUSED(drawflag),
+ const uiWidgetStateInfo *UNUSED(state),
eUIEmbossType UNUSED(emboss))
{
wt->wcol = *(wt->wcol_theme);
@@ -2654,8 +2667,7 @@ static void widget_state_nothing(uiWidgetType *wt,
/* special case, button that calls pulldown */
static void widget_state_pulldown(uiWidgetType *wt,
- int UNUSED(state),
- int UNUSED(drawflag),
+ const uiWidgetStateInfo *UNUSED(state),
eUIEmbossType UNUSED(emboss))
{
wt->wcol = *(wt->wcol_theme);
@@ -2663,14 +2675,13 @@ static void widget_state_pulldown(uiWidgetType *wt,
/* special case, pie menu items */
static void widget_state_pie_menu_item(uiWidgetType *wt,
- int state,
- int UNUSED(drawflag),
+ const uiWidgetStateInfo *state,
eUIEmbossType UNUSED(emboss))
{
wt->wcol = *(wt->wcol_theme);
/* active and disabled (not so common) */
- if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
+ if ((state->but_flag & UI_BUT_DISABLED) && (state->but_flag & UI_ACTIVE)) {
color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.5f);
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
@@ -2679,18 +2690,18 @@ static void widget_state_pie_menu_item(uiWidgetType *wt,
}
else {
/* regular active */
- if (state & (UI_SELECT | UI_ACTIVE)) {
+ if (state->but_flag & (UI_SELECT | UI_ACTIVE)) {
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
}
- else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
+ else if (state->but_flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* regular disabled */
color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
}
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
}
- else if (state & UI_ACTIVE) {
+ else if (state->but_flag & UI_ACTIVE) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.item);
}
}
@@ -2698,14 +2709,13 @@ static void widget_state_pie_menu_item(uiWidgetType *wt,
/* special case, menu items */
static void widget_state_menu_item(uiWidgetType *wt,
- int state,
- int UNUSED(drawflag),
+ const uiWidgetStateInfo *state,
eUIEmbossType UNUSED(emboss))
{
wt->wcol = *(wt->wcol_theme);
/* active and disabled (not so common) */
- if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
+ if ((state->but_flag & UI_BUT_DISABLED) && (state->but_flag & UI_ACTIVE)) {
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
wt->wcol.text[3] = 128;
@@ -2714,15 +2724,15 @@ static void widget_state_menu_item(uiWidgetType *wt,
}
else {
/* regular active */
- if (state & UI_ACTIVE) {
+ if (state->but_flag & UI_ACTIVE) {
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
}
- else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
+ else if (state->but_flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* regular disabled */
color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
}
- if (state & UI_ACTIVE) {
+ if (state->but_flag & UI_ACTIVE) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
}
}
@@ -2788,7 +2798,7 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
}
static void widget_menu_back(
- uiWidgetColors *wcol, rcti *rect, int flag, int direction, const float zoom)
+ uiWidgetColors *wcol, rcti *rect, const int block_flag, const int direction, const float zoom)
{
uiWidgetBase wtb;
int roundboxalign = UI_CNR_ALL;
@@ -2796,7 +2806,7 @@ static void widget_menu_back(
widget_init(&wtb);
/* menu is 2nd level or deeper */
- if (flag & UI_BLOCK_POPUP) {
+ if (block_flag & UI_BLOCK_POPUP) {
// rect->ymin -= 4.0;
// rect->ymax += 4.0;
}
@@ -3322,13 +3332,17 @@ static void ui_draw_separator(const rcti *rect, const uiWidgetColors *wcol)
#define NUM_BUT_PADDING_FACTOR 0.425f
-static void widget_numbut_draw(
- uiWidgetColors *wcol, rcti *rect, const float zoom, int state, int roundboxalign, bool emboss)
+static void widget_numbut_draw(uiWidgetColors *wcol,
+ rcti *rect,
+ const float zoom,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ bool emboss)
{
const float rad = widget_radius_from_zoom(zoom, wcol);
const int handle_width = min_ii(BLI_rcti_size_x(rect) / 3, BLI_rcti_size_y(rect) * 0.7f);
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
SWAP(short, wcol->shadetop, wcol->shadedown);
}
@@ -3344,7 +3358,7 @@ static void widget_numbut_draw(
}
/* decoration */
- if ((state & UI_ACTIVE) && !(state & UI_STATE_TEXT_INPUT)) {
+ if ((state->but_flag & UI_ACTIVE) && !state->is_text_input) {
uiWidgetColors wcol_zone;
uiWidgetBase wtb_zone;
rcti rect_zone;
@@ -3357,7 +3371,7 @@ static void widget_numbut_draw(
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
- if (state & UI_STATE_ACTIVE_LEFT) {
+ if (state->but_drawflag & UI_BUT_ACTIVE_LEFT) {
widget_active_color(&wcol_zone);
}
@@ -3377,7 +3391,7 @@ static void widget_numbut_draw(
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
- if (state & UI_STATE_ACTIVE_RIGHT) {
+ if (state->but_drawflag & UI_BUT_ACTIVE_RIGHT) {
widget_active_color(&wcol_zone);
}
@@ -3396,7 +3410,7 @@ static void widget_numbut_draw(
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
- if (!(state & (UI_STATE_ACTIVE_LEFT | UI_STATE_ACTIVE_RIGHT))) {
+ if (!(state->but_drawflag & (UI_BUT_ACTIVE_LEFT | UI_BUT_ACTIVE_RIGHT))) {
widget_active_color(&wcol_zone);
}
@@ -3415,7 +3429,7 @@ static void widget_numbut_draw(
widgetbase_draw(&wtb, wcol);
}
- if (!(state & UI_STATE_TEXT_INPUT)) {
+ if (!state->is_text_input) {
const float text_padding = NUM_BUT_PADDING_FACTOR * BLI_rcti_size_y(rect);
rect->xmin += text_padding;
@@ -3423,14 +3437,20 @@ static void widget_numbut_draw(
}
}
-static void widget_numbut(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_numbut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
widget_numbut_draw(wcol, rect, zoom, state, roundboxalign, false);
}
-static void widget_menubut(
- uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
+static void widget_menubut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -3455,7 +3475,7 @@ static void widget_menubut(
static void widget_menubut_embossn(const uiBut *UNUSED(but),
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign))
{
uiWidgetBase wtb;
@@ -3477,7 +3497,7 @@ static void widget_menubut_embossn(const uiBut *UNUSED(but),
static void widget_numbut_embossn(const uiBut *UNUSED(but),
uiWidgetColors *wcol,
rcti *rect,
- int state,
+ const uiWidgetStateInfo *state,
int roundboxalign,
const float zoom)
{
@@ -3487,7 +3507,6 @@ static void widget_numbut_embossn(const uiBut *UNUSED(but),
void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
{
uiWidgetBase wtb;
- bool outline = false;
widget_init(&wtb);
@@ -3532,11 +3551,6 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
/* draw */
wtb.draw_emboss = false; /* only emboss once */
- /* exception for progress bar */
- if (state & UI_SCROLL_NO_OUTLINE) {
- SWAP(bool, outline, wtb.draw_outline);
- }
-
round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
if (state & UI_SCROLL_ARROWS) {
@@ -3564,17 +3578,13 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
}
}
widgetbase_draw(&wtb, wcol);
-
- if (state & UI_SCROLL_NO_OUTLINE) {
- SWAP(bool, outline, wtb.draw_outline);
- }
}
}
static void widget_scroll(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int state,
+ const uiWidgetStateInfo *state,
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
@@ -3624,19 +3634,13 @@ static void widget_scroll(uiBut *but,
}
}
- if (state & UI_SELECT) {
- state = UI_SCROLL_PRESSED;
- }
- else {
- state = 0;
- }
- UI_draw_widget_scroll(wcol, rect, &rect1, state);
+ UI_draw_widget_scroll(wcol, rect, &rect1, (state->but_flag & UI_SELECT) ? UI_SCROLL_PRESSED : 0);
}
static void widget_progressbar(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int roundboxalign,
const float zoom)
{
@@ -3670,7 +3674,7 @@ static void widget_progressbar(uiBut *but,
static void widget_treerow_exec(uiWidgetColors *wcol,
rcti *rect,
- int state,
+ const uiWidgetStateInfo *state,
int UNUSED(roundboxalign),
int indentation,
const float zoom)
@@ -3683,7 +3687,7 @@ static void widget_treerow_exec(uiWidgetColors *wcol,
const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
- if ((state & UI_ACTIVE) || (state & UI_SELECT)) {
+ if ((state->but_flag & UI_ACTIVE) || (state->but_flag & UI_SELECT)) {
widgetbase_draw(&wtb, wcol);
}
@@ -3691,8 +3695,12 @@ static void widget_treerow_exec(uiWidgetColors *wcol,
BLI_rcti_translate(rect, 0.5f * UI_UNIT_X * indentation, 0);
}
-static void widget_treerow(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_treerow(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
uiButTreeRow *tree_row = (uiButTreeRow *)but;
BLI_assert(but->type == UI_BTYPE_TREEROW);
@@ -3709,7 +3717,7 @@ static void widget_gridtile(
static void widget_nodesocket(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
@@ -3745,8 +3753,12 @@ static void widget_nodesocket(uiBut *but,
copy_v3_v3_uchar(wcol->outline, old_outline);
}
-static void widget_numslider(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_numslider(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb, wtb1;
widget_init(&wtb);
@@ -3760,7 +3772,7 @@ static void widget_numslider(
widgetbase_draw(&wtb, wcol);
/* Draw slider part only when not in text editing. */
- if (!(state & UI_STATE_TEXT_INPUT)) {
+ if (!state->is_text_input) {
int roundboxalign_slider = roundboxalign;
uchar outline[3];
@@ -3768,7 +3780,7 @@ static void widget_numslider(
copy_v3_v3_uchar(wcol->outline, wcol->item);
copy_v3_v3_uchar(wcol->inner, wcol->item);
- if (!(state & UI_SELECT)) {
+ if (!(state->but_flag & UI_SELECT)) {
SWAP(short, wcol->shadetop, wcol->shadedown);
}
@@ -3836,7 +3848,7 @@ static void widget_numslider(
copy_v3_v3_uchar(wcol->outline, outline);
- if (!(state & UI_SELECT)) {
+ if (!(state->but_flag & UI_SELECT)) {
SWAP(short, wcol->shadetop, wcol->shadedown);
}
}
@@ -3848,7 +3860,7 @@ static void widget_numslider(
/* Add space at either side of the button so text aligns with number-buttons
* (which have arrow icons). */
- if (!(state & UI_STATE_TEXT_INPUT)) {
+ if (!state->is_text_input) {
const float text_padding = NUM_BUT_PADDING_FACTOR * BLI_rcti_size_y(rect);
rect->xmax -= text_padding;
rect->xmin += text_padding;
@@ -3858,8 +3870,12 @@ static void widget_numslider(
/* I think 3 is sufficient border to indicate keyed status */
#define SWATCH_KEYED_BORDER 3
-static void widget_swatch(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_swatch(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
BLI_assert(but->type == UI_BTYPE_COLOR);
uiButColor *color_but = (uiButColor *)but;
@@ -3883,9 +3899,9 @@ static void widget_swatch(
ui_but_v3_get(but, col);
- if ((state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_OVERRIDDEN |
- UI_BUT_REDALERT)) ||
- (but->drawflag & UI_BUT_ANIMATED_CHANGED)) {
+ if ((state->but_flag & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN |
+ UI_BUT_OVERRIDDEN | UI_BUT_REDALERT)) ||
+ (state->but_drawflag & UI_BUT_ANIMATED_CHANGED)) {
/* draw based on state - color for keyed etc */
widgetbase_draw(&wtb, wcol);
@@ -3946,7 +3962,7 @@ static void widget_swatch(
static void widget_unitvec(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -3954,10 +3970,15 @@ static void widget_unitvec(uiBut *but,
ui_draw_but_UNITVEC(but, wcol, rect, rad);
}
-static void widget_icon_has_anim(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_icon_has_anim(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
- if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT) &&
+ if (state->but_flag &
+ (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT) &&
but->emboss != UI_EMBOSS_NONE) {
uiWidgetBase wtb;
widget_init(&wtb);
@@ -3978,10 +3999,13 @@ static void widget_icon_has_anim(
}
}
-static void widget_textbut(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_textbut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
SWAP(short, wcol->shadetop, wcol->shadedown);
}
@@ -3997,7 +4021,7 @@ static void widget_textbut(
static void widget_preview_tile(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
@@ -4006,8 +4030,11 @@ static void widget_preview_tile(uiBut *but,
&style->widget, rect, but->drawstr, but->icon, wcol->text, UI_STYLE_TEXT_CENTER);
}
-static void widget_menuiconbut(
- uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
+static void widget_menuiconbut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4019,17 +4046,20 @@ static void widget_menuiconbut(
widgetbase_draw(&wtb, wcol);
}
-static void widget_pulldownbut(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_pulldownbut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
float back[4];
UI_GetThemeColor4fv(TH_BACK, back);
- if ((state & UI_ACTIVE) || (back[3] < 1.0f)) {
+ if ((state->but_flag & UI_ACTIVE) || (back[3] < 1.0f)) {
uiWidgetBase wtb;
const float rad = widget_radius_from_zoom(zoom, wcol);
- if (state & UI_ACTIVE) {
+ if (state->but_flag & UI_ACTIVE) {
copy_v4_v4_uchar(wcol->inner, wcol->inner_sel);
copy_v3_v3_uchar(wcol->text, wcol->text_sel);
copy_v3_v3_uchar(wcol->outline, wcol->inner);
@@ -4050,7 +4080,7 @@ static void widget_pulldownbut(
static void widget_menu_itembut(uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4074,7 +4104,7 @@ static void widget_menu_itembut(uiWidgetColors *wcol,
static void widget_menu_itembut_unpadded(uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4096,7 +4126,7 @@ static void widget_menu_itembut_unpadded(uiWidgetColors *wcol,
static void widget_menu_radial_itembut(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4122,7 +4152,7 @@ static void widget_menu_radial_itembut(uiBut *but,
static void widget_list_itembut(uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4139,11 +4169,13 @@ static void widget_list_itembut(uiWidgetColors *wcol,
static void widget_optionbut(uiWidgetColors *wcol,
rcti *rect,
- int state,
+ const uiWidgetStateInfo *state,
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
- const bool text_before_widget = (state & UI_STATE_TEXT_BEFORE_WIDGET);
+ /* For a right aligned layout (signified by #UI_BUT_TEXT_RIGHT), draw the text on the left of the
+ * checkbox. */
+ const bool text_before_widget = (state->but_drawflag & UI_BUT_TEXT_RIGHT);
rcti recttemp = *rect;
uiWidgetBase wtb;
@@ -4168,7 +4200,7 @@ static void widget_optionbut(uiWidgetColors *wcol,
round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
/* decoration */
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
shape_preset_trias_from_rect_checkmark(&wtb.tria1, &recttemp);
}
@@ -4185,19 +4217,21 @@ static void widget_optionbut(uiWidgetColors *wcol,
}
/* labels use Editor theme colors for text */
-static void widget_state_label(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss)
+static void widget_state_label(uiWidgetType *wt,
+ const uiWidgetStateInfo *state,
+ eUIEmbossType emboss)
{
- if (state & UI_BUT_LIST_ITEM) {
+ if (state->but_flag & UI_BUT_LIST_ITEM) {
/* Override default label theme's colors. */
bTheme *btheme = UI_GetTheme();
wt->wcol_theme = &btheme->tui.wcol_list_item;
/* call this for option button */
- widget_state(wt, state, drawflag, emboss);
+ widget_state(wt, state, emboss);
}
else {
/* call this for option button */
- widget_state(wt, state, drawflag, emboss);
- if (state & UI_SELECT) {
+ widget_state(wt, state, emboss);
+ if (state->but_flag & UI_SELECT) {
UI_GetThemeColor3ubv(TH_TEXT_HI, wt->wcol.text);
}
else {
@@ -4205,14 +4239,17 @@ static void widget_state_label(uiWidgetType *wt, int state, int drawflag, eUIEmb
}
}
- if (state & UI_BUT_REDALERT) {
+ if (state->but_flag & UI_BUT_REDALERT) {
const uchar red[4] = {255, 0, 0};
color_blend_v3_v3(wt->wcol.text, red, 0.4f);
}
}
-static void widget_radiobut(
- uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
+static void widget_radiobut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4226,7 +4263,7 @@ static void widget_radiobut(
static void widget_box(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int roundboxalign,
const float zoom)
{
@@ -4252,8 +4289,11 @@ static void widget_box(uiBut *but,
copy_v3_v3_uchar(wcol->inner, old_col);
}
-static void widget_but(
- uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
+static void widget_but(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4279,13 +4319,16 @@ static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
}
#endif
-static void widget_roundbut_exec(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_roundbut_exec(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- if (state & UI_STATE_HOLD_ACTION) {
+ if (state->has_hold_action) {
/* Show that keeping pressed performs another action (typically a menu). */
shape_preset_init_hold_action(&wtb.tria1, rect, 0.75f, 'r');
}
@@ -4298,11 +4341,14 @@ static void widget_roundbut_exec(
widgetbase_draw(&wtb, wcol);
}
-static void widget_tab(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_tab(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
const float rad = widget_radius_from_zoom(zoom, wcol);
- const bool is_active = (state & UI_SELECT);
+ const bool is_active = (state->but_flag & UI_SELECT);
/* Draw shaded outline - Disabled for now,
* seems incorrect and also looks nicer without it IMHO ;). */
@@ -4450,7 +4496,7 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
case UI_WTYPE_TOOLTIP:
wt.wcol_theme = &btheme->tui.wcol_tooltip;
- wt.draw = widget_menu_back;
+ wt.draw_block = widget_menu_back;
break;
/* strings */
@@ -4506,7 +4552,7 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
case UI_WTYPE_MENU_BACK:
wt.wcol_theme = &btheme->tui.wcol_menu_back;
- wt.draw = widget_menu_back;
+ wt.draw_block = widget_menu_back;
break;
/* specials */
@@ -4940,62 +4986,50 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
const int roundboxalign = widget_roundbox_set(but, rect);
- /* Mask out flags re-used for local state. */
- int state = but->flag & ~UI_STATE_FLAGS_ALL;
- const int drawflag = but->drawflag;
+ uiWidgetStateInfo state = {0};
+ state.but_flag = but->flag;
+ state.but_drawflag = but->drawflag;
- if (state & UI_SELECT_DRAW) {
- state |= UI_SELECT;
+ /* Override selected flag for drawing. */
+ if (but->flag & UI_SELECT_DRAW) {
+ state.but_flag |= UI_SELECT;
}
if ((but->editstr) ||
(UNLIKELY(but->flag & UI_BUT_DRAG_MULTI) && ui_but_drag_multi_edit_get(but))) {
- state |= UI_STATE_TEXT_INPUT;
+ state.is_text_input = true;
}
if (but->hold_func) {
- state |= UI_STATE_HOLD_ACTION;
- }
-
- if (state & UI_ACTIVE) {
- if (but->drawflag & UI_BUT_ACTIVE_LEFT) {
- state |= UI_STATE_ACTIVE_LEFT;
- }
- else if (but->drawflag & UI_BUT_ACTIVE_RIGHT) {
- state |= UI_STATE_ACTIVE_RIGHT;
- }
+ state.has_hold_action = true;
}
bool use_alpha_blend = false;
if (but->emboss != UI_EMBOSS_PULLDOWN) {
- if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
+ if (but->flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
use_alpha_blend = true;
- ui_widget_color_disabled(wt, state);
+ ui_widget_color_disabled(wt, &state);
}
}
- if (drawflag & UI_BUT_TEXT_RIGHT) {
- state |= UI_STATE_TEXT_BEFORE_WIDGET;
- }
-
#ifdef USE_UI_POPOVER_ONCE
if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
- if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
- state |= UI_BUT_ACTIVE_DEFAULT;
+ if ((but->flag & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
+ state.but_flag |= UI_BUT_ACTIVE_DEFAULT;
}
}
#endif
if (but->block->flag & UI_BLOCK_NO_DRAW_OVERRIDDEN_STATE) {
- state &= ~UI_BUT_OVERRIDDEN;
+ state.but_flag &= ~UI_BUT_OVERRIDDEN;
}
const float zoom = 1.0f / but->block->aspect;
- wt->state(wt, state, drawflag, but->emboss);
+ wt->state(wt, &state, but->emboss);
if (wt->custom) {
- wt->custom(but, &wt->wcol, rect, state, roundboxalign, zoom);
+ wt->custom(but, &wt->wcol, rect, &state, roundboxalign, zoom);
}
else if (wt->draw) {
- wt->draw(&wt->wcol, rect, state, roundboxalign, zoom);
+ wt->draw(&wt->wcol, rect, &state, roundboxalign, zoom);
}
if (wt->text) {
@@ -5036,13 +5070,13 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_BACK);
- wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
+ wt->state(wt, &STATE_INFO_NULL, UI_EMBOSS_UNDEFINED);
if (block) {
const float zoom = 1.0f / block->aspect;
- wt->draw(&wt->wcol, rect, block->flag, block->direction, zoom);
+ wt->draw_block(&wt->wcol, rect, block->flag, block->direction, zoom);
}
else {
- wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
+ wt->draw_block(&wt->wcol, rect, 0, 0, 1.0f);
}
ui_draw_clip_tri(block, rect, wt);
@@ -5137,8 +5171,8 @@ void ui_draw_popover_back(struct ARegion *region,
}
else {
const float zoom = 1.0f / block->aspect;
- wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0, zoom);
+ wt->state(wt, &STATE_INFO_NULL, UI_EMBOSS_UNDEFINED);
+ wt->draw_block(&wt->wcol, rect, 0, 0, zoom);
}
ui_draw_clip_tri(block, rect, wt);
@@ -5326,11 +5360,20 @@ static void ui_draw_widget_back_color(uiWidgetTypeEnum type,
}
rcti rect_copy = *rect;
- wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
+ wt->state(wt, &STATE_INFO_NULL, UI_EMBOSS_UNDEFINED);
if (color) {
rgba_float_to_uchar(wt->wcol.inner, color);
}
- wt->draw(&wt->wcol, &rect_copy, 0, UI_CNR_ALL, 1.0f);
+
+ if (wt->draw_block) {
+ wt->draw_block(&wt->wcol, &rect_copy, 0, UI_CNR_ALL, 1.0f);
+ }
+ else if (wt->draw) {
+ wt->draw(&wt->wcol, &rect_copy, &STATE_INFO_NULL, UI_CNR_ALL, 1.0f);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
}
void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const float color[4])
{
@@ -5345,16 +5388,16 @@ void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow)
void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(block), rcti *rect)
{
uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);
- wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
- /* wt->draw ends up using same function to draw the tooltip as menu_back */
- wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
+ wt->state(wt, &STATE_INFO_NULL, UI_EMBOSS_UNDEFINED);
+ /* wt->draw_block ends up using same function to draw the tooltip as menu_back */
+ wt->draw_block(&wt->wcol, rect, 0, 0, 1.0f);
}
void ui_draw_menu_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ int but_flag,
uiMenuItemSeparatorType separator_type,
int *r_xmax)
{
@@ -5365,8 +5408,11 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
int padding = 0.25f * row_height;
char *cpoin = NULL;
- wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
+ uiWidgetStateInfo state = {0};
+ state.but_flag = but_flag;
+
+ wt->state(wt, &state, UI_EMBOSS_UNDEFINED);
+ wt->draw(&wt->wcol, rect, &STATE_INFO_NULL, 0, 1.0f);
UI_fontstyle_set(fstyle);
@@ -5461,8 +5507,12 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
/* part text right aligned */
if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) {
if (cpoin) {
+ /* State info for the hint drawing. */
+ uiWidgetStateInfo hint_state = state;
/* Set inactive state for grayed out text. */
- wt->state(wt, state | UI_BUT_INACTIVE, 0, UI_EMBOSS_UNDEFINED);
+ hint_state.but_flag |= UI_BUT_INACTIVE;
+
+ wt->state(wt, &hint_state, UI_EMBOSS_UNDEFINED);
char hint_drawstr[UI_MAX_DRAW_STR];
{
@@ -5545,14 +5595,17 @@ void ui_draw_preview_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ int but_flag,
eFontStyle_Align text_align)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM_UNPADDED);
+ uiWidgetStateInfo state = {0};
+ state.but_flag = but_flag;
+
/* drawing button background */
- wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
+ wt->state(wt, &state, UI_EMBOSS_UNDEFINED);
+ wt->draw(&wt->wcol, rect, &STATE_INFO_NULL, 0, 1.0f);
ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, text_align);
}
diff --git a/source/blender/editors/interface/view2d.cc b/source/blender/editors/interface/view2d.cc
index 66171dc13e4..6ece7eb4ffa 100644
--- a/source/blender/editors/interface/view2d.cc
+++ b/source/blender/editors/interface/view2d.cc
@@ -2103,21 +2103,12 @@ void UI_view2d_text_cache_draw(ARegion *region)
col_pack_prev = v2s->col.pack;
}
- if (v2s->rect.xmin >= v2s->rect.xmax) {
- BLF_draw_default((float)(v2s->mval[0] + xofs),
- (float)(v2s->mval[1] + yofs),
- 0.0,
- v2s->str,
- BLF_DRAW_STR_DUMMY_MAX);
- }
- else {
- BLF_enable(font_id, BLF_CLIPPING);
- BLF_clipping(
- font_id, v2s->rect.xmin - 4, v2s->rect.ymin - 4, v2s->rect.xmax + 4, v2s->rect.ymax + 4);
- BLF_draw_default(
- v2s->rect.xmin + xofs, v2s->rect.ymin + yofs, 0.0f, v2s->str, BLF_DRAW_STR_DUMMY_MAX);
- BLF_disable(font_id, BLF_CLIPPING);
- }
+ BLF_enable(font_id, BLF_CLIPPING);
+ BLF_clipping(
+ font_id, v2s->rect.xmin - 4, v2s->rect.ymin - 4, v2s->rect.xmax + 4, v2s->rect.ymax + 4);
+ BLF_draw_default(
+ v2s->rect.xmin + xofs, v2s->rect.ymin + yofs, 0.0f, v2s->str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_disable(font_id, BLF_CLIPPING);
}
g_v2d_strings = nullptr;
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index 886586ff236..f1cd7607771 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -16,6 +16,8 @@
#include "BLT_translation.h"
+#include "ED_outliner.h"
+
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
@@ -410,6 +412,12 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op)
OBJ_import(C, &import_params);
+ Scene *scene = CTX_data_scene(C);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 0b9261eac4f..d10c420e28c 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -230,7 +230,7 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
MaskLayer *mask_layer;
MaskSpline *spline;
MaskSplinePoint *point = NULL;
- const float threshold = 9;
+ const float threshold = 12;
float tangent[2];
float u;
@@ -593,7 +593,7 @@ static int add_feather_vertex_exec(bContext *C, wmOperator *op)
MaskLayer *mask_layer;
MaskSpline *spline;
MaskSplinePoint *point = NULL;
- const float threshold = 9;
+ const float threshold = 12;
float co[2], u;
RNA_float_get_array(op->ptr, "location", co);
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index afe457a8502..89524a7b9e2 100644
--- a/source/blender/editors/mask/mask_query.c
+++ b/source/blender/editors/mask/mask_query.c
@@ -45,6 +45,8 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
float *r_u,
float *r_score)
{
+ const float threshold_sq = threshold * threshold;
+
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
@@ -139,7 +141,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
}
}
- if (point && dist_best_sq < threshold) {
+ if (point && dist_best_sq < threshold_sq) {
if (r_mask_layer) {
*r_mask_layer = point_mask_layer;
}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index b2f33428b21..57e0d04727c 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -113,7 +113,7 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(
@@ -178,7 +178,7 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(em,
@@ -252,7 +252,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(
@@ -324,7 +324,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(em,
@@ -400,7 +400,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(em,
@@ -476,7 +476,7 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(
@@ -553,7 +553,7 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(em,
@@ -614,7 +614,7 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(
@@ -682,7 +682,7 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(
diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c
index d0f37314661..f5090c0143d 100644
--- a/source/blender/editors/mesh/editmesh_add_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_add_gizmo.c
@@ -328,7 +328,7 @@ static int add_primitive_cube_gizmo_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(em,
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 5de7681a1e6..7972459e457 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -377,45 +377,45 @@ static void knifetool_raycast_planes(const KnifeTool_OpData *kcd, float r_v1[3],
kcd->vc.rv3d->persmat, planes[2], planes[0], planes[1], planes[3], NULL, NULL);
/* Ray-cast all planes. */
+ float ray_dir[3];
+ float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}};
+ float lambda_best[2] = {-FLT_MAX, FLT_MAX};
+ int i;
+
{
- float ray_dir[3];
- float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}};
- float lambda_best[2] = {-FLT_MAX, FLT_MAX};
- int i;
+ float curr_cage_adjust[3];
+ float co_depth[3];
- {
- float curr_cage_adjust[3];
- float co_depth[3];
+ copy_v3_v3(co_depth, kcd->prev.cage);
+ ED_view3d_win_to_3d(kcd->vc.v3d, kcd->region, co_depth, kcd->curr.mval, curr_cage_adjust);
- copy_v3_v3(co_depth, kcd->prev.cage);
- ED_view3d_win_to_3d(kcd->vc.v3d, kcd->region, co_depth, kcd->curr.mval, curr_cage_adjust);
+ sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage);
+ }
- sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage);
+ for (i = 0; i < 4; i++) {
+ float ray_hit[3];
+ float lambda_test;
+ if (!isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) {
+ continue;
}
- for (i = 0; i < 4; i++) {
- float ray_hit[3];
- float lambda_test;
- if (isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) {
- madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test);
- if (lambda_test < 0.0f) {
- if (lambda_test > lambda_best[0]) {
- copy_v3_v3(ray_hit_best[0], ray_hit);
- lambda_best[0] = lambda_test;
- }
- }
- else {
- if (lambda_test < lambda_best[1]) {
- copy_v3_v3(ray_hit_best[1], ray_hit);
- lambda_best[1] = lambda_test;
- }
- }
+ madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test);
+ if (lambda_test < 0.0f) {
+ if (lambda_test > lambda_best[0]) {
+ copy_v3_v3(ray_hit_best[0], ray_hit);
+ lambda_best[0] = lambda_test;
+ }
+ }
+ else {
+ if (lambda_test < lambda_best[1]) {
+ copy_v3_v3(ray_hit_best[1], ray_hit);
+ lambda_best[1] = lambda_test;
}
}
-
- copy_v3_v3(r_v1, ray_hit_best[0]);
- copy_v3_v3(r_v2, ray_hit_best[1]);
}
+
+ copy_v3_v3(r_v1, ray_hit_best[0]);
+ copy_v3_v3(r_v2, ray_hit_best[1]);
}
static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
@@ -440,43 +440,45 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
static void knifetool_draw_orientation_locking(const KnifeTool_OpData *kcd)
{
- if (!compare_v3v3(kcd->prev.cage, kcd->curr.cage, KNIFE_FLT_EPSBIG)) {
- float v1[3], v2[3];
+ if (compare_v3v3(kcd->prev.cage, kcd->curr.cage, KNIFE_FLT_EPSBIG)) {
+ return;
+ }
- /* This is causing buggy behavior when `prev.cage` and `curr.cage` are too close together. */
- knifetool_raycast_planes(kcd, v1, v2);
+ float v1[3], v2[3];
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ /* This is causing buggy behavior when `prev.cage` and `curr.cage` are too close together. */
+ knifetool_raycast_planes(kcd, v1, v2);
- switch (kcd->constrain_axis) {
- case KNF_CONSTRAIN_AXIS_X: {
- immUniformColor3ubv(kcd->colors.xaxis);
- break;
- }
- case KNF_CONSTRAIN_AXIS_Y: {
- immUniformColor3ubv(kcd->colors.yaxis);
- break;
- }
- case KNF_CONSTRAIN_AXIS_Z: {
- immUniformColor3ubv(kcd->colors.zaxis);
- break;
- }
- default: {
- immUniformColor3ubv(kcd->colors.axis_extra);
- break;
- }
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ switch (kcd->constrain_axis) {
+ case KNF_CONSTRAIN_AXIS_X: {
+ immUniformColor3ubv(kcd->colors.xaxis);
+ break;
+ }
+ case KNF_CONSTRAIN_AXIS_Y: {
+ immUniformColor3ubv(kcd->colors.yaxis);
+ break;
}
+ case KNF_CONSTRAIN_AXIS_Z: {
+ immUniformColor3ubv(kcd->colors.zaxis);
+ break;
+ }
+ default: {
+ immUniformColor3ubv(kcd->colors.axis_extra);
+ break;
+ }
+ }
- GPU_line_width(2.0);
+ GPU_line_width(2.0);
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3fv(pos, v1);
- immVertex3fv(pos, v2);
- immEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immEnd();
- immUnbindProgram();
- }
+ immUnbindProgram();
}
static void knifetool_draw_visible_distances(const KnifeTool_OpData *kcd)
@@ -1226,7 +1228,6 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
}
/* Construct BVH Tree. */
- float cos[3][3];
const float epsilon = FLT_EPSILON * 2.0f;
int tottri = 0;
int ob_tottri = 0;
@@ -1283,8 +1284,10 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
if (!test_fn_ret) {
continue;
}
- knife_bm_tri_cagecos_get_worldspace(kcd, b, i, cos);
- BLI_bvhtree_insert(kcd->bvh.tree, i + tottri, (float *)cos, 3);
+
+ float tri_cos[3][3];
+ knife_bm_tri_cagecos_get_worldspace(kcd, b, i, tri_cos);
+ BLI_bvhtree_insert(kcd->bvh.tree, i + tottri, &tri_cos[0][0], 3);
}
tottri += em->tottri;
@@ -1307,6 +1310,10 @@ static void knife_bvh_raycast_cb(void *userdata,
const BVHTreeRay *ray,
BVHTreeRayHit *hit)
{
+ if (index != -1) {
+ return;
+ }
+
KnifeTool_OpData *kcd = userdata;
BMLoop **ltri;
Object *ob;
@@ -1315,60 +1322,49 @@ static void knife_bvh_raycast_cb(void *userdata,
float dist, uv[2];
bool isect;
int tottri;
- float tri_cos[3][3];
- if (index != -1) {
- tottri = 0;
- uint b = 0;
- for (; b < kcd->objects_len; b++) {
- index -= tottri;
- ob = kcd->objects[b];
- em = BKE_editmesh_from_object(ob);
- tottri = em->tottri;
- if (index < tottri) {
- ltri = em->looptris[index];
- break;
- }
+ tottri = 0;
+ uint b = 0;
+ for (; b < kcd->objects_len; b++) {
+ index -= tottri;
+ ob = kcd->objects[b];
+ em = BKE_editmesh_from_object(ob);
+ tottri = em->tottri;
+ if (index < tottri) {
+ ltri = em->looptris[index];
+ break;
}
+ }
- if (kcd->bvh.filter_cb) {
- if (!kcd->bvh.filter_cb(ltri[0]->f, kcd->bvh.filter_data)) {
- return;
- }
+ if (kcd->bvh.filter_cb) {
+ if (!kcd->bvh.filter_cb(ltri[0]->f, kcd->bvh.filter_data)) {
+ return;
}
+ }
- knife_bm_tri_cagecos_get_worldspace(kcd, b, index, tri_cos);
-
- isect =
- (ray->radius > 0.0f ?
- isect_ray_tri_epsilon_v3(ray->origin,
- ray->direction,
- tri_cos[0],
- tri_cos[1],
- tri_cos[2],
- &dist,
- uv,
- ray->radius) :
+ float tri_cos[3][3];
+ knife_bm_tri_cagecos_get_worldspace(kcd, b, index, tri_cos);
+ isect = (ray->radius > 0.0f ?
+ isect_ray_tri_epsilon_v3(
+ ray->origin, ray->direction, UNPACK3(tri_cos), &dist, uv, ray->radius) :
#ifdef USE_KDOPBVH_WATERTIGHT
- isect_ray_tri_watertight_v3(
- ray->origin, ray->isect_precalc, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
+ isect_ray_tri_watertight_v3(
+ ray->origin, ray->isect_precalc, UNPACK3(tri_cos), &dist, uv));
#else
- isect_ray_tri_v3(
- ray->origin, ray->direction, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
+ isect_ray_tri_v3(ray->origin, ray->direction, UNPACK3(tri_cos), &dist, uv);
#endif
- if (isect && dist < hit->dist) {
- hit->dist = dist;
- hit->index = index;
+ if (isect && dist < hit->dist) {
+ hit->dist = dist;
+ hit->index = index;
- copy_v3_v3(hit->no, ltri[0]->f->no);
+ copy_v3_v3(hit->no, ltri[0]->f->no);
- madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
- kcd->bvh.looptris = em->looptris;
- copy_v2_v2(kcd->bvh.uv, uv);
- kcd->bvh.base_index = b;
- }
+ kcd->bvh.looptris = em->looptris;
+ copy_v2_v2(kcd->bvh.uv, uv);
+ kcd->bvh.base_index = b;
}
}
@@ -1383,7 +1379,6 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd,
uint *r_base_index)
{
BMFace *face;
- BMLoop **ltri;
BVHTreeRayHit hit;
const float dist = r_dist ? *r_dist : FLT_MAX;
hit.dist = dist;
@@ -1397,8 +1392,9 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd,
/* Hits returned in world space. */
if (r_hitout) {
- ltri = kcd->bvh.looptris[hit.index];
- interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, kcd->bvh.uv);
+ float tri_cos[3][3];
+ knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.base_index, hit.index, tri_cos);
+ interp_v3_v3v3v3_uv(r_hitout, UNPACK3(tri_cos), kcd->bvh.uv);
if (r_cagehit) {
copy_v3_v3(r_cagehit, hit.co);
@@ -1434,7 +1430,6 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd,
kcd->bvh.filter_data = filter_userdata;
BMFace *face;
- BMLoop **ltri;
BVHTreeRayHit hit;
const float dist = r_dist ? *r_dist : FLT_MAX;
hit.dist = dist;
@@ -1451,8 +1446,9 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd,
/* Hits returned in world space. */
if (r_hitout) {
- ltri = kcd->bvh.looptris[hit.index];
- interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, kcd->bvh.uv);
+ float tri_cos[3][3];
+ knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.base_index, hit.index, tri_cos);
+ interp_v3_v3v3v3_uv(r_hitout, UNPACK3(tri_cos), kcd->bvh.uv);
if (r_cagehit) {
copy_v3_v3(r_cagehit, hit.co);
@@ -1978,29 +1974,30 @@ static void prepare_linehits_for_cut(KnifeTool_OpData *kcd)
* Also remove all but one of a series of vertex hits for the same vertex. */
for (int i = 0; i < n; i++) {
KnifeLineHit *lhi = &linehits[i];
- if (lhi->v) {
- for (int j = i - 1; j >= 0; j--) {
- KnifeLineHit *lhj = &linehits[j];
- if (!lhj->kfe || fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG ||
- fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) {
- break;
- }
+ if (lhi->v == NULL) {
+ continue;
+ }
- if (lhi->kfe == lhj->kfe) {
- lhj->l = -1.0f;
- is_double = true;
- }
+ for (int j = i - 1; j >= 0; j--) {
+ KnifeLineHit *lhj = &linehits[j];
+ if (!lhj->kfe || fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG ||
+ fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) {
+ break;
}
- for (int j = i + 1; j < n; j++) {
- KnifeLineHit *lhj = &linehits[j];
- if (fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG ||
- fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) {
- break;
- }
- if ((lhj->kfe && (lhi->kfe == lhj->kfe)) || (lhi->v == lhj->v)) {
- lhj->l = -1.0f;
- is_double = true;
- }
+
+ if (lhi->kfe == lhj->kfe) {
+ lhj->l = -1.0f;
+ is_double = true;
+ }
+ }
+ for (int j = i + 1; j < n; j++) {
+ KnifeLineHit *lhj = &linehits[j];
+ if (fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG || fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) {
+ break;
+ }
+ if ((lhj->kfe && (lhi->kfe == lhj->kfe)) || (lhi->v == lhj->v)) {
+ lhj->l = -1.0f;
+ is_double = true;
}
}
}
@@ -2272,11 +2269,12 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMesh *bm, BMFace *f, Li
/* Remove dangling edges, not essential - but nice for users. */
for (i = 0; i < edge_array_len_orig; i++) {
- if (kfe_array[i]) {
- if (BM_edge_is_wire(kfe_array[i]->e)) {
- BM_edge_kill(bm, kfe_array[i]->e);
- kfe_array[i]->e = NULL;
- }
+ if (kfe_array[i] == NULL) {
+ continue;
+ }
+ if (BM_edge_is_wire(kfe_array[i]->e)) {
+ BM_edge_kill(bm, kfe_array[i]->e);
+ kfe_array[i]->e = NULL;
}
}
@@ -2588,7 +2586,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
BLI_assert(tri_i >= 0 && tri_i < tottri);
for (; tri_i < tottri; tri_i++) {
- float lv[3][3];
+ float tri_cos[3][3];
float ray_tri_uv[2];
tri = em->looptris[tri_i];
@@ -2596,22 +2594,22 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
break;
}
- knife_bm_tri_cagecos_get_worldspace(kcd, base_index, tri_i, lv);
+ knife_bm_tri_cagecos_get_worldspace(kcd, base_index, tri_i, tri_cos);
/* Using epsilon test in case ray is directly through an internal
* tessellation edge and might not hit either tessellation tri with
* an exact test;
* We will exclude hits near real edges by a later test. */
if (isect_ray_tri_epsilon_v3(
- v1, raydir, lv[0], lv[1], lv[2], &lambda, ray_tri_uv, KNIFE_FLT_EPS)) {
+ v1, raydir, UNPACK3(tri_cos), &lambda, ray_tri_uv, KNIFE_FLT_EPS)) {
/* Check if line coplanar with tri. */
- normal_tri_v3(tri_norm, lv[0], lv[1], lv[2]);
- plane_from_point_normal_v3(tri_plane, lv[0], tri_norm);
+ normal_tri_v3(tri_norm, UNPACK3(tri_cos));
+ plane_from_point_normal_v3(tri_plane, tri_cos[0], tri_norm);
if ((dist_squared_to_plane_v3(v1, tri_plane) < KNIFE_FLT_EPS) &&
(dist_squared_to_plane_v3(v2, tri_plane) < KNIFE_FLT_EPS)) {
return false;
}
- interp_v3_v3v3v3_uv(hit_cageco, lv[0], lv[1], lv[2], ray_tri_uv);
+ interp_v3_v3v3v3_uv(hit_cageco, UNPACK3(tri_cos), ray_tri_uv);
/* Now check that far enough away from verts and edges. */
list = knife_get_face_kedges(kcd, ob, base_index, f);
for (ref = list->first; ref; ref = ref->next) {
@@ -3810,7 +3808,7 @@ static void knife_reset_snap_angle_input(KnifeTool_OpData *kcd)
* If scene orientation is set to anything other than global it takes priority.
* Otherwise kcd->constrain_axis_mode is used.
*/
-static void knife_constrain_axis(bContext *C, KnifeTool_OpData *kcd)
+static void knife_constrain_axis(KnifeTool_OpData *kcd)
{
/* Obtain current mouse position in world space. */
float curr_cage_adjusted[3];
@@ -3819,7 +3817,7 @@ static void knife_constrain_axis(bContext *C, KnifeTool_OpData *kcd)
/* Constrain axes. */
Scene *scene = kcd->scene;
- ViewLayer *view_layer = CTX_data_view_layer(C);
+ ViewLayer *view_layer = kcd->vc.view_layer;
Object *obedit = (kcd->prev.ob) ? kcd->prev.ob : kcd->vc.obedit;
RegionView3D *rv3d = kcd->region->regiondata;
const short scene_orientation = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
@@ -3871,7 +3869,7 @@ static void knife_constrain_axis(bContext *C, KnifeTool_OpData *kcd)
* In this case the selection-buffer is used to select the face,
* then the closest `vert` or `edge` is set, and those will enable `is_co_set`.
*/
-static bool knife_snap_update_from_mval(bContext *C, KnifeTool_OpData *kcd, const float mval[2])
+static bool knife_snap_update_from_mval(KnifeTool_OpData *kcd, const float mval[2])
{
knife_pos_data_clear(&kcd->curr);
copy_v2_v2(kcd->curr.mval, mval);
@@ -3894,7 +3892,7 @@ static bool knife_snap_update_from_mval(bContext *C, KnifeTool_OpData *kcd, cons
}
if (kcd->axis_constrained) {
- knife_constrain_axis(C, kcd);
+ knife_constrain_axis(kcd);
}
}
@@ -4075,8 +4073,7 @@ static void knife_init_colors(KnifeColors *colors)
}
/* called when modal loop selection gets set up... */
-static void knifetool_init(bContext *C,
- ViewContext *vc,
+static void knifetool_init(ViewContext *vc,
KnifeTool_OpData *kcd,
const bool only_select,
const bool cut_through,
@@ -4099,7 +4096,7 @@ static void knifetool_init(bContext *C,
kcd->region = vc->region;
kcd->objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
- CTX_data_view_layer(C), CTX_wm_view3d(C), &kcd->objects_len);
+ vc->view_layer, vc->v3d, &kcd->objects_len);
Object *ob;
BMEditMesh *em;
@@ -4241,14 +4238,14 @@ static void knifetool_exit(wmOperator *op)
/** \name Mouse-Moving Event Updates
* \{ */
-/* Update active knife edge/vert pointers. */
-static int knife_update_active(bContext *C, KnifeTool_OpData *kcd)
+/** Update active knife edge/vert pointers. */
+static int knife_update_active(KnifeTool_OpData *kcd)
{
/* If no hits are found this would normally default to (0, 0, 0) so instead
* get a point at the mouse ray closest to the previous point.
* Note that drawing lines in `free-space` isn't properly supported
* but there's no guarantee (0, 0, 0) has any geometry either - campbell */
- if (!knife_snap_update_from_mval(C, kcd, kcd->mval)) {
+ if (!knife_snap_update_from_mval(kcd, kcd->mval)) {
float origin[3];
float origin_ofs[3];
@@ -4269,20 +4266,20 @@ static int knife_update_active(bContext *C, KnifeTool_OpData *kcd)
return 1;
}
-static void knifetool_update_mval(bContext *C, KnifeTool_OpData *kcd, const float mval[2])
+static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2])
{
knife_recalc_ortho(kcd);
copy_v2_v2(kcd->mval, mval);
- if (knife_update_active(C, kcd)) {
+ if (knife_update_active(kcd)) {
ED_region_tag_redraw(kcd->region);
}
}
-static void knifetool_update_mval_i(bContext *C, KnifeTool_OpData *kcd, const int mval_i[2])
+static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2])
{
const float mval[2] = {UNPACK2(mval_i)};
- knifetool_update_mval(C, kcd, mval);
+ knifetool_update_mval(kcd, mval);
}
/** \} */
@@ -4291,33 +4288,18 @@ static void knifetool_update_mval_i(bContext *C, KnifeTool_OpData *kcd, const in
/** \name Finalization
* \{ */
-/* Called on tool confirmation. */
-static void knifetool_finish_ex(KnifeTool_OpData *kcd)
+static void knifetool_finish_single_pre(KnifeTool_OpData *kcd, Object *ob)
{
- Object *ob;
- BMEditMesh *em;
- for (uint b = 0; b < kcd->objects_len; b++) {
- ob = kcd->objects[b];
- em = BKE_editmesh_from_object(ob);
-
- knife_make_cuts(kcd, ob);
-
- EDBM_selectmode_flush(em);
- EDBM_update(ob->data,
- &(const struct EDBMUpdate_Params){
- .calc_looptri = true,
- .calc_normals = true,
- .is_destructive = true,
- });
- }
+ knife_make_cuts(kcd, ob);
}
-static void knifetool_finish_single_ex(KnifeTool_OpData *kcd, Object *ob, uint UNUSED(base_index))
+/**
+ * A post version is needed to to delay recalculating tessellation after making cuts.
+ * Without this, knife-project can't use the BVH tree to select geometry after a cut, see: T98349.
+ */
+static void knifetool_finish_single_post(KnifeTool_OpData *UNUSED(kcd), Object *ob)
{
- knife_make_cuts(kcd, ob);
-
BMEditMesh *em = BKE_editmesh_from_object(ob);
-
EDBM_selectmode_flush(em);
EDBM_update(ob->data,
&(const struct EDBMUpdate_Params){
@@ -4327,6 +4309,16 @@ static void knifetool_finish_single_ex(KnifeTool_OpData *kcd, Object *ob, uint U
});
}
+/* Called on tool confirmation. */
+static void knifetool_finish_ex(KnifeTool_OpData *kcd)
+{
+ for (uint b = 0; b < kcd->objects_len; b++) {
+ Object *ob = kcd->objects[b];
+ knifetool_finish_single_pre(kcd, ob);
+ knifetool_finish_single_post(kcd, ob);
+ }
+}
+
static void knifetool_finish(wmOperator *op)
{
KnifeTool_OpData *kcd = op->customdata;
@@ -4445,7 +4437,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
snapping_increment_temp <= KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
kcd->angle_snapping_increment = snapping_increment_temp;
}
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->region);
return OPERATOR_RUNNING_MODAL;
@@ -4486,7 +4478,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
knifetool_undo(kcd);
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
ED_region_tag_redraw(kcd->region);
handled = true;
break;
@@ -4494,7 +4486,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
kcd->snap_midpoints = true;
knife_recalc_ortho(kcd);
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->region);
do_refresh = true;
@@ -4504,7 +4496,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
kcd->snap_midpoints = false;
knife_recalc_ortho(kcd);
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->region);
do_refresh = true;
@@ -4538,7 +4530,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
RNA_float_get(op->ptr, "angle_snapping_increment"));
knifetool_disable_orientation_locking(kcd);
knife_reset_snap_angle_input(kcd);
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->region);
do_refresh = true;
@@ -4623,7 +4615,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
kcd->is_drag_undo = false;
/* Needed because the last face 'hit' is ignored when dragging. */
- knifetool_update_mval(C, kcd, kcd->curr.mval);
+ knifetool_update_mval(kcd, kcd->curr.mval);
}
ED_region_tag_redraw(kcd->region);
@@ -4636,14 +4628,14 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (kcd->is_drag_hold) {
kcd->is_drag_hold = false;
kcd->is_drag_undo = false;
- knifetool_update_mval(C, kcd, kcd->curr.mval);
+ knifetool_update_mval(kcd, kcd->curr.mval);
}
kcd->prev = kcd->curr;
kcd->curr = kcd->init;
knife_project_v2(kcd, kcd->curr.cage, kcd->curr.mval);
- knifetool_update_mval(C, kcd, kcd->curr.mval);
+ knifetool_update_mval(kcd, kcd->curr.mval);
knife_add_cut(kcd);
@@ -4679,7 +4671,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
case MOUSEMOVE: /* Mouse moved somewhere to select another loop. */
if (kcd->mode != MODE_PANNING) {
- knifetool_update_mval_i(C, kcd, event->mval);
+ knifetool_update_mval_i(kcd, event->mval);
if (kcd->is_drag_hold) {
if (kcd->totlinehit >= 2) {
@@ -4706,7 +4698,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
snapping_increment_temp <= KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
kcd->angle_snapping_increment = snapping_increment_temp;
}
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->region);
return OPERATOR_RUNNING_MODAL;
@@ -4761,7 +4753,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (do_refresh) {
/* We don't really need to update mval,
* but this happens to be the best way to refresh at the moment. */
- knifetool_update_mval_i(C, kcd, event->mval);
+ knifetool_update_mval_i(kcd, event->mval);
}
/* Keep going until the user confirms. */
@@ -4787,8 +4779,7 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* alloc new customdata */
kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
- knifetool_init(C,
- &vc,
+ knifetool_init(&vc,
kcd,
only_select,
cut_through,
@@ -4824,7 +4815,7 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_KNIFE);
WM_event_add_modal_handler(C, op);
- knifetool_update_mval_i(C, kcd, event->mval);
+ knifetool_update_mval_i(kcd, event->mval);
if (wait_for_input == false) {
/* Avoid copy-paste logic. */
@@ -4942,7 +4933,7 @@ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
return false;
}
-void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_through)
+void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_through)
{
KnifeTool_OpData *kcd;
@@ -4957,8 +4948,7 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
kcd = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
- knifetool_init(C,
- vc,
+ knifetool_init(vc,
kcd,
only_select,
cut_through,
@@ -4984,7 +4974,7 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
int i;
for (i = 0; i < mval_tot; i++) {
- knifetool_update_mval(C, kcd, mval_fl[i]);
+ knifetool_update_mval(kcd, mval_fl[i]);
if (i == 0) {
knife_start_cut(kcd);
kcd->mode = MODE_DRAGGING;
@@ -5012,7 +5002,7 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
BM_mesh_elem_hflag_enable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false);
}
- knifetool_finish_single_ex(kcd, ob, b);
+ knifetool_finish_single_pre(kcd, ob);
/* Tag faces inside! */
if (use_tag) {
@@ -5036,17 +5026,19 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
/* Tag all faces linked to cut edges. */
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
/* Check are we tagged?, then we are an original face. */
- if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) {
- BMFace *f;
- BMIter fiter;
- BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- float cent[3], cent_ss[2];
- BM_face_calc_point_in_face(f, cent);
- mul_m4_v3(ob->obmat, cent);
- knife_project_v2(kcd, cent, cent_ss);
- if (edbm_mesh_knife_point_isect(polys, cent_ss)) {
- BM_elem_flag_enable(f, BM_ELEM_TAG);
- }
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ BMFace *f;
+ BMIter fiter;
+ BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
+ float cent[3], cent_ss[2];
+ BM_face_calc_point_in_face(f, cent);
+ mul_m4_v3(ob->obmat, cent);
+ knife_project_v2(kcd, cent, cent_ss);
+ if (edbm_mesh_knife_point_isect(polys, cent_ss)) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
}
}
}
@@ -5056,43 +5048,45 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
BMFace *f;
keep_search = false;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_TAG) == false && (F_ISECT_IS_UNKNOWN(f))) {
- /* Am I connected to a tagged face via an un-tagged edge
- * (ie, not across a cut)? */
- BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
- BMLoop *l_iter = l_first;
- bool found = false;
-
- do {
- if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) {
- /* Now check if the adjacent faces is tagged. */
- BMLoop *l_radial_iter = l_iter->radial_next;
- if (l_radial_iter != l_iter) {
- do {
- if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) {
- found = true;
- }
- } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter &&
- (found == false));
- }
- }
- } while ((l_iter = l_iter->next) != l_first && (found == false));
-
- if (found) {
- float cent[3], cent_ss[2];
- BM_face_calc_point_in_face(f, cent);
- mul_m4_v3(ob->obmat, cent);
- knife_project_v2(kcd, cent, cent_ss);
- if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) &&
- edbm_mesh_knife_point_isect(polys, cent_ss)) {
- BM_elem_flag_enable(f, BM_ELEM_TAG);
- keep_search = true;
- }
- else {
- /* Don't lose time on this face again, set it as outside. */
- F_ISECT_SET_OUTSIDE(f);
+ if (BM_elem_flag_test(f, BM_ELEM_TAG) || !F_ISECT_IS_UNKNOWN(f)) {
+ continue;
+ }
+
+ /* Am I connected to a tagged face via an un-tagged edge
+ * (ie, not across a cut)? */
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+ bool found = false;
+
+ do {
+ if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) {
+ /* Now check if the adjacent faces is tagged. */
+ BMLoop *l_radial_iter = l_iter->radial_next;
+ if (l_radial_iter != l_iter) {
+ do {
+ if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) {
+ found = true;
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter &&
+ (found == false));
}
}
+ } while ((l_iter = l_iter->next) != l_first && (found == false));
+
+ if (found) {
+ float cent[3], cent_ss[2];
+ BM_face_calc_point_in_face(f, cent);
+ mul_m4_v3(ob->obmat, cent);
+ knife_project_v2(kcd, cent, cent_ss);
+ if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) &&
+ edbm_mesh_knife_point_isect(polys, cent_ss)) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ keep_search = true;
+ }
+ else {
+ /* Don't lose time on this face again, set it as outside. */
+ F_ISECT_SET_OUTSIDE(f);
+ }
}
}
} while (keep_search);
@@ -5101,6 +5095,10 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
#undef F_ISECT_SET_UNKNOWN
#undef F_ISECT_SET_OUTSIDE
}
+
+ /* Defer freeing data until the BVH tree is finished with, see: #point_is_visible and
+ * the doc-string for #knifetool_finish_single_post. */
+ knifetool_finish_single_post(kcd, ob);
}
knifetool_exit_ex(kcd);
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index bce46dd7cf7..c32b1fa99c0 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -142,7 +142,7 @@ static int knifeproject_exec(bContext *C, wmOperator *op)
ED_view3d_viewcontext_init_object(&vc, obedit);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- EDBM_mesh_knife(C, &vc, polys, true, cut_through);
+ EDBM_mesh_knife(&vc, polys, true, cut_through);
/* select only tagged faces */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index cafcc4ec578..feecefdb7ea 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -7032,6 +7032,14 @@ static void sort_bmelem_flag(bContext *C,
}
BM_mesh_remap(em->bm, map[0], map[1], map[2]);
+
+ EDBM_update(ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = (totelem[2] != 0),
+ .calc_normals = false,
+ .is_destructive = true,
+ });
+
DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc
index ae06cf4c3bd..67834bf05ce 100644
--- a/source/blender/editors/mesh/mesh_data.cc
+++ b/source/blender/editors/mesh/mesh_data.cc
@@ -241,7 +241,7 @@ void ED_mesh_uv_loop_reset(bContext *C, Mesh *me)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
}
-int ED_mesh_uv_texture_add(
+int ED_mesh_uv_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
/* NOTE: keep in sync with #ED_mesh_color_add. */
@@ -307,7 +307,7 @@ int ED_mesh_uv_texture_add(
return layernum_dst;
}
-void ED_mesh_uv_texture_ensure(Mesh *me, const char *name)
+void ED_mesh_uv_ensure(Mesh *me, const char *name)
{
BMEditMesh *em;
int layernum_dst;
@@ -317,18 +317,18 @@ void ED_mesh_uv_texture_ensure(Mesh *me, const char *name)
layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV);
if (layernum_dst == 0) {
- ED_mesh_uv_texture_add(me, name, true, true, nullptr);
+ ED_mesh_uv_add(me, name, true, true, nullptr);
}
}
else {
layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (layernum_dst == 0) {
- ED_mesh_uv_texture_add(me, name, true, true, nullptr);
+ ED_mesh_uv_add(me, name, true, true, nullptr);
}
}
}
-bool ED_mesh_uv_texture_remove_index(Mesh *me, const int n)
+bool ED_mesh_uv_remove_index(Mesh *me, const int n)
{
CustomData *ldata = GET_CD_DATA(me, ldata);
CustomDataLayer *cdlu;
@@ -348,24 +348,22 @@ bool ED_mesh_uv_texture_remove_index(Mesh *me, const int n)
return true;
}
-bool ED_mesh_uv_texture_remove_active(Mesh *me)
+bool ED_mesh_uv_remove_active(Mesh *me)
{
- /* texpoly/uv are assumed to be in sync */
CustomData *ldata = GET_CD_DATA(me, ldata);
const int n = CustomData_get_active_layer(ldata, CD_MLOOPUV);
if (n != -1) {
- return ED_mesh_uv_texture_remove_index(me, n);
+ return ED_mesh_uv_remove_index(me, n);
}
return false;
}
-bool ED_mesh_uv_texture_remove_named(Mesh *me, const char *name)
+bool ED_mesh_uv_remove_named(Mesh *me, const char *name)
{
- /* texpoly/uv are assumed to be in sync */
CustomData *ldata = GET_CD_DATA(me, ldata);
const int n = CustomData_get_named_layer(ldata, CD_MLOOPUV, name);
if (n != -1) {
- return ED_mesh_uv_texture_remove_index(me, n);
+ return ED_mesh_uv_remove_index(me, n);
}
return false;
}
@@ -373,7 +371,7 @@ bool ED_mesh_uv_texture_remove_named(Mesh *me, const char *name)
int ED_mesh_color_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
- /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
+ /* NOTE: keep in sync with #ED_mesh_uv_add. */
BMEditMesh *em;
int layernum;
@@ -516,7 +514,7 @@ static bool sculpt_vertex_color_remove_poll(bContext *C)
int ED_mesh_sculpt_color_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
- /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
+ /* NOTE: keep in sync with #ED_mesh_uv_add. */
BMEditMesh *em;
int layernum;
@@ -650,7 +648,7 @@ static int mesh_uv_texture_add_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_context(C);
Mesh *me = static_cast<Mesh *>(ob->data);
- if (ED_mesh_uv_texture_add(me, nullptr, true, true, op->reports) == -1) {
+ if (ED_mesh_uv_add(me, nullptr, true, true, op->reports) == -1) {
return OPERATOR_CANCELLED;
}
@@ -683,7 +681,7 @@ static int mesh_uv_texture_remove_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = ED_object_context(C);
Mesh *me = static_cast<Mesh *>(ob->data);
- if (!ED_mesh_uv_texture_remove_active(me)) {
+ if (!ED_mesh_uv_remove_active(me)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 1ee4be50322..303234df48c 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -174,8 +174,7 @@ void MESH_OT_knife_project(struct wmOperatorType *ot);
/**
* \param use_tag: When set, tag all faces inside the polylines.
*/
-void EDBM_mesh_knife(struct bContext *C,
- struct ViewContext *vc,
+void EDBM_mesh_knife(struct ViewContext *vc,
struct LinkNode *polys,
bool use_tag,
bool cut_through);
diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc
index fafccf68f03..9e28e1bafdd 100644
--- a/source/blender/editors/mesh/meshtools.cc
+++ b/source/blender/editors/mesh/meshtools.cc
@@ -418,7 +418,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
}
totcol = ob->totcol;
- /* obact materials in new main array, is nicer start! */
+ /* Active object materials in new main array, is nicer start! */
for (a = 0; a < ob->totcol; a++) {
matar[a] = BKE_object_material_get(ob, a + 1);
id_us_plus((ID *)matar[a]);
diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index ac8ab834cb7..422aaa03120 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -1265,9 +1265,9 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot)
"Relative Path",
"Select the file relative to the blend file");
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
- prop = RNA_def_string(
- ot->srna, "name", nullptr, MAX_ID_NAME - 2, "Name", "Image name to assign");
- RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
+
+ WM_operator_properties_id_lookup(ot, true);
+
ED_object_add_generic_props(ot, false);
}
@@ -1651,19 +1651,12 @@ static std::optional<CollectionAddInfo> collection_add_info_get_from_op(bContext
Main *bmain = CTX_data_main(C);
PropertyRNA *prop_location = RNA_struct_find_property(op->ptr, "location");
- PropertyRNA *prop_session_uuid = RNA_struct_find_property(op->ptr, "session_uuid");
- PropertyRNA *prop_name = RNA_struct_find_property(op->ptr, "name");
+
+ add_info.collection = reinterpret_cast<Collection *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_GR));
bool update_location_if_necessary = false;
- if (prop_name && RNA_property_is_set(op->ptr, prop_name)) {
- char name[MAX_ID_NAME - 2];
- RNA_property_string_get(op->ptr, prop_name, name);
- add_info.collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
- update_location_if_necessary = true;
- }
- else if (RNA_property_is_set(op->ptr, prop_session_uuid)) {
- const uint32_t session_uuid = (uint32_t)RNA_property_int_get(op->ptr, prop_session_uuid);
- add_info.collection = (Collection *)BKE_libblock_find_session_uuid(bmain, ID_GR, session_uuid);
+ if (add_info.collection) {
update_location_if_necessary = true;
}
else {
@@ -1736,8 +1729,7 @@ static int object_instance_add_invoke(bContext *C, wmOperator *op, const wmEvent
RNA_int_set(op->ptr, "drop_y", event->xy[1]);
}
- if (!RNA_struct_property_is_set(op->ptr, "name") &&
- !RNA_struct_property_is_set(op->ptr, "session_uuid")) {
+ if (!WM_operator_properties_id_lookup_is_set(op->ptr)) {
return WM_enum_search_invoke(C, op, event);
}
return op->type->exec(C, op);
@@ -1769,16 +1761,7 @@ void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
ot->prop = prop;
ED_object_add_generic_props(ot, false);
- prop = RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the collection to add",
- INT32_MIN,
- INT32_MAX);
- RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
+ WM_operator_properties_id_lookup(ot, false);
object_add_drop_xy_props(ot);
}
@@ -1875,16 +1858,7 @@ void OBJECT_OT_collection_external_asset_drop(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
- prop = RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the collection to add",
- INT32_MIN,
- INT32_MAX);
- RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
+ WM_operator_properties_id_lookup(ot, false);
ED_object_add_generic_props(ot, false);
@@ -1920,18 +1894,12 @@ static int object_data_instance_add_exec(bContext *C, wmOperator *op)
ushort local_view_bits;
float loc[3], rot[3];
- PropertyRNA *prop_name = RNA_struct_find_property(op->ptr, "name");
PropertyRNA *prop_type = RNA_struct_find_property(op->ptr, "type");
PropertyRNA *prop_location = RNA_struct_find_property(op->ptr, "location");
- /* These shouldn't fail when created by outliner dropping as it checks the ID is valid. */
- if (!RNA_property_is_set(op->ptr, prop_name) || !RNA_property_is_set(op->ptr, prop_type)) {
- return OPERATOR_CANCELLED;
- }
const short id_type = RNA_property_enum_get(op->ptr, prop_type);
- char name[MAX_ID_NAME - 2];
- RNA_property_string_get(op->ptr, prop_name, name);
- id = BKE_libblock_find_name(bmain, id_type, name);
+ id = WM_operator_properties_id_lookup_from_name_or_session_uuid(
+ bmain, op->ptr, (ID_Type)id_type);
if (id == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -1974,7 +1942,7 @@ void OBJECT_OT_data_instance_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_string(ot->srna, "name", "Name", MAX_ID_NAME - 2, "Name", "ID name to add");
+ WM_operator_properties_id_lookup(ot, true);
PropertyRNA *prop = RNA_def_enum(ot->srna, "type", rna_enum_id_type_items, 0, "Type", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
ED_object_add_generic_props(ot, false);
@@ -3802,15 +3770,13 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *basen;
- Object *ob;
const bool linked = RNA_boolean_get(op->ptr, "linked");
const eDupli_ID_Flags dupflag = (linked) ? (eDupli_ID_Flags)0 : (eDupli_ID_Flags)U.dupflag;
- char name[MAX_ID_NAME - 2];
- /* find object, create fake base */
- RNA_string_get(op->ptr, "name", name);
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name);
+ /* Find object, create fake base. */
+
+ Object *ob = reinterpret_cast<Object *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_OB));
if (ob == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Object not found");
@@ -3818,7 +3784,7 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
}
/* prepare dupli */
- basen = object_add_duplicate_internal(
+ Base *basen = object_add_duplicate_internal(
bmain,
scene,
view_layer,
@@ -3898,7 +3864,7 @@ void OBJECT_OT_add_named(wmOperatorType *ot)
"Linked",
"Duplicate object but not object data, linking to the original data");
- RNA_def_string(ot->srna, "name", nullptr, MAX_ID_NAME - 2, "Name", "Object name to add");
+ WM_operator_properties_id_lookup(ot, true);
prop = RNA_def_float_matrix(
ot->srna, "matrix", 4, 4, nullptr, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
@@ -3920,14 +3886,11 @@ static int object_transform_to_mouse_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob;
- if (RNA_struct_property_is_set(op->ptr, "name")) {
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name);
- }
- else {
+ Object *ob = reinterpret_cast<Object *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_OB));
+
+ if (!ob) {
ob = OBACT(view_layer);
}
@@ -4006,12 +3969,25 @@ void OBJECT_OT_transform_to_mouse(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
- RNA_def_string(ot->srna,
- "name",
- nullptr,
- MAX_ID_NAME - 2,
- "Name",
- "Object name to place (when unset use the active object)");
+ prop = RNA_def_string(
+ ot->srna,
+ "name",
+ nullptr,
+ MAX_ID_NAME - 2,
+ "Name",
+ "Object name to place (uses the active object when this and 'session_uuid' are unset)");
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the object to place (uses the active object when this and "
+ "'name' are unset)",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
prop = RNA_def_float_matrix(
ot->srna, "matrix", 4, 4, nullptr, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index adac1479c7e..e5dd9fb2c8b 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -1243,6 +1243,9 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op)
ED_objects_recalculate_paths_selected(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL);
+ /* Note: the notifier below isn't actually correct, but kept around just to be on the safe side.
+ * If further testing shows it's not necessary (for both bones and objects) removal is fine. */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM | ND_POSE, NULL);
return OPERATOR_FINISHED;
@@ -1312,6 +1315,9 @@ static int object_update_paths_exec(bContext *C, wmOperator *op)
ED_objects_recalculate_paths_selected(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL);
+ /* Note: the notifier below isn't actually correct, but kept around just to be on the safe side.
+ * If further testing shows it's not necessary (for both bones and objects) removal is fine. */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM | ND_POSE, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index eed0a63565e..963e92942bb 100644
--- a/source/blender/editors/object/object_modifier.cc
+++ b/source/blender/editors/object/object_modifier.cc
@@ -3399,6 +3399,7 @@ static int geometry_node_tree_copy_assign_exec(bContext *C, wmOperator *UNUSED(o
nmd->node_group = new_tree;
id_us_min(&tree->id);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index a7efb45e803..abbde3b5b3a 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2267,8 +2267,12 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
ID *id_root = NULL;
bool is_override_instancing_object = false;
- GSet *user_overrides_objects_uids = BLI_gset_new(
- BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+ const bool do_fully_editable = RNA_boolean_get(op->ptr, "do_fully_editable");
+
+ GSet *user_overrides_objects_uids = do_fully_editable ? NULL :
+ BLI_gset_new(BLI_ghashutil_inthash_p,
+ BLI_ghashutil_intcmp,
+ __func__);
bool user_overrides_from_selected_objects = false;
if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL &&
@@ -2316,7 +2320,10 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
user_overrides_from_selected_objects = true;
}
- if (user_overrides_from_selected_objects) {
+ if (do_fully_editable) {
+ /* Pass. */
+ }
+ else if (user_overrides_from_selected_objects) {
/* Only selected objects can be 'user overrides'. */
FOREACH_SELECTED_OBJECT_BEGIN (view_layer, CTX_wm_view3d(C), ob_iter) {
BLI_gset_add(user_overrides_objects_uids, POINTER_FROM_UINT(ob_iter->id.session_uuid));
@@ -2336,25 +2343,34 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
ID *id_root_override;
- const bool success = BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id_root, id_root, &obact->id, &id_root_override);
-
- /* Define liboverrides from selected/validated objects as user defined. */
- ID *id_hierarchy_root_override = id_root_override->override_library->hierarchy_root;
- ID *id_iter;
- FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
- if (ID_IS_LINKED(id_iter) || !ID_IS_OVERRIDE_LIBRARY_REAL(id_iter) ||
- id_iter->override_library->hierarchy_root != id_hierarchy_root_override) {
- continue;
- }
- if (BLI_gset_haskey(user_overrides_objects_uids,
- POINTER_FROM_UINT(id_iter->override_library->reference->session_uuid))) {
- id_iter->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ const bool success = BKE_lib_override_library_create(bmain,
+ scene,
+ view_layer,
+ NULL,
+ id_root,
+ id_root,
+ &obact->id,
+ &id_root_override,
+ do_fully_editable);
+
+ if (!do_fully_editable) {
+ /* Define liboverrides from selected/validated objects as user defined. */
+ ID *id_hierarchy_root_override = id_root_override->override_library->hierarchy_root;
+ ID *id_iter;
+ FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
+ if (ID_IS_LINKED(id_iter) || !ID_IS_OVERRIDE_LIBRARY_REAL(id_iter) ||
+ id_iter->override_library->hierarchy_root != id_hierarchy_root_override) {
+ continue;
+ }
+ if (BLI_gset_haskey(user_overrides_objects_uids,
+ POINTER_FROM_UINT(id_iter->override_library->reference->session_uuid))) {
+ id_iter->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ }
}
- }
- FOREACH_MAIN_ID_END;
+ FOREACH_MAIN_ID_END;
- BLI_gset_free(user_overrides_objects_uids, NULL);
+ BLI_gset_free(user_overrides_objects_uids, NULL);
+ }
/* Remove the instance empty from this scene, the items now have an overridden collection
* instead. */
@@ -2468,6 +2484,13 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot)
RNA_def_enum_funcs(prop, make_override_collections_of_linked_object_itemf);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
ot->prop = prop;
+
+ prop = RNA_def_boolean(ot->srna,
+ "do_fully_editable",
+ false,
+ "Create Fully Editable",
+ "Make all created override data-blocks fully editable");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/** \} */
@@ -2582,9 +2605,7 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
/** \name Drop Named Material on Object Operator
* \{ */
-char *ED_object_ot_drop_named_material_tooltip(bContext *C,
- PointerRNA *properties,
- const int mval[2])
+char *ED_object_ot_drop_named_material_tooltip(bContext *C, const char *name, const int mval[2])
{
int mat_slot = 0;
Object *ob = ED_view3d_give_material_slot_under_cursor(C, mval, &mat_slot);
@@ -2593,9 +2614,6 @@ char *ED_object_ot_drop_named_material_tooltip(bContext *C,
}
mat_slot = max_ii(mat_slot, 1);
- char name[MAX_ID_NAME - 2];
- RNA_string_get(properties, "name", name);
-
Material *prev_mat = BKE_object_material_get(ob, mat_slot);
char *result;
@@ -2617,11 +2635,9 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot);
mat_slot = max_ii(mat_slot, 1);
- Material *ma;
- char name[MAX_ID_NAME - 2];
+ Material *ma = (Material *)WM_operator_properties_id_lookup_from_name_or_session_uuid(
+ bmain, op->ptr, ID_MA);
- RNA_string_get(op->ptr, "name", name);
- ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name);
if (ob == NULL || ma == NULL) {
return OPERATOR_CANCELLED;
}
@@ -2651,7 +2667,7 @@ void OBJECT_OT_drop_named_material(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
- RNA_def_string(ot->srna, "name", "Material", MAX_ID_NAME - 2, "Name", "Material name to assign");
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index 04ae6c62aee..d7f4b71d2d0 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -179,7 +179,7 @@ struct AddOperationExecutor {
curves_sculpt_ = scene_->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
brush_settings_ = brush_->curves_sculpt_settings;
- brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_re_ = brush_radius_get(*scene_, *brush_, stroke_extension);
brush_pos_re_ = stroke_extension.mouse_position;
use_front_face_ = brush_->flag & BRUSH_FRONTFACE;
@@ -700,10 +700,9 @@ struct AddOperationExecutor {
for (const NeighborInfo &neighbor : neighbors) {
const IndexRange neighbor_points = curves_->points_for_curve(neighbor.index);
float neighbor_length = 0.0f;
- const int tot_segments = neighbor_points.size() - 1;
- for (const int segment_i : IndexRange(tot_segments)) {
- const float3 &p1 = positions_cu[neighbor_points[segment_i]];
- const float3 &p2 = positions_cu[neighbor_points[segment_i] + 1];
+ for (const int segment_i : neighbor_points.drop_back(1)) {
+ const float3 &p1 = positions_cu[segment_i];
+ const float3 &p2 = positions_cu[segment_i + 1];
neighbor_length += math::distance(p1, p2);
}
length_sum += neighbor.weight * neighbor_length;
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
index 9ebbf72806e..92ce6ba3153 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
@@ -94,11 +94,30 @@ static std::optional<float3> find_curves_brush_position(const CurvesGeometry &cu
for (const int curve_i : curves_range) {
const IndexRange points = curves.points_for_curve(curve_i);
- const int tot_segments = points.size() - 1;
- for (const int segment_i : IndexRange(tot_segments)) {
- const float3 &p1_cu = positions[points[segment_i]];
- const float3 &p2_cu = positions[points[segment_i] + 1];
+ if (points.size() == 1) {
+ const float3 &pos_cu = positions[points.first()];
+
+ const float depth_sq_cu = math::distance_squared(ray_start_cu, pos_cu);
+ if (depth_sq_cu > max_depth_sq_cu) {
+ continue;
+ }
+
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(&region, pos_cu, pos_re, projection.values);
+
+ BrushPositionCandidate candidate;
+ candidate.position_cu = pos_cu;
+ candidate.depth_sq_cu = depth_sq_cu;
+ candidate.distance_sq_re = math::distance_squared(brush_pos_re, pos_re);
+
+ update_if_better(best_candidate, candidate);
+ continue;
+ }
+
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions[segment_i];
+ const float3 &p2_cu = positions[segment_i + 1];
float2 p1_re, p2_re;
ED_view3d_project_float_v2_m4(&region, p1_cu, p1_re, projection.values);
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
index cecb13fbf7f..1fcab2290e8 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
@@ -86,7 +86,8 @@ struct CombOperationExecutor {
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
- float brush_radius_re_;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
float brush_strength_;
eBrushFalloffShape falloff_shape_;
@@ -126,8 +127,9 @@ struct CombOperationExecutor {
curves_sculpt_ = scene_->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
- brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
- brush_strength_ = BKE_brush_alpha_get(scene_, brush_);
+ brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
curves_to_world_mat_ = object_->obmat;
world_to_curves_mat_ = curves_to_world_mat_.inverted();
@@ -212,7 +214,8 @@ struct CombOperationExecutor {
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
- const float brush_radius_sq_re = pow2f(brush_radius_re_);
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
Vector<int> &local_changed_curves = r_changed_curves.local();
@@ -236,7 +239,7 @@ struct CombOperationExecutor {
const float distance_to_brush_re = std::sqrt(distance_to_brush_sq_re);
/* A falloff that is based on how far away the point is from the stroke. */
const float radius_falloff = BKE_brush_curve_strength(
- brush_, distance_to_brush_re, brush_radius_re_);
+ brush_, distance_to_brush_re, brush_radius_re);
/* Combine the falloff and brush strength. */
const float weight = brush_strength_ * radius_falloff;
@@ -280,7 +283,7 @@ struct CombOperationExecutor {
const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
- const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -342,7 +345,7 @@ struct CombOperationExecutor {
void initialize_spherical_brush_reference_point()
{
std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_re_);
+ *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
index 9446f38891e..323e99df099 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
@@ -50,8 +50,6 @@ using blender::bke::CurvesGeometry;
class DeleteOperation : public CurvesSculptStrokeOperation {
private:
- float2 brush_pos_prev_re_;
-
CurvesBrush3D brush_3d_;
friend struct DeleteOperationExecutor;
@@ -74,17 +72,16 @@ struct DeleteOperationExecutor {
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
- float brush_radius_re_;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
float2 brush_pos_re_;
- float2 brush_pos_prev_re_;
float4x4 curves_to_world_mat_;
float4x4 world_to_curves_mat_;
void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
{
- BLI_SCOPED_DEFER([&]() { self.brush_pos_prev_re_ = stroke_extension.mouse_position; });
self_ = &self;
depsgraph_ = CTX_data_depsgraph_pointer(&C);
@@ -99,11 +96,10 @@ struct DeleteOperationExecutor {
curves_sculpt_ = scene_->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
- brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
brush_pos_re_ = stroke_extension.mouse_position;
- brush_pos_prev_re_ = stroke_extension.is_first ? stroke_extension.mouse_position :
- self.brush_pos_prev_re_;
curves_to_world_mat_ = object_->obmat;
world_to_curves_mat_ = curves_to_world_mat_.inverted();
@@ -159,9 +155,23 @@ struct DeleteOperationExecutor {
Span<float3> positions_cu = curves_->positions();
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) {
for (const int curve_i : curve_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
+ if (points.size() == 1) {
+ const float3 pos_cu = brush_transform_inv * positions_cu[points.first()];
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(region_, pos_cu, pos_re, projection.values);
+
+ if (math::distance_squared(brush_pos_re_, pos_re) <= brush_radius_sq_re) {
+ curves_to_delete[curve_i] = true;
+ }
+ continue;
+ }
+
for (const int segment_i : points.drop_back(1)) {
const float3 pos1_cu = brush_transform_inv * positions_cu[segment_i];
const float3 pos2_cu = brush_transform_inv * positions_cu[segment_i + 1];
@@ -170,8 +180,9 @@ struct DeleteOperationExecutor {
ED_view3d_project_float_v2_m4(region_, pos1_cu, pos1_re, projection.values);
ED_view3d_project_float_v2_m4(region_, pos2_cu, pos2_re, projection.values);
- const float dist = dist_seg_seg_v2(pos1_re, pos2_re, brush_pos_prev_re_, brush_pos_re_);
- if (dist <= brush_radius_re_) {
+ const float dist_sq_re = dist_squared_to_line_segment_v2(
+ brush_pos_re_, pos1_re, pos2_re);
+ if (dist_sq_re <= brush_radius_sq_re) {
curves_to_delete[curve_i] = true;
break;
}
@@ -185,55 +196,48 @@ struct DeleteOperationExecutor {
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
- float3 brush_start_wo, brush_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
- brush_pos_prev_re_,
- brush_start_wo);
+ float3 brush_wo;
ED_view3d_win_to_3d(v3d_,
region_,
curves_to_world_mat_ * self_->brush_3d_.position_cu,
brush_pos_re_,
- brush_end_wo);
- const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
- const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+ brush_wo);
+ const float3 brush_cu = world_to_curves_mat_ * brush_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
- this->delete_spherical(
- brush_transform * brush_start_cu, brush_transform * brush_end_cu, curves_to_delete);
+ this->delete_spherical(brush_transform * brush_cu, curves_to_delete);
}
}
- void delete_spherical(const float3 &brush_start_cu,
- const float3 &brush_end_cu,
- MutableSpan<bool> curves_to_delete)
+ void delete_spherical(const float3 &brush_cu, MutableSpan<bool> curves_to_delete)
{
Span<float3> positions_cu = curves_->positions();
- const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) {
for (const int curve_i : curve_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
+
+ if (points.size() == 1) {
+ const float3 &pos_cu = positions_cu[points.first()];
+ const float distance_sq_cu = math::distance_squared(pos_cu, brush_cu);
+ if (distance_sq_cu < brush_radius_sq_cu) {
+ curves_to_delete[curve_i] = true;
+ }
+ continue;
+ }
+
for (const int segment_i : points.drop_back(1)) {
const float3 &pos1_cu = positions_cu[segment_i];
const float3 &pos2_cu = positions_cu[segment_i + 1];
- float3 closest_segment_cu, closest_brush_cu;
- isect_seg_seg_v3(pos1_cu,
- pos2_cu,
- brush_start_cu,
- brush_end_cu,
- closest_segment_cu,
- closest_brush_cu);
- const float distance_to_brush_sq_cu = math::distance_squared(closest_segment_cu,
- closest_brush_cu);
- if (distance_to_brush_sq_cu > brush_radius_sq_cu) {
+ const float distance_sq_cu = dist_squared_to_line_segment_v3(brush_cu, pos1_cu, pos2_cu);
+ if (distance_sq_cu > brush_radius_sq_cu) {
continue;
}
curves_to_delete[curve_i] = true;
@@ -246,7 +250,7 @@ struct DeleteOperationExecutor {
void initialize_spherical_brush_reference_point()
{
std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_re_);
+ *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
index d10cf239dd2..b0a6d6ef29c 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
@@ -283,9 +283,10 @@ struct CurvesEffectOperationExecutor {
CurvesGeometry *curves_ = nullptr;
const Brush *brush_ = nullptr;
- float brush_radius_re_;
- float brush_radius_sq_re_;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
float brush_strength_;
+
eBrushFalloffShape falloff_shape_;
float4x4 curves_to_world_mat_;
@@ -321,9 +322,12 @@ struct CurvesEffectOperationExecutor {
const CurvesSculpt &curves_sculpt = *scene_->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt.paint);
- brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
- brush_strength_ = BKE_brush_alpha_get(scene_, brush_);
- brush_radius_sq_re_ = pow2f(brush_radius_re_);
+ brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+
+ brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+
falloff_shape_ = eBrushFalloffShape(brush_->falloff_shape);
curves_to_world_mat_ = object_->obmat;
@@ -341,7 +345,7 @@ struct CurvesEffectOperationExecutor {
*rv3d_,
*object_,
stroke_extension.mouse_position,
- brush_radius_re_)) {
+ brush_radius_base_re_)) {
self.brush_3d_ = *brush_3d;
}
}
@@ -385,18 +389,20 @@ struct CurvesEffectOperationExecutor {
symmetry_brush_transforms_inv.append(brush_transform.inverted());
}
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
Influences &local_influences = influences_for_thread.local();
for (const int curve_i : curves_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
- const int tot_segments = points.size() - 1;
- float max_move_distance_cu = 0.0f;
+ float max_move_distance_cu = 0.0f;
for (const float4x4 &brush_transform_inv : symmetry_brush_transforms_inv) {
- for (const int segment_i : IndexRange(tot_segments)) {
- const float3 &p1_cu = brush_transform_inv * positions_cu[points[segment_i]];
- const float3 &p2_cu = brush_transform_inv * positions_cu[points[segment_i] + 1];
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 p1_cu = brush_transform_inv * positions_cu[segment_i];
+ const float3 p2_cu = brush_transform_inv * positions_cu[segment_i + 1];
float2 p1_re, p2_re;
ED_view3d_project_float_v2_m4(region_, p1_cu, p1_re, projection.values);
@@ -415,13 +421,13 @@ struct CurvesEffectOperationExecutor {
p1_re,
p2_re);
- if (dist_to_brush_sq_re > brush_radius_sq_re_) {
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
continue;
}
const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
const float radius_falloff = BKE_brush_curve_strength(
- brush_, dist_to_brush_re, brush_radius_re_);
+ brush_, dist_to_brush_re, brush_radius_re);
const float weight = brush_strength_ * radius_falloff;
const float3 closest_on_segment_cu = math::interpolate(
@@ -474,7 +480,7 @@ struct CurvesEffectOperationExecutor {
const float3 brush_pos_end_cu = world_to_curves_mat_ * brush_pos_end_wo;
const float3 brush_pos_diff_cu = brush_pos_end_cu - brush_pos_start_cu;
const float brush_pos_diff_length_cu = math::length(brush_pos_diff_cu);
- const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
@@ -485,15 +491,15 @@ struct CurvesEffectOperationExecutor {
for (const int curve_i : curves_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
- const int tot_segments = points.size() - 1;
+
float max_move_distance_cu = 0.0f;
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
const float3 brush_pos_start_transformed_cu = brush_transform * brush_pos_start_cu;
const float3 brush_pos_end_transformed_cu = brush_transform * brush_pos_end_cu;
- for (const int segment_i : IndexRange(tot_segments)) {
- const float3 &p1_cu = positions_cu[points[segment_i]];
- const float3 &p2_cu = positions_cu[points[segment_i] + 1];
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions_cu[segment_i];
+ const float3 &p2_cu = positions_cu[segment_i + 1];
float3 closest_on_segment_cu;
float3 closest_on_brush_cu;
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
index 00e7213b5e6..842de234761 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
@@ -16,6 +16,8 @@ struct RegionView3D;
struct Depsgraph;
struct View3D;
struct Object;
+struct Brush;
+struct Scene;
namespace blender::ed::sculpt_paint {
@@ -24,8 +26,19 @@ using bke::CurvesGeometry;
struct StrokeExtension {
bool is_first;
float2 mouse_position;
+ float pressure;
};
+float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension);
+float brush_radius_get(const Scene &scene,
+ const Brush &brush,
+ const StrokeExtension &stroke_extension);
+
+float brush_strength_factor(const Brush &brush, const StrokeExtension &stroke_extension);
+float brush_strength_get(const Scene &scene,
+ const Brush &brush,
+ const StrokeExtension &stroke_extension);
+
/**
* Base class for stroke based operations in curves sculpt mode.
*/
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
index 776da37205c..15d0f73592d 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
@@ -74,6 +74,36 @@ using blender::bke::CurvesGeometry;
/** \name * SCULPT_CURVES_OT_brush_stroke
* \{ */
+float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
+{
+ if (BKE_brush_use_size_pressure(&brush)) {
+ return stroke_extension.pressure;
+ }
+ return 1.0f;
+}
+
+float brush_radius_get(const Scene &scene,
+ const Brush &brush,
+ const StrokeExtension &stroke_extension)
+{
+ return BKE_brush_size_get(&scene, &brush) * brush_radius_factor(brush, stroke_extension);
+}
+
+float brush_strength_factor(const Brush &brush, const StrokeExtension &stroke_extension)
+{
+ if (BKE_brush_use_alpha_pressure(&brush)) {
+ return stroke_extension.pressure;
+ }
+ return 1.0f;
+}
+
+float brush_strength_get(const Scene &scene,
+ const Brush &brush,
+ const StrokeExtension &stroke_extension)
+{
+ return BKE_brush_alpha_get(&scene, &brush) * brush_strength_factor(brush, stroke_extension);
+}
+
static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bContext &C,
wmOperator &op)
{
@@ -128,6 +158,7 @@ static void stroke_update_step(bContext *C,
StrokeExtension stroke_extension;
RNA_float_get_array(stroke_element, "mouse", stroke_extension.mouse_position);
+ stroke_extension.pressure = RNA_float_get(stroke_element, "pressure");
if (!op_data->operation) {
stroke_extension.is_first = true;
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
index e009b443839..bcdeaaeabf2 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
@@ -80,8 +80,10 @@ struct SnakeHookOperatorExecutor {
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
- float brush_radius_re_;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
float brush_strength_;
+
eBrushFalloffShape falloff_shape_;
Object *object_ = nullptr;
@@ -112,8 +114,11 @@ struct SnakeHookOperatorExecutor {
curves_sculpt_ = scene_->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
- brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
- brush_strength_ = BKE_brush_alpha_get(scene_, brush_);
+
+ brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
curves_to_world_mat_ = object_->obmat;
@@ -132,7 +137,7 @@ struct SnakeHookOperatorExecutor {
if (stroke_extension.is_first) {
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_re_);
+ *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -174,6 +179,9 @@ struct SnakeHookOperatorExecutor {
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
@@ -183,13 +191,14 @@ struct SnakeHookOperatorExecutor {
float2 old_pos_re;
ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values);
- const float distance_to_brush_re = math::distance(old_pos_re, brush_pos_prev_re_);
- if (distance_to_brush_re > brush_radius_re_) {
+ const float distance_to_brush_sq_re = math::distance_squared(old_pos_re,
+ brush_pos_prev_re_);
+ if (distance_to_brush_sq_re > brush_radius_sq_re) {
continue;
}
const float radius_falloff = BKE_brush_curve_strength(
- brush_, distance_to_brush_re, brush_radius_re_);
+ brush_, std::sqrt(distance_to_brush_sq_re), brush_radius_re);
const float weight = brush_strength_ * radius_falloff;
const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
@@ -222,7 +231,7 @@ struct SnakeHookOperatorExecutor {
const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
- const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc
index 572e5b78b74..a313489885d 100644
--- a/source/blender/editors/sculpt_paint/paint_image.cc
+++ b/source/blender/editors/sculpt_paint/paint_image.cc
@@ -359,9 +359,7 @@ void paint_brush_color_get(struct Scene *scene,
}
/* Gradient / Color-band colors are not considered #PROP_COLOR_GAMMA.
* Brush colors are expected to be in sRGB though. */
- IMB_colormanagement_scene_linear_to_srgb_v3(color_gr);
-
- copy_v3_v3(color, color_gr);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color, color_gr);
}
else {
copy_v3_v3(color, BKE_brush_color_get(scene, br));
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc
index 16b22775b9e..fb1c8ceaa1a 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -331,8 +331,7 @@ static Color vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary)
float color[4];
const float *brush_color = secondary ? BKE_brush_secondary_color_get(scene, brush) :
BKE_brush_color_get(scene, brush);
- copy_v3_v3(color, brush_color);
- IMB_colormanagement_srgb_to_scene_linear_v3(color);
+ IMB_colormanagement_srgb_to_scene_linear_v3(color, brush_color);
color[3] = 1.0f; /* alpha isn't used, could even be removed to speedup paint a little */
diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index 46940b619e6..644f14905ba 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -2001,7 +2001,7 @@ static void sculpt_expand_cache_initial_config_set(bContext *C,
BKE_curvemapping_init(expand_cache->brush->curve);
copy_v4_fl(expand_cache->fill_color, 1.0f);
copy_v3_v3(expand_cache->fill_color, BKE_brush_color_get(ss->scene, expand_cache->brush));
- IMB_colormanagement_srgb_to_scene_linear_v3(expand_cache->fill_color);
+ IMB_colormanagement_srgb_to_scene_linear_v3(expand_cache->fill_color, expand_cache->fill_color);
expand_cache->scene = CTX_data_scene(C);
expand_cache->mtex = &expand_cache->brush->mtex;
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index f71a814aff4..26d18823b37 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -298,7 +298,7 @@ static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent
float fill_color[3];
RNA_float_get_array(op->ptr, "fill_color", fill_color);
- IMB_colormanagement_srgb_to_scene_linear_v3(fill_color);
+ IMB_colormanagement_srgb_to_scene_linear_v3(fill_color, fill_color);
if (filter_strength < 0.0 && !ss->filter_cache->pre_smoothed_color) {
sculpt_color_presmooth_init(ss);
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index 8803c95aab1..dc620f0ee93 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -781,8 +781,7 @@ static int sculpt_sample_color_invoke(bContext *C, wmOperator *op, const wmEvent
}
float color_srgb[3];
- copy_v3_v3(color_srgb, active_vertex_color);
- IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb, active_vertex_color);
BKE_brush_color_set(scene, brush, color_srgb);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index 7a8a6e8e484..ac05652b058 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -124,7 +124,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
copy_v3_v3(brush_color,
ss->cache->invert ? BKE_brush_secondary_color_get(ss->scene, brush) :
BKE_brush_color_get(ss->scene, brush));
- IMB_colormanagement_srgb_to_scene_linear_v3(brush_color);
+ IMB_colormanagement_srgb_to_scene_linear_v3(brush_color, brush_color);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 1d0061ab7d8..052af39319c 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -724,6 +724,9 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
/* Needed to refresh context path when changing active particle system index. */
buttons_area_redraw(area, BCONTEXT_PARTICLE);
break;
+ case ND_DRAW_ANIMVIZ:
+ buttons_area_redraw(area, BCONTEXT_OBJECT);
+ break;
default:
/* Not all object RNA props have a ND_ notifier (yet) */
ED_area_tag_redraw(area);
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 568bd064e3e..63f919a1713 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -103,7 +103,7 @@ static SpaceLink *image_create(const ScrArea *UNUSED(area), const Scene *UNUSED(
simage->overlay.flag = SI_OVERLAY_SHOW_OVERLAYS | SI_OVERLAY_SHOW_GRID_BACKGROUND;
BKE_imageuser_default(&simage->iuser);
- simage->iuser.flag = IMA_SHOW_STEREO | IMA_ANIM_ALWAYS | IMA_SHOW_MAX_RESOLUTION;
+ simage->iuser.flag = IMA_SHOW_STEREO | IMA_ANIM_ALWAYS;
BKE_scopes_new(&simage->scopes);
simage->sample_line_hist.height = 100;
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 7fb15d69ab5..975d4eda7e3 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -303,10 +303,8 @@ static bNodeTree *node_add_group_get_and_poll_group_node_tree(Main *bmain,
wmOperator *op,
bNodeTree *ntree)
{
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
-
- bNodeTree *node_group = (bNodeTree *)BKE_libblock_find_name(bmain, ID_NT, name);
+ bNodeTree *node_group = reinterpret_cast<bNodeTree *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_NT));
if (!node_group) {
return nullptr;
}
@@ -348,8 +346,14 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+ const char *node_idname = node_group_idname(C);
+ if (node_idname[0] == '\0') {
+ BKE_report(op->reports, RPT_WARNING, "Could not determine type of group node");
+ return OPERATOR_CANCELLED;
+ }
+
bNode *group_node = node_add_node(*C,
- node_group_idname(C),
+ node_idname,
(node_group->type == NTREE_CUSTOM) ? NODE_CUSTOM_GROUP :
NODE_GROUP,
snode->runtime->cursor[0],
@@ -365,9 +369,25 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, group_node);
ED_node_tree_propagate_change(C, bmain, nullptr);
+ DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
}
+static bool node_add_group_poll(bContext *C)
+{
+ if (!ED_operator_node_editable(C)) {
+ return false;
+ }
+ const SpaceNode *snode = CTX_wm_space_node(C);
+ if (snode->edittree->type == NTREE_CUSTOM) {
+ CTX_wm_operator_poll_msg_set(C,
+ "This node editor displays a custom (Python defined) node tree. "
+ "Dropping node groups isn't supported for this.");
+ return false;
+ }
+ return true;
+}
+
static int node_add_group_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
@@ -396,12 +416,12 @@ void NODE_OT_add_group(wmOperatorType *ot)
/* callbacks */
ot->exec = node_add_group_exec;
ot->invoke = node_add_group_invoke;
- ot->poll = ED_operator_node_editable;
+ ot->poll = node_add_group_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
@@ -410,26 +430,16 @@ void NODE_OT_add_group(wmOperatorType *ot)
/** \name Add Node Object Operator
* \{ */
-static Object *node_add_object_get_and_poll_object_node_tree(Main *bmain, wmOperator *op)
-{
- if (RNA_struct_property_is_set(op->ptr, "session_uuid")) {
- const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
- return (Object *)BKE_libblock_find_session_uuid(bmain, ID_OB, session_uuid);
- }
-
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- return (Object *)BKE_libblock_find_name(bmain, ID_OB, name);
-}
-
static int node_add_object_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
- Object *object;
- if (!(object = node_add_object_get_and_poll_object_node_tree(bmain, op))) {
+ Object *object = reinterpret_cast<Object *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_OB));
+
+ if (!object) {
return OPERATOR_CANCELLED;
}
@@ -486,8 +496,6 @@ static bool node_add_object_poll(bContext *C)
void NODE_OT_add_object(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Add Node Object";
ot->description = "Add an object info node to the current node editor";
@@ -501,17 +509,7 @@ void NODE_OT_add_object(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- RNA_def_string(ot->srna, "name", "Object", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- prop = RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
- RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
@@ -520,27 +518,16 @@ void NODE_OT_add_object(wmOperatorType *ot)
/** \name Add Node Collection Operator
* \{ */
-static Collection *node_add_collection_get_and_poll_collection_node_tree(Main *bmain,
- wmOperator *op)
-{
- if (RNA_struct_property_is_set(op->ptr, "session_uuid")) {
- const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
- return (Collection *)BKE_libblock_find_session_uuid(bmain, ID_GR, session_uuid);
- }
-
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- return (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
-}
-
static int node_add_collection_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
bNodeTree *ntree = snode.edittree;
- Collection *collection;
- if (!(collection = node_add_collection_get_and_poll_collection_node_tree(bmain, op))) {
+ Collection *collection = reinterpret_cast<Collection *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_GR));
+
+ if (!collection) {
return OPERATOR_CANCELLED;
}
@@ -597,8 +584,6 @@ static bool node_add_collection_poll(bContext *C)
void NODE_OT_add_collection(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Add Node Collection";
ot->description = "Add an collection info node to the current node editor";
@@ -612,18 +597,7 @@ void NODE_OT_add_collection(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- RNA_def_string(
- ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- prop = RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
- RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
@@ -745,7 +719,7 @@ void NODE_OT_add_file(wmOperatorType *ot)
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
- RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
@@ -754,18 +728,6 @@ void NODE_OT_add_file(wmOperatorType *ot)
/** \name Add Mask Node Operator
* \{ */
-static ID *node_add_mask_get_and_poll_mask(Main *bmain, wmOperator *op)
-{
- if (RNA_struct_property_is_set(op->ptr, "session_uuid")) {
- const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
- return BKE_libblock_find_session_uuid(bmain, ID_MSK, session_uuid);
- }
-
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- return BKE_libblock_find_name(bmain, ID_MSK, name);
-}
-
static bool node_add_mask_poll(bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
@@ -779,7 +741,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
SpaceNode &snode = *CTX_wm_space_node(C);
bNode *node;
- ID *mask = node_add_mask_get_and_poll_mask(bmain, op);
+ ID *mask = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_MSK);
if (!mask) {
return OPERATOR_CANCELLED;
}
@@ -805,8 +767,6 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
void NODE_OT_add_mask(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Add Mask Node";
ot->description = "Add a mask node to the current node editor";
@@ -819,17 +779,7 @@ void NODE_OT_add_mask(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- prop = RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
- RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index fb2f1bf3751..ab80a44d636 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -293,10 +293,10 @@ static void compo_startjob(void *cjv,
ntree->progress = nullptr;
}
-} // namespace blender::ed::space_node
-
/** \} */
+} // namespace blender::ed::space_node
+
/* -------------------------------------------------------------------- */
/** \name Composite Job C API
* \{ */
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index fee64da0459..9c0172cfabf 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -183,9 +183,9 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
BLI_assert(socket->type == SOCK_STRING);
/* For the attribute input node, also adjust the type and links connected to the output. */
- if (node->type == GEO_NODE_INPUT_NAMED_ATTRIBUTE) {
+ if (node->type == GEO_NODE_INPUT_NAMED_ATTRIBUTE && item->data_type.has_value()) {
NodeGeometryInputNamedAttribute &storage = *(NodeGeometryInputNamedAttribute *)node->storage;
- const CustomDataType new_type = data_type_in_attribute_input_node(item->data_type);
+ const CustomDataType new_type = data_type_in_attribute_input_node(*item->data_type);
if (new_type != storage.data_type) {
storage.data_type = new_type;
/* Make the output socket with the new type on the attribute input node active. */
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index 3963186f73b..15afd024766 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -672,7 +672,7 @@ static void node_group_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *d
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_int_set(drop->ptr, "session_uuid", (int)id->session_uuid);
}
static void node_id_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
@@ -687,7 +687,7 @@ static void node_id_path_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
if (id) {
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_int_set(drop->ptr, "session_uuid", (int)id->session_uuid);
RNA_struct_property_unset(drop->ptr, "filepath");
}
else if (drag->path[0]) {
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index 59f6bd85d59..97d2957eed2 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -27,6 +27,7 @@ set(SRC
outliner_draw.cc
outliner_edit.cc
outliner_ops.cc
+ outliner_query.cc
outliner_select.cc
outliner_sync.cc
outliner_tools.cc
@@ -57,6 +58,7 @@ set(SRC
tree/tree_element_scene_objects.cc
tree/tree_element_seq.cc
tree/tree_element_view_layer.cc
+ tree/tree_iterator.cc
outliner_intern.hh
tree/common.hh
@@ -75,6 +77,7 @@ set(SRC
tree/tree_element_scene_objects.hh
tree/tree_element_seq.hh
tree/tree_element_view_layer.hh
+ tree/tree_iterator.hh
)
set(LIB
diff --git a/source/blender/editors/space_outliner/outliner_context.cc b/source/blender/editors/space_outliner/outliner_context.cc
index d07b6641836..1a804cb58b8 100644
--- a/source/blender/editors/space_outliner/outliner_context.cc
+++ b/source/blender/editors/space_outliner/outliner_context.cc
@@ -12,23 +12,25 @@
#include "DNA_space_types.h"
#include "outliner_intern.hh"
+#include "tree/tree_iterator.hh"
-static void outliner_context_selected_ids_recursive(const ListBase *subtree,
+using namespace blender::ed::outliner;
+
+static void outliner_context_selected_ids_recursive(const SpaceOutliner &space_outliner,
bContextDataResult *result)
{
- LISTBASE_FOREACH (const TreeElement *, te, subtree) {
+ tree_iterator::all(space_outliner, [&](const TreeElement *te) {
const TreeStoreElem *tse = TREESTORE(te);
if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, TSE_SOME_ID, TSE_LAYER_COLLECTION))) {
CTX_data_id_list_add(result, tse->id);
}
- outliner_context_selected_ids_recursive(&te->subtree, result);
- }
+ });
}
static void outliner_context_selected_ids(const SpaceOutliner *space_outliner,
bContextDataResult *result)
{
- outliner_context_selected_ids_recursive(&space_outliner->tree, result);
+ outliner_context_selected_ids_recursive(*space_outliner, result);
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
}
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc
index a22ce9d3d24..e20958c1b1e 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.cc
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc
@@ -316,7 +316,7 @@ static bool parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- bool changed = outliner_flag_set(&space_outliner->tree, TSE_DRAG_ANY, false);
+ bool changed = outliner_flag_set(*space_outliner, TSE_DRAG_ANY, false);
if (changed) {
ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
}
@@ -847,8 +847,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
ARegion *region = CTX_wm_region(C);
- bool changed = outliner_flag_set(
- &space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
+ bool changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
if (!drop_data) {
@@ -1195,8 +1194,7 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
ARegion *region = CTX_wm_region(C);
- bool changed = outliner_flag_set(
- &space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
+ bool changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
CollectionDrop data;
if (((event->modifier & KM_SHIFT) == 0) &&
@@ -1461,7 +1459,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
/* Only drag element under mouse if it was not selected before. */
if ((tselem->flag & TSE_SELECTED) == 0) {
- outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
+ outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
tselem->flag |= TSE_SELECTED;
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index d165e98d7d4..753de83a10d 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -71,7 +71,9 @@
#include "tree/tree_element_id.hh"
#include "tree/tree_element_overrides.hh"
#include "tree/tree_element_rna.hh"
+#include "tree/tree_iterator.hh"
+using namespace blender;
using namespace blender::ed::outliner;
/* -------------------------------------------------------------------- */
@@ -1714,72 +1716,70 @@ static void outliner_draw_restrictbuts(uiBlock *block,
}
static void outliner_draw_userbuts(uiBlock *block,
- ARegion *region,
- SpaceOutliner *space_outliner,
- ListBase *lb)
+ const ARegion *region,
+ const SpaceOutliner *space_outliner)
{
+ tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
+ if (!outliner_is_element_in_view(te, &region->v2d)) {
+ return;
+ }
- LISTBASE_FOREACH (TreeElement *, te, lb) {
- TreeStoreElem *tselem = TREESTORE(te);
- if (outliner_is_element_in_view(te, &region->v2d)) {
- if (tselem->type == TSE_SOME_ID) {
- uiBut *bt;
- ID *id = tselem->id;
- const char *tip = nullptr;
- char buf[16] = "";
- int but_flag = UI_BUT_DRAG_LOCK;
+ const TreeStoreElem *tselem = TREESTORE(te);
+ if (tselem->type != TSE_SOME_ID) {
+ return;
+ }
- if (ID_IS_LINKED(id)) {
- but_flag |= UI_BUT_DISABLED;
- }
+ uiBut *bt;
+ ID *id = tselem->id;
+ const char *tip = nullptr;
+ char buf[16] = "";
+ int but_flag = UI_BUT_DRAG_LOCK;
- BLI_str_format_int_grouped(buf, id->us);
- bt = uiDefBut(block,
- UI_BTYPE_BUT,
- 1,
- buf,
- (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS),
- te->ys,
- UI_UNIT_X,
- UI_UNIT_Y,
- nullptr,
- 0.0,
- 0.0,
- 0,
- 0,
- TIP_("Number of users of this data-block"));
- UI_but_flag_enable(bt, but_flag);
-
- if (id->flag & LIB_FAKEUSER) {
- tip = TIP_("Data-block will be retained using a fake user");
- }
- else {
- tip = TIP_("Data-block has no users and will be deleted");
- }
- bt = uiDefIconButBitS(block,
- UI_BTYPE_ICON_TOGGLE,
- LIB_FAKEUSER,
- 1,
- ICON_FAKE_USER_OFF,
- (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS),
- te->ys,
- UI_UNIT_X,
- UI_UNIT_Y,
- &id->flag,
- 0,
- 0,
- 0,
- 0,
- tip);
- UI_but_func_set(bt, restrictbutton_id_user_toggle, id, nullptr);
- UI_but_flag_enable(bt, but_flag);
- }
+ if (ID_IS_LINKED(id)) {
+ but_flag |= UI_BUT_DISABLED;
}
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_draw_userbuts(block, region, space_outliner, &te->subtree);
+ BLI_str_format_int_grouped(buf, id->us);
+ bt = uiDefBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ buf,
+ (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS),
+ te->ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ nullptr,
+ 0.0,
+ 0.0,
+ 0,
+ 0,
+ TIP_("Number of users of this data-block"));
+ UI_but_flag_enable(bt, but_flag);
+
+ if (id->flag & LIB_FAKEUSER) {
+ tip = TIP_("Data-block will be retained using a fake user");
}
- }
+ else {
+ tip = TIP_("Data-block has no users and will be deleted");
+ }
+ bt = uiDefIconButBitS(block,
+ UI_BTYPE_ICON_TOGGLE,
+ LIB_FAKEUSER,
+ 1,
+ ICON_FAKE_USER_OFF,
+ (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS),
+ te->ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ &id->flag,
+ 0,
+ 0,
+ 0,
+ 0,
+ tip);
+ UI_but_func_set(bt, restrictbutton_id_user_toggle, id, nullptr);
+ UI_but_flag_enable(bt, but_flag);
+ });
}
static void outliner_draw_overrides_rna_buts(uiBlock *block,
@@ -1920,91 +1920,6 @@ static void outliner_draw_overrides_restrictbuts(Main *bmain,
}
}
-static bool outliner_draw_overrides_warning_buts(uiBlock *block,
- ARegion *region,
- SpaceOutliner *space_outliner,
- ListBase *lb,
- const bool is_open)
-{
- bool any_item_has_warnings = false;
-
- LISTBASE_FOREACH (TreeElement *, te, lb) {
- bool item_has_warnings = false;
- const bool do_draw = outliner_is_element_in_view(te, &region->v2d);
- int but_flag = UI_BUT_DRAG_LOCK;
- const char *tip = nullptr;
-
- TreeStoreElem *tselem = TREESTORE(te);
- switch (tselem->type) {
- case TSE_LIBRARY_OVERRIDE_BASE: {
- ID *id = tselem->id;
-
- if (id->flag & LIB_LIB_OVERRIDE_RESYNC_LEFTOVER) {
- item_has_warnings = true;
- if (do_draw) {
- tip = TIP_(
- "This override data-block is not needed anymore, but was detected as user-edited");
- }
- }
- else if (ID_IS_OVERRIDE_LIBRARY_REAL(id) && ID_REAL_USERS(id) == 0) {
- item_has_warnings = true;
- if (do_draw) {
- tip = TIP_("This override data-block is unused");
- }
- }
- break;
- }
- case TSE_LIBRARY_OVERRIDE: {
- TreeElementOverridesProperty &te_override_prop =
- *tree_element_cast<TreeElementOverridesProperty>(te);
- if (!te_override_prop.is_rna_path_valid) {
- item_has_warnings = true;
- if (do_draw) {
- tip = TIP_(
- "This override property does not exist in current data, it will be removed on "
- "next .blend file save");
- }
- }
- break;
- }
- default:
- break;
- }
-
- const bool any_child_has_warnings = outliner_draw_overrides_warning_buts(
- block,
- region,
- space_outliner,
- &te->subtree,
- is_open && TSELEM_OPEN(tselem, space_outliner));
-
- if (do_draw &&
- (item_has_warnings || (any_child_has_warnings && !TSELEM_OPEN(tselem, space_outliner)))) {
- if (tip == nullptr) {
- tip = TIP_("Some sub-items require attention");
- }
- uiBut *bt = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 1,
- ICON_ERROR,
- (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS),
- te->ys,
- UI_UNIT_X,
- UI_UNIT_Y,
- nullptr,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- tip);
- UI_but_flag_enable(bt, but_flag);
- }
- any_item_has_warnings = any_item_has_warnings || item_has_warnings || any_child_has_warnings;
- }
-
- return any_item_has_warnings;
-}
-
static void outliner_draw_separator(ARegion *region, const int x)
{
View2D *v2d = &region->v2d;
@@ -2025,81 +1940,82 @@ static void outliner_draw_separator(ARegion *region, const int x)
immUnbindProgram();
}
-static void outliner_draw_rnabuts(
- uiBlock *block, ARegion *region, SpaceOutliner *space_outliner, int sizex, ListBase *lb)
+static void outliner_draw_rnabuts(uiBlock *block,
+ ARegion *region,
+ SpaceOutliner *space_outliner,
+ int sizex)
{
PointerRNA ptr;
PropertyRNA *prop;
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
- if (outliner_is_element_in_view(te, &region->v2d)) {
- if (TreeElementRNAProperty *te_rna_prop = tree_element_cast<TreeElementRNAProperty>(te)) {
- ptr = te_rna_prop->getPointerRNA();
- prop = te_rna_prop->getPropertyRNA();
-
- if (!TSELEM_OPEN(tselem, space_outliner)) {
- if (RNA_property_type(prop) == PROP_POINTER) {
- uiBut *but = uiDefAutoButR(block,
- &ptr,
- prop,
- -1,
- "",
- ICON_NONE,
- sizex,
- te->ys,
- OL_RNA_COL_SIZEX,
- UI_UNIT_Y - 1);
- UI_but_flag_enable(but, UI_BUT_DISABLED);
- }
- else if (RNA_property_type(prop) == PROP_ENUM) {
- uiDefAutoButR(block,
- &ptr,
- prop,
- -1,
- nullptr,
- ICON_NONE,
- sizex,
- te->ys,
- OL_RNA_COL_SIZEX,
- UI_UNIT_Y - 1);
- }
- else {
- uiDefAutoButR(block,
- &ptr,
- prop,
- -1,
- "",
- ICON_NONE,
- sizex,
- te->ys,
- OL_RNA_COL_SIZEX,
- UI_UNIT_Y - 1);
- }
- }
- }
- else if (TreeElementRNAArrayElement *te_rna_array_elem =
- tree_element_cast<TreeElementRNAArrayElement>(te)) {
- ptr = te_rna_array_elem->getPointerRNA();
- prop = te_rna_array_elem->getPropertyRNA();
-
- uiDefAutoButR(block,
- &ptr,
- prop,
- te->index,
- "",
- ICON_NONE,
- sizex,
- te->ys,
- OL_RNA_COL_SIZEX,
- UI_UNIT_Y - 1);
- }
- }
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_draw_rnabuts(block, region, space_outliner, sizex, &te->subtree);
- }
- }
+ if (!outliner_is_element_in_view(te, &region->v2d)) {
+ return;
+ }
+
+ if (TreeElementRNAProperty *te_rna_prop = tree_element_cast<TreeElementRNAProperty>(te)) {
+ ptr = te_rna_prop->getPointerRNA();
+ prop = te_rna_prop->getPropertyRNA();
+
+ if (!TSELEM_OPEN(tselem, space_outliner)) {
+ if (RNA_property_type(prop) == PROP_POINTER) {
+ uiBut *but = uiDefAutoButR(block,
+ &ptr,
+ prop,
+ -1,
+ "",
+ ICON_NONE,
+ sizex,
+ te->ys,
+ OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
+ }
+ else if (RNA_property_type(prop) == PROP_ENUM) {
+ uiDefAutoButR(block,
+ &ptr,
+ prop,
+ -1,
+ nullptr,
+ ICON_NONE,
+ sizex,
+ te->ys,
+ OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
+ }
+ else {
+ uiDefAutoButR(block,
+ &ptr,
+ prop,
+ -1,
+ "",
+ ICON_NONE,
+ sizex,
+ te->ys,
+ OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
+ }
+ }
+ }
+ else if (TreeElementRNAArrayElement *te_rna_array_elem =
+ tree_element_cast<TreeElementRNAArrayElement>(te)) {
+ ptr = te_rna_array_elem->getPointerRNA();
+ prop = te_rna_array_elem->getPropertyRNA();
+
+ uiDefAutoButR(block,
+ &ptr,
+ prop,
+ te->index,
+ "",
+ ICON_NONE,
+ sizex,
+ te->ys,
+ OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
+ }
+ });
}
static void outliner_buttons(const bContext *C,
@@ -2185,9 +2101,9 @@ static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void *UNUSED
static void outliner_draw_mode_column_toggle(uiBlock *block,
TreeViewContext *tvc,
TreeElement *te,
- TreeStoreElem *tselem,
const bool lock_object_modes)
{
+ TreeStoreElem *tselem = TREESTORE(te);
if ((tselem->type != TSE_SOME_ID) || (te->idcode != ID_OB)) {
return;
}
@@ -2258,59 +2174,63 @@ static void outliner_draw_mode_column_toggle(uiBlock *block,
}
}
-static void outliner_draw_mode_column(const bContext *C,
- uiBlock *block,
+static void outliner_draw_mode_column(uiBlock *block,
TreeViewContext *tvc,
- SpaceOutliner *space_outliner,
- ListBase *tree)
+ SpaceOutliner *space_outliner)
{
- TreeStoreElem *tselem;
const bool lock_object_modes = tvc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK;
- LISTBASE_FOREACH (TreeElement *, te, tree) {
- tselem = TREESTORE(te);
-
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
if (tvc->obact && tvc->obact->mode != OB_MODE_OBJECT) {
- outliner_draw_mode_column_toggle(block, tvc, te, tselem, lock_object_modes);
+ outliner_draw_mode_column_toggle(block, tvc, te, lock_object_modes);
}
+ });
+}
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_draw_mode_column(C, block, tvc, space_outliner, &te->subtree);
+static StringRefNull outliner_draw_get_warning_tree_element_subtree(const TreeElement *parent_te)
+{
+ LISTBASE_FOREACH (const TreeElement *, sub_te, &parent_te->subtree) {
+ const AbstractTreeElement *abstract_te = tree_element_cast<AbstractTreeElement>(sub_te);
+ StringRefNull warning_msg = abstract_te ? abstract_te->getWarning() : "";
+
+ if (!warning_msg.is_empty()) {
+ return warning_msg;
+ }
+
+ warning_msg = outliner_draw_get_warning_tree_element_subtree(sub_te);
+ if (!warning_msg.is_empty()) {
+ return warning_msg;
}
}
+
+ return "";
}
-/* Returns `true` if some warning was drawn for that element or one of its sub-elements (if it is
- * not open). */
-static bool outliner_draw_warning_tree_element(uiBlock *block,
- SpaceOutliner *space_outliner,
- TreeElement *te,
- TreeStoreElem *tselem,
- const bool use_mode_column,
- const int te_ys)
+static StringRefNull outliner_draw_get_warning_tree_element(const SpaceOutliner &space_outliner,
+ const TreeElement *te)
{
- if ((te->flag & TE_HAS_WARNING) == 0) {
- /* If given element has no warning, recursively try to display the first sub-elements' warning.
- */
- if (!TSELEM_OPEN(tselem, space_outliner)) {
- LISTBASE_FOREACH (TreeElement *, sub_te, &te->subtree) {
- TreeStoreElem *sub_tselem = TREESTORE(sub_te);
+ const AbstractTreeElement *abstract_te = tree_element_cast<AbstractTreeElement>(te);
+ const StringRefNull warning_msg = abstract_te ? abstract_te->getWarning() : "";
- if (outliner_draw_warning_tree_element(
- block, space_outliner, sub_te, sub_tselem, use_mode_column, te_ys)) {
- return true;
- }
- }
- }
- return false;
+ if (!warning_msg.is_empty()) {
+ return warning_msg;
+ }
+
+ /* If given element has no warning, recursively try to display the first sub-element's warning.
+ */
+ if (!TSELEM_OPEN(te->store_elem, &space_outliner)) {
+ return outliner_draw_get_warning_tree_element_subtree(te);
}
- int icon = ICON_NONE;
- const char *tip = "";
- const bool has_warning = tree_element_warnings_get(te, &icon, &tip);
- BLI_assert(has_warning);
- UNUSED_VARS_NDEBUG(has_warning);
+ return "";
+}
+static void outliner_draw_warning_tree_element(uiBlock *block,
+ const SpaceOutliner *space_outliner,
+ StringRefNull warning_msg,
+ const bool use_mode_column,
+ const int te_ys)
+{
/* Move the warnings a unit left in view layer mode. */
const short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
UI_UNIT_X :
@@ -2320,7 +2240,7 @@ static bool outliner_draw_warning_tree_element(uiBlock *block,
uiBut *but = uiDefIconBut(block,
UI_BTYPE_ICON_TOGGLE,
0,
- icon,
+ ICON_ERROR,
mode_column_offset,
te_ys,
UI_UNIT_X,
@@ -2330,28 +2250,25 @@ static bool outliner_draw_warning_tree_element(uiBlock *block,
0.0,
0.0,
0.0,
- tip);
+ warning_msg.c_str());
/* No need for undo here, this is a pure info widget. */
UI_but_flag_disable(but, UI_BUT_UNDO);
-
- return true;
}
-static void outliner_draw_warning_column(const bContext *C,
- uiBlock *block,
- SpaceOutliner *space_outliner,
- const bool use_mode_column,
- ListBase *tree)
+static void outliner_draw_warning_column(uiBlock *block,
+ const SpaceOutliner *space_outliner,
+ const bool use_mode_column)
{
- LISTBASE_FOREACH (TreeElement *, te, tree) {
- TreeStoreElem *tselem = TREESTORE(te);
+ tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
+ /* Get warning for this element, or if there is none and the element is collapsed, the first
+ * warning in the collapsed sub-tree. */
+ StringRefNull warning_msg = outliner_draw_get_warning_tree_element(*space_outliner, te);
- outliner_draw_warning_tree_element(block, space_outliner, te, tselem, use_mode_column, te->ys);
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &te->subtree);
+ if (!warning_msg.is_empty()) {
+ outliner_draw_warning_tree_element(
+ block, space_outliner, warning_msg, use_mode_column, te->ys);
}
- }
+ });
}
/** \} */
@@ -3232,18 +3149,16 @@ static void outliner_draw_iconrow(bContext *C,
}
/* closed tree element */
-static void outliner_set_coord_tree_element(TreeElement *te, int startx, int starty)
+static void outliner_set_subtree_coords(const TreeElement *te)
{
- /* closed items may be displayed in row of parent, don't change their coordinate! */
- if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) {
- te->xs = 0;
- te->ys = 0;
- te->xend = 0;
- }
-
- LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
- outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty);
- }
+ tree_iterator::all(te->subtree, [&](TreeElement *te) {
+ /* closed items may be displayed in row of parent, don't change their coordinate! */
+ if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) {
+ te->xs = 0;
+ te->ys = 0;
+ te->xend = 0;
+ }
+ });
}
static bool element_should_draw_faded(const TreeViewContext *tvc,
@@ -3495,10 +3410,7 @@ static void outliner_draw_tree_element(bContext *C,
}
}
else {
- LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
- outliner_set_coord_tree_element(ten, startx, *starty);
- }
-
+ outliner_set_subtree_coords(te);
*starty -= UI_UNIT_Y;
}
}
@@ -3654,22 +3566,21 @@ static void outliner_draw_struct_marks(ARegion *region,
}
}
-static void outliner_draw_highlights_recursive(uint pos,
- const ARegion *region,
- const SpaceOutliner *space_outliner,
- const ListBase *lb,
- const float col_selection[4],
- const float col_active[4],
- const float col_highlight[4],
- const float col_searchmatch[4],
- int start_x,
- int *io_start_y)
+static void outliner_draw_highlights(uint pos,
+ const ARegion *region,
+ const SpaceOutliner *space_outliner,
+ const float col_selection[4],
+ const float col_active[4],
+ const float col_highlight[4],
+ const float col_searchmatch[4],
+ int start_x,
+ int *io_start_y)
{
const bool is_searching = (SEARCHING_OUTLINER(space_outliner) ||
(space_outliner->outlinevis == SO_DATA_API &&
space_outliner->search_string[0] != 0));
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
const TreeStoreElem *tselem = TREESTORE(te);
const int start_y = *io_start_y;
@@ -3725,19 +3636,7 @@ static void outliner_draw_highlights_recursive(uint pos,
}
*io_start_y -= UI_UNIT_Y;
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_draw_highlights_recursive(pos,
- region,
- space_outliner,
- &te->subtree,
- col_selection,
- col_active,
- col_highlight,
- col_searchmatch,
- start_x + UI_UNIT_X,
- io_start_y);
- }
- }
+ });
}
static void outliner_draw_highlights(ARegion *region,
@@ -3759,16 +3658,15 @@ static void outliner_draw_highlights(ARegion *region,
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- outliner_draw_highlights_recursive(pos,
- region,
- space_outliner,
- &space_outliner->tree,
- col_selection,
- col_active,
- col_highlight,
- col_searchmatch,
- startx,
- starty);
+ outliner_draw_highlights(pos,
+ region,
+ space_outliner,
+ col_selection,
+ col_active,
+ col_highlight,
+ col_searchmatch,
+ startx,
+ starty);
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
}
@@ -3961,13 +3859,8 @@ void draw_outliner(const bContext *C)
UI_view2d_view_ortho(v2d);
/* Only show mode column in View Layers and Scenes view. */
- const bool use_mode_column = (space_outliner->flag & SO_MODE_COLUMN) &&
- (ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES));
-
- const bool use_warning_column = ELEM(space_outliner->outlinevis,
- SO_LIBRARIES,
- SO_OVERRIDES_LIBRARY) &&
- space_outliner->runtime->tree_display->hasWarnings();
+ const bool use_mode_column = outliner_shows_mode_column(*space_outliner);
+ const bool use_warning_column = outliner_has_element_warnings(*space_outliner);
/* Draw outliner stuff (background, hierarchy lines and names). */
const float right_column_width = outliner_right_columns_width(space_outliner);
@@ -3997,18 +3890,14 @@ void draw_outliner(const bContext *C)
outliner_draw_separator(region, buttons_start_x + OL_RNA_COL_SIZEX);
UI_block_emboss_set(block, UI_EMBOSS);
- outliner_draw_rnabuts(block, region, space_outliner, buttons_start_x, &space_outliner->tree);
+ outliner_draw_rnabuts(block, region, space_outliner, buttons_start_x);
UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS);
}
else if (space_outliner->outlinevis == SO_ID_ORPHANS) {
/* draw user toggle columns */
- outliner_draw_userbuts(block, region, space_outliner, &space_outliner->tree);
+ outliner_draw_userbuts(block, region, space_outliner);
}
else if (space_outliner->outlinevis == SO_OVERRIDES_LIBRARY) {
- /* Draw overrides status columns. */
- outliner_draw_overrides_warning_buts(
- block, region, space_outliner, &space_outliner->tree, true);
-
const int x = region->v2d.cur.xmax - right_column_width;
outliner_draw_separator(region, x);
if (space_outliner->lib_override_view_mode == SO_LIB_OVERRIDE_VIEW_PROPERTIES) {
@@ -4037,12 +3926,12 @@ void draw_outliner(const bContext *C)
/* Draw mode icons */
if (use_mode_column) {
- outliner_draw_mode_column(C, block, &tvc, space_outliner, &space_outliner->tree);
+ outliner_draw_mode_column(block, &tvc, space_outliner);
}
/* Draw warning icons */
if (use_warning_column) {
- outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &space_outliner->tree);
+ outliner_draw_warning_column(block, space_outliner, use_mode_column);
}
UI_block_emboss_set(block, UI_EMBOSS);
diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index 1de45b0ec96..c4a9398a5f7 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -60,6 +60,7 @@
#include "outliner_intern.hh"
#include "tree/tree_element_rna.hh"
+#include "tree/tree_iterator.hh"
using namespace blender::ed::outliner;
@@ -107,7 +108,7 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const
if (!hovered_te || !is_over_icon || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED) ||
!(icon_te->store_elem->flag & TSE_HIGHLIGHTED_ICON)) {
/* Clear highlights when nothing is hovered or when a new item is hovered. */
- changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
+ changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
if (hovered_te) {
hovered_te->store_elem->flag |= TSE_HIGHLIGHTED;
changed = true;
@@ -167,7 +168,7 @@ void outliner_item_openclose(SpaceOutliner *space_outliner,
}
if (toggle_all) {
- outliner_flag_set(&te->subtree, TSE_CLOSED, !open);
+ outliner_flag_set(te->subtree, TSE_CLOSED, !open);
}
}
@@ -1077,11 +1078,16 @@ int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel)
return 0;
}
-bool outliner_flag_set(ListBase *lb, short flag, short set)
+bool outliner_flag_set(const SpaceOutliner &space_outliner, const short flag, const short set)
+{
+ return outliner_flag_set(space_outliner.tree, flag, set);
+}
+
+bool outliner_flag_set(const ListBase &lb, const short flag, const short set)
{
bool changed = false;
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all(lb, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
bool has_flag = (tselem->flag & flag);
if (set == 0) {
@@ -1094,21 +1100,24 @@ bool outliner_flag_set(ListBase *lb, short flag, short set)
tselem->flag |= flag;
changed = true;
}
- changed |= outliner_flag_set(&te->subtree, flag, set);
- }
+ });
return changed;
}
-bool outliner_flag_flip(ListBase *lb, short flag)
+bool outliner_flag_flip(const SpaceOutliner &space_outliner, const short flag)
+{
+ return outliner_flag_flip(space_outliner.tree, flag);
+}
+
+bool outliner_flag_flip(const ListBase &lb, const short flag)
{
bool changed = false;
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all(lb, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
tselem->flag ^= flag;
- changed |= outliner_flag_flip(&te->subtree, flag);
- }
+ });
return changed;
}
@@ -1125,10 +1134,10 @@ static int outliner_toggle_expanded_exec(bContext *C, wmOperator *UNUSED(op))
ARegion *region = CTX_wm_region(C);
if (outliner_flag_is_any_test(&space_outliner->tree, TSE_CLOSED, 1)) {
- outliner_flag_set(&space_outliner->tree, TSE_CLOSED, 0);
+ outliner_flag_set(*space_outliner, TSE_CLOSED, 0);
}
else {
- outliner_flag_set(&space_outliner->tree, TSE_CLOSED, 1);
+ outliner_flag_set(*space_outliner, TSE_CLOSED, 1);
}
ED_region_tag_redraw(region);
@@ -1169,13 +1178,13 @@ static int outliner_select_all_exec(bContext *C, wmOperator *op)
switch (action) {
case SEL_SELECT:
- outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 1);
+ outliner_flag_set(*space_outliner, TSE_SELECTED, 1);
break;
case SEL_DESELECT:
- outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
+ outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
break;
case SEL_INVERT:
- outliner_flag_flip(&space_outliner->tree, TSE_SELECTED);
+ outliner_flag_flip(*space_outliner, TSE_SELECTED);
break;
}
@@ -1211,32 +1220,16 @@ void OUTLINER_OT_select_all(wmOperatorType *ot)
/** \name View Show Active (Outliner) Operator
* \{ */
-static void outliner_set_coordinates_element_recursive(SpaceOutliner *space_outliner,
- TreeElement *te,
- int startx,
- int *starty)
-{
- TreeStoreElem *tselem = TREESTORE(te);
-
- /* store coord and continue, we need coordinates for elements outside view too */
- te->xs = (float)startx;
- te->ys = (float)(*starty);
- *starty -= UI_UNIT_Y;
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
- outliner_set_coordinates_element_recursive(space_outliner, ten, startx + UI_UNIT_X, starty);
- }
- }
-}
-
-void outliner_set_coordinates(ARegion *region, SpaceOutliner *space_outliner)
+void outliner_set_coordinates(const ARegion *region, const SpaceOutliner *space_outliner)
{
int starty = (int)(region->v2d.tot.ymax) - UI_UNIT_Y;
- LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
- outliner_set_coordinates_element_recursive(space_outliner, te, 0, &starty);
- }
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
+ /* store coord and continue, we need coordinates for elements outside view too */
+ te->xs = 0;
+ te->ys = (float)starty;
+ starty -= UI_UNIT_Y;
+ });
}
/* return 1 when levels were opened */
@@ -1624,11 +1617,11 @@ static int subtree_has_objects(ListBase *lb)
return 0;
}
-/* recursive helper function for Show Hierarchy operator */
-static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outliner, ListBase *lb)
+/* Helper function for Show Hierarchy operator */
+static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outliner)
{
/* open all object elems, close others */
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
if (ELEM(tselem->type,
@@ -1656,11 +1649,7 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outli
else {
tselem->flag |= TSE_CLOSED;
}
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- tree_element_show_hierarchy(scene, space_outliner, &te->subtree);
- }
- }
+ });
}
/* show entire object level hierarchy */
@@ -1671,7 +1660,7 @@ static int outliner_show_hierarchy_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
/* recursively open/close levels */
- tree_element_show_hierarchy(scene, space_outliner, &space_outliner->tree);
+ tree_element_show_hierarchy(scene, space_outliner);
ED_region_tag_redraw(region);
@@ -1873,79 +1862,75 @@ enum {
DRIVERS_EDITMODE_REMOVE,
} /*eDrivers_EditModes*/;
-/* Recursively iterate over tree, finding and working on selected items */
+/* Iterate over tree, finding and working on selected items */
static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
- ListBase *tree,
ReportList *reports,
short mode)
{
- LISTBASE_FOREACH (TreeElement *, te, tree) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
/* if item is selected, perform operation */
- if (tselem->flag & TSE_SELECTED) {
- ID *id = nullptr;
- char *path = nullptr;
- int array_index = 0;
- short flag = 0;
- short groupmode = KSP_GROUP_KSNAME;
-
- TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te);
- PointerRNA ptr = te_rna ? te_rna->getPointerRNA() : PointerRNA_NULL;
- PropertyRNA *prop = te_rna ? te_rna->getPropertyRNA() : nullptr;
-
- /* check if RNA-property described by this selected element is an animatable prop */
- if (prop && RNA_property_animateable(&ptr, prop)) {
- /* get id + path + index info from the selected element */
- tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
- }
+ if (!(tselem->flag & TSE_SELECTED)) {
+ return;
+ }
- /* only if ID and path were set, should we perform any actions */
- if (id && path) {
- short dflags = CREATEDRIVER_WITH_DEFAULT_DVAR;
- int arraylen = 1;
+ ID *id = nullptr;
+ char *path = nullptr;
+ int array_index = 0;
+ short flag = 0;
+ short groupmode = KSP_GROUP_KSNAME;
- /* array checks */
- if (flag & KSP_FLAG_WHOLE_ARRAY) {
- /* entire array was selected, so add drivers for all */
- arraylen = RNA_property_array_length(&ptr, prop);
- }
- else {
- arraylen = array_index;
- }
+ TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te);
+ PointerRNA ptr = te_rna ? te_rna->getPointerRNA() : PointerRNA_NULL;
+ PropertyRNA *prop = te_rna ? te_rna->getPropertyRNA() : nullptr;
- /* we should do at least one step */
- if (arraylen == array_index) {
- arraylen++;
- }
+ /* check if RNA-property described by this selected element is an animatable prop */
+ if (prop && RNA_property_animateable(&ptr, prop)) {
+ /* get id + path + index info from the selected element */
+ tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
+ }
- /* for each array element we should affect, add driver */
- for (; array_index < arraylen; array_index++) {
- /* action depends on mode */
- switch (mode) {
- case DRIVERS_EDITMODE_ADD: {
- /* add a new driver with the information obtained (only if valid) */
- ANIM_add_driver(reports, id, path, array_index, dflags, DRIVER_TYPE_PYTHON);
- break;
- }
- case DRIVERS_EDITMODE_REMOVE: {
- /* remove driver matching the information obtained (only if valid) */
- ANIM_remove_driver(reports, id, path, array_index, dflags);
- break;
- }
+ /* only if ID and path were set, should we perform any actions */
+ if (id && path) {
+ short dflags = CREATEDRIVER_WITH_DEFAULT_DVAR;
+ int arraylen = 1;
+
+ /* array checks */
+ if (flag & KSP_FLAG_WHOLE_ARRAY) {
+ /* entire array was selected, so add drivers for all */
+ arraylen = RNA_property_array_length(&ptr, prop);
+ }
+ else {
+ arraylen = array_index;
+ }
+
+ /* we should do at least one step */
+ if (arraylen == array_index) {
+ arraylen++;
+ }
+
+ /* for each array element we should affect, add driver */
+ for (; array_index < arraylen; array_index++) {
+ /* action depends on mode */
+ switch (mode) {
+ case DRIVERS_EDITMODE_ADD: {
+ /* add a new driver with the information obtained (only if valid) */
+ ANIM_add_driver(reports, id, path, array_index, dflags, DRIVER_TYPE_PYTHON);
+ break;
+ }
+ case DRIVERS_EDITMODE_REMOVE: {
+ /* remove driver matching the information obtained (only if valid) */
+ ANIM_remove_driver(reports, id, path, array_index, dflags);
+ break;
}
}
-
- /* free path, since it had to be generated */
- MEM_freeN(path);
}
- }
- /* go over sub-tree */
- if (TSELEM_OPEN(tselem, space_outliner)) {
- do_outliner_drivers_editop(space_outliner, &te->subtree, reports, mode);
+ /* free path, since it had to be generated */
+ MEM_freeN(path);
}
- }
+ });
}
/** \} */
@@ -1964,8 +1949,7 @@ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
}
/* recursively go into tree, adding selected items */
- do_outliner_drivers_editop(
- space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_ADD);
+ do_outliner_drivers_editop(space_outliner, op->reports, DRIVERS_EDITMODE_ADD);
/* send notifiers */
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, nullptr); /* XXX */
@@ -2004,8 +1988,7 @@ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
}
/* recursively go into tree, adding selected items */
- do_outliner_drivers_editop(
- space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_REMOVE);
+ do_outliner_drivers_editop(space_outliner, op->reports, DRIVERS_EDITMODE_REMOVE);
/* send notifiers */
WM_event_add_notifier(C, ND_KEYS, nullptr); /* XXX */
@@ -2072,68 +2055,64 @@ static KeyingSet *verify_active_keyingset(Scene *scene, short add)
return ks;
}
-/* Recursively iterate over tree, finding and working on selected items */
+/* Iterate over tree, finding and working on selected items */
static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner,
KeyingSet *ks,
- ListBase *tree,
- short mode)
+ const short mode)
{
- LISTBASE_FOREACH (TreeElement *, te, tree) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
/* if item is selected, perform operation */
- if (tselem->flag & TSE_SELECTED) {
- ID *id = nullptr;
- char *path = nullptr;
- int array_index = 0;
- short flag = 0;
- short groupmode = KSP_GROUP_KSNAME;
-
- /* check if RNA-property described by this selected element is an animatable prop */
- const TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te);
- PointerRNA ptr = te_rna->getPointerRNA();
- if (te_rna && te_rna->getPropertyRNA() &&
- RNA_property_animateable(&ptr, te_rna->getPropertyRNA())) {
- /* get id + path + index info from the selected element */
- tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
- }
+ if (!(tselem->flag & TSE_SELECTED)) {
+ return;
+ }
- /* only if ID and path were set, should we perform any actions */
- if (id && path) {
- /* action depends on mode */
- switch (mode) {
- case KEYINGSET_EDITMODE_ADD: {
- /* add a new path with the information obtained (only if valid) */
- /* TODO: what do we do with group name?
- * for now, we don't supply one, and just let this use the KeyingSet name */
- BKE_keyingset_add_path(ks, id, nullptr, path, array_index, flag, groupmode);
- ks->active_path = BLI_listbase_count(&ks->paths);
- break;
- }
- case KEYINGSET_EDITMODE_REMOVE: {
- /* find the relevant path, then remove it from the KeyingSet */
- KS_Path *ksp = BKE_keyingset_find_path(ks, id, nullptr, path, array_index, groupmode);
+ ID *id = nullptr;
+ char *path = nullptr;
+ int array_index = 0;
+ short flag = 0;
+ short groupmode = KSP_GROUP_KSNAME;
+
+ /* check if RNA-property described by this selected element is an animatable prop */
+ const TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te);
+ PointerRNA ptr = te_rna->getPointerRNA();
+ if (te_rna && te_rna->getPropertyRNA() &&
+ RNA_property_animateable(&ptr, te_rna->getPropertyRNA())) {
+ /* get id + path + index info from the selected element */
+ tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
+ }
- if (ksp) {
- /* free path's data */
- BKE_keyingset_free_path(ks, ksp);
+ /* only if ID and path were set, should we perform any actions */
+ if (id && path) {
+ /* action depends on mode */
+ switch (mode) {
+ case KEYINGSET_EDITMODE_ADD: {
+ /* add a new path with the information obtained (only if valid) */
+ /* TODO: what do we do with group name?
+ * for now, we don't supply one, and just let this use the KeyingSet name */
+ BKE_keyingset_add_path(ks, id, nullptr, path, array_index, flag, groupmode);
+ ks->active_path = BLI_listbase_count(&ks->paths);
+ break;
+ }
+ case KEYINGSET_EDITMODE_REMOVE: {
+ /* find the relevant path, then remove it from the KeyingSet */
+ KS_Path *ksp = BKE_keyingset_find_path(ks, id, nullptr, path, array_index, groupmode);
- ks->active_path = 0;
- }
- break;
+ if (ksp) {
+ /* free path's data */
+ BKE_keyingset_free_path(ks, ksp);
+
+ ks->active_path = 0;
}
+ break;
}
-
- /* free path, since it had to be generated */
- MEM_freeN(path);
}
- }
- /* go over sub-tree */
- if (TSELEM_OPEN(tselem, space_outliner)) {
- do_outliner_keyingset_editop(space_outliner, ks, &te->subtree, mode);
+ /* free path, since it had to be generated */
+ MEM_freeN(path);
}
- }
+ });
}
/** \} */
@@ -2158,7 +2137,7 @@ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
}
/* recursively go into tree, adding selected items */
- do_outliner_keyingset_editop(space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_ADD);
+ do_outliner_keyingset_editop(space_outliner, ks, KEYINGSET_EDITMODE_ADD);
/* send notifiers */
WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr);
@@ -2199,8 +2178,7 @@ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(o
}
/* recursively go into tree, adding selected items */
- do_outliner_keyingset_editop(
- space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_REMOVE);
+ do_outliner_keyingset_editop(space_outliner, ks, KEYINGSET_EDITMODE_REMOVE);
/* send notifiers */
WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr);
diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh
index f3bcb7b0f1e..a0dcb49aa43 100644
--- a/source/blender/editors/space_outliner/outliner_intern.hh
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -160,8 +160,6 @@ enum {
/* Child elements of the same type in the icon-row are drawn merged as one icon.
* This flag is set for an element that is part of these merged child icons. */
TE_ICONROW_MERGED = (1 << 7),
- /* This element has some warning to be displayed. */
- TE_HAS_WARNING = (1 << 8),
};
/* button events */
@@ -410,8 +408,12 @@ int outliner_flag_is_any_test(ListBase *lb, short flag, int curlevel);
* Set or unset \a flag for all outliner elements in \a lb and sub-trees.
* \return if any flag was modified.
*/
-bool outliner_flag_set(ListBase *lb, short flag, short set);
-bool outliner_flag_flip(ListBase *lb, short flag);
+extern "C++" {
+bool outliner_flag_set(const SpaceOutliner &space_outliner, short flag, short set);
+bool outliner_flag_set(const ListBase &lb, short flag, short set);
+bool outliner_flag_flip(const SpaceOutliner &space_outliner, short flag);
+bool outliner_flag_flip(const ListBase &lb, short flag);
+}
void item_rename_fn(struct bContext *C,
struct ReportList *reports,
@@ -453,7 +455,8 @@ void id_remap_fn(struct bContext *C,
/**
* To retrieve coordinates with redrawing the entire tree.
*/
-void outliner_set_coordinates(struct ARegion *region, struct SpaceOutliner *space_outliner);
+void outliner_set_coordinates(const struct ARegion *region,
+ const struct SpaceOutliner *space_outliner);
/**
* Open or close a tree element, optionally toggling all children recursively.
@@ -510,6 +513,11 @@ void OUTLINER_OT_drivers_delete_selected(struct wmOperatorType *ot);
void OUTLINER_OT_orphans_purge(struct wmOperatorType *ot);
+/* outliner_query.cc ---------------------------------------------- */
+
+bool outliner_shows_mode_column(const SpaceOutliner &space_outliner);
+bool outliner_has_element_warnings(const SpaceOutliner &space_outliner);
+
/* outliner_tools.c ---------------------------------------------- */
void merged_element_search_menu_invoke(struct bContext *C,
diff --git a/source/blender/editors/space_outliner/outliner_query.cc b/source/blender/editors/space_outliner/outliner_query.cc
new file mode 100644
index 00000000000..d6483c44fce
--- /dev/null
+++ b/source/blender/editors/space_outliner/outliner_query.cc
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include <functional>
+
+#include "BLI_listbase.h"
+
+#include "DNA_space_types.h"
+
+#include "outliner_intern.hh"
+#include "tree/tree_display.hh"
+
+using namespace blender::ed::outliner;
+
+bool outliner_shows_mode_column(const SpaceOutliner &space_outliner)
+{
+ const AbstractTreeDisplay &tree_display = *space_outliner.runtime->tree_display;
+
+ return tree_display.supportsModeColumn() && (space_outliner.flag & SO_MODE_COLUMN);
+}
+
+/**
+ * Iterate over the entire tree (including collapsed sub-elements), probing if any of the elements
+ * has a warning to be displayed.
+ */
+bool outliner_has_element_warnings(const SpaceOutliner &space_outliner)
+{
+ std::function<bool(const ListBase &)> recursive_fn;
+
+ recursive_fn = [&](const ListBase &lb) {
+ LISTBASE_FOREACH (const TreeElement *, te, &lb) {
+ if (te->abstract_element && !te->abstract_element->getWarning().is_empty()) {
+ return true;
+ }
+
+ if (recursive_fn(te->subtree)) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ return recursive_fn(space_outliner.tree);
+}
diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc
index fd0ee422df0..bd6d3d89706 100644
--- a/source/blender/editors/space_outliner/outliner_select.cc
+++ b/source/blender/editors/space_outliner/outliner_select.cc
@@ -66,7 +66,9 @@
#include "RNA_prototypes.h"
#include "outliner_intern.hh"
+#include "tree/tree_display.hh"
#include "tree/tree_element_seq.hh"
+#include "tree/tree_iterator.hh"
using namespace blender::ed::outliner;
@@ -1456,7 +1458,7 @@ void outliner_item_select(bContext *C,
/* Clear previous active when activating and clear selection when not extending selection */
const short clear_flag = (activate ? TSE_ACTIVE : 0) | (extend ? 0 : TSE_SELECTED);
if (clear_flag) {
- outliner_flag_set(&space_outliner->tree, clear_flag, false);
+ outliner_flag_set(*space_outliner, clear_flag, false);
}
if (select_flag & OL_ITEM_SELECT) {
@@ -1530,7 +1532,7 @@ static void do_outliner_range_select(bContext *C,
const bool active_selected = (tselem->flag & TSE_SELECTED);
if (!extend) {
- outliner_flag_set(&space_outliner->tree, TSE_SELECTED, false);
+ outliner_flag_set(*space_outliner, TSE_SELECTED, false);
}
/* Select active if under cursor */
@@ -1557,12 +1559,11 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *space_ou
bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2])
{
- /* Mode toggles only show in View Layer and Scenes modes. */
- if (!ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES)) {
+ if (!outliner_shows_mode_column(*space_outliner)) {
return false;
}
- return space_outliner->flag & SO_MODE_COLUMN && view_mval[0] < UI_UNIT_X;
+ return view_mval[0] < UI_UNIT_X;
}
static bool outliner_is_co_within_active_mode_column(bContext *C,
@@ -1604,7 +1605,7 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
if (!(te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]))) {
if (deselect_all) {
- changed |= outliner_flag_set(&space_outliner->tree, TSE_SELECTED, false);
+ changed |= outliner_flag_set(*space_outliner, TSE_SELECTED, false);
}
}
/* Don't allow toggle on scene collection */
@@ -1715,26 +1716,17 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
/** \name Box Select Operator
* \{ */
-static void outliner_item_box_select(bContext *C,
- SpaceOutliner *space_outliner,
- Scene *scene,
- rctf *rectf,
- TreeElement *te,
- bool select)
+static void outliner_box_select(bContext *C,
+ SpaceOutliner *space_outliner,
+ const rctf *rectf,
+ const bool select)
{
- TreeStoreElem *tselem = TREESTORE(te);
-
- if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) {
- outliner_item_select(
- C, space_outliner, te, (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | OL_ITEM_EXTEND);
- }
-
- /* Look at its children. */
- if (TSELEM_OPEN(tselem, space_outliner)) {
- LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
- outliner_item_box_select(C, space_outliner, scene, rectf, te_sub, select);
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
+ if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) {
+ outliner_item_select(
+ C, space_outliner, te, (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | OL_ITEM_EXTEND);
}
- }
+ });
}
static int outliner_box_select_exec(bContext *C, wmOperator *op)
@@ -1747,15 +1739,13 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
+ outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
}
WM_operator_properties_border_to_rctf(op, &rectf);
UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
- LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
- outliner_item_box_select(C, space_outliner, scene, &rectf, te, select);
- }
+ outliner_box_select(C, space_outliner, &rectf, select);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index cc81d5ed68d..3b018d59881 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -84,6 +84,7 @@
#include "outliner_intern.hh"
#include "tree/tree_element_rna.hh"
#include "tree/tree_element_seq.hh"
+#include "tree/tree_iterator.hh"
static CLG_LogRef LOG = {"ed.outliner.tools"};
@@ -412,11 +413,10 @@ static void outliner_do_libdata_operation(bContext *C,
ReportList *reports,
Scene *scene,
SpaceOutliner *space_outliner,
- ListBase *lb,
outliner_operation_fn operation_fn,
void *user_data)
{
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
@@ -425,11 +425,7 @@ static void outliner_do_libdata_operation(bContext *C,
operation_fn(C, reports, scene, te, tsep, tselem, user_data);
}
}
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_do_libdata_operation(
- C, reports, scene, space_outliner, &te->subtree, operation_fn, user_data);
- }
- }
+ });
}
/** \} */
@@ -763,6 +759,10 @@ static void id_local_fn(bContext *C,
struct OutlinerLibOverrideData {
bool do_hierarchy;
+
+ /** When creating new overrides, make them all user-editable. */
+ bool do_fully_editable;
+
/**
* For resync operation, force keeping newly created override IDs (or original linked IDs)
* instead of re-applying relevant existing ID pointer property override operations. Helps
@@ -957,7 +957,8 @@ static void id_override_library_create_fn(bContext *C,
id_root_reference,
id_hierarchy_root_reference,
id_instance_hint,
- &id_root_override);
+ &id_root_override,
+ data->do_fully_editable);
BLI_assert(id_root_override != nullptr);
BLI_assert(!ID_IS_LINKED(id_root_override));
@@ -1597,21 +1598,17 @@ static void outliner_do_data_operation(
SpaceOutliner *space_outliner,
int type,
int event,
- ListBase *lb,
void (*operation_fn)(int, TreeElement *, TreeStoreElem *, void *),
void *arg)
{
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == type) {
operation_fn(event, te, tselem, arg);
}
}
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_do_data_operation(space_outliner, type, event, &te->subtree, operation_fn, arg);
- }
- }
+ });
}
static Base *outliner_batch_delete_hierarchy(
@@ -1775,8 +1772,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
selection_changed = true;
break;
case OL_OP_REMAP:
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
+ outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_remap_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
break;
@@ -1979,6 +1975,7 @@ enum eOutlinerIdOpTypes {
OUTLINER_IDOP_LOCAL,
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY,
+ OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY,
@@ -2024,6 +2021,12 @@ static const EnumPropertyItem prop_id_op_types[] = {
"Make Library Override Hierarchy",
"Make a local override of this linked data-block, and its hierarchy of dependencies - only "
"applies to active Outliner item"},
+ {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE,
+ "OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE",
+ 0,
+ "Make Library Override Hierarchy Fully Editable",
+ "Make a local override of this linked data-block, and its hierarchy of dependencies, making "
+ "them all fully user-editable - only applies to active Outliner item"},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE,
"OVERRIDE_LIBRARY_MAKE_EDITABLE",
0,
@@ -2103,6 +2106,7 @@ static bool outliner_id_operation_item_poll(bContext *C,
}
return false;
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY:
+ case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE:
if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id) || (ID_IS_LINKED(tselem->id))) {
return true;
}
@@ -2179,13 +2183,8 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_UNLINK: {
/* unlink datablock from its parent */
if (objectlevel) {
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- unlink_object_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_object_fn, nullptr);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr);
ED_undo_push(C, "Unlink Object");
@@ -2194,61 +2193,36 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- unlink_action_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_action_fn, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Unlink action");
break;
case ID_MA:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- unlink_material_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_material_fn, nullptr);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, nullptr);
ED_undo_push(C, "Unlink material");
break;
case ID_TE:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- unlink_texture_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_texture_fn, nullptr);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, nullptr);
ED_undo_push(C, "Unlink texture");
break;
case ID_WO:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- unlink_world_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_world_fn, nullptr);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr);
ED_undo_push(C, "Unlink world");
break;
case ID_GR:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- unlink_collection_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_collection_fn, nullptr);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr);
ED_undo_push(C, "Unlink Collection");
@@ -2261,20 +2235,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_LOCAL: {
/* make local */
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_local_fn, nullptr);
+ outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_local_fn, nullptr);
ED_undo_push(C, "Localized Data");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE: {
OutlinerLibOverrideData override_data{};
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_create_fn,
- &override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_create_fn, &override_data);
ED_undo_push(C, "Overridden Data");
break;
}
@@ -2285,19 +2253,30 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
op->reports,
scene,
space_outliner,
- &space_outliner->tree,
id_override_library_create_hierarchy_pre_process_fn,
&override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_create_fn, &override_data);
+ id_override_library_create_hierarchy_post_process(C, &override_data);
+
+ ED_undo_push(C, "Overridden Data Hierarchy");
+ break;
+ }
+ case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
+ override_data.do_fully_editable = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
- &space_outliner->tree,
- id_override_library_create_fn,
+ id_override_library_create_hierarchy_pre_process_fn,
&override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_create_fn, &override_data);
id_override_library_create_hierarchy_post_process(C, &override_data);
- ED_undo_push(C, "Overridden Data Hierarchy");
+ ED_undo_push(C, "Overridden Data Hierarchy Fully Editable");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE: {
@@ -2305,7 +2284,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
op->reports,
scene,
space_outliner,
- &space_outliner->tree,
id_override_library_toggle_flag_fn,
POINTER_FROM_UINT(IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED));
@@ -2314,39 +2292,24 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: {
OutlinerLibOverrideData override_data{};
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_reset_fn,
- &override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_reset_fn, &override_data);
ED_undo_push(C, "Reset Overridden Data");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: {
OutlinerLibOverrideData override_data{};
override_data.do_hierarchy = true;
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_reset_fn,
- &override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_reset_fn, &override_data);
ED_undo_push(C, "Reset Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: {
OutlinerLibOverrideData override_data{};
override_data.do_hierarchy = true;
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_resync_fn,
- &override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_resync_fn, &override_data);
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
@@ -2354,35 +2317,20 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
OutlinerLibOverrideData override_data{};
override_data.do_hierarchy = true;
override_data.do_resync_hierarchy_enforce = true;
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_resync_fn,
- &override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_resync_fn, &override_data);
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY: {
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_clear_hierarchy_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_clear_hierarchy_fn, nullptr);
ED_undo_push(C, "Clear Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE: {
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_clear_single_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_clear_single_fn, nullptr);
ED_undo_push(C, "Clear Overridden Data Hierarchy");
break;
}
@@ -2390,26 +2338,16 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
/* make single user */
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- singleuser_action_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, singleuser_action_fn, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Single-User Action");
break;
case ID_WO:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- singleuser_world_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, singleuser_world_fn, nullptr);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr);
ED_undo_push(C, "Single-User World");
@@ -2424,15 +2362,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_DELETE: {
if (idlevel > 0) {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, nullptr);
+ C, op->reports, scene, space_outliner, id_delete_fn, nullptr);
ED_undo_push(C, "Delete");
}
break;
}
case OUTLINER_IDOP_REMAP: {
if (idlevel > 0) {
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
+ outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_remap_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
}
@@ -2455,13 +2392,8 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_FAKE_ADD: {
/* set fake user */
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_fake_user_set_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_fake_user_set_fn, nullptr);
WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Add Fake User");
@@ -2469,13 +2401,8 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_FAKE_CLEAR: {
/* clear fake user */
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_fake_user_clear_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_fake_user_clear_fn, nullptr);
WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Clear Fake User");
@@ -2484,20 +2411,15 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_RENAME: {
/* rename */
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, nullptr);
+ C, op->reports, scene, space_outliner, item_rename_fn, nullptr);
WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Rename");
break;
}
case OUTLINER_IDOP_SELECT_LINKED:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_select_linked_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_select_linked_fn, nullptr);
ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Select");
break;
@@ -2580,21 +2502,19 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
eOutlinerLibOpTypes event = (eOutlinerLibOpTypes)RNA_enum_get(op->ptr, "type");
switch (event) {
case OL_LIB_DELETE: {
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, nullptr);
+ outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_delete_fn, nullptr);
ED_undo_push(C, "Delete Library");
break;
}
case OL_LIB_RELOCATE: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, lib_relocate_fn, nullptr);
+ C, op->reports, scene, space_outliner, lib_relocate_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
break;
}
case OL_LIB_RELOAD: {
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, lib_reload_fn, nullptr);
+ outliner_do_libdata_operation(C, op->reports, scene, space_outliner, lib_reload_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
break;
@@ -2637,11 +2557,10 @@ void OUTLINER_OT_lib_operation(wmOperatorType *ot)
static void outliner_do_id_set_operation(
SpaceOutliner *space_outliner,
int type,
- ListBase *lb,
ID *newid,
void (*operation_fn)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *))
{
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == type) {
@@ -2649,10 +2568,7 @@ static void outliner_do_id_set_operation(
operation_fn(te, tselem, tsep, newid);
}
}
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_do_id_set_operation(space_outliner, type, &te->subtree, newid, operation_fn);
- }
- }
+ });
}
static void actionset_id_fn(TreeElement *UNUSED(te),
@@ -2707,12 +2623,10 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
/* perform action if valid channel */
if (datalevel == TSE_ANIM_DATA) {
- outliner_do_id_set_operation(
- space_outliner, datalevel, &space_outliner->tree, (ID *)act, actionset_id_fn);
+ outliner_do_id_set_operation(space_outliner, datalevel, (ID *)act, actionset_id_fn);
}
else if (idlevel == ID_AC) {
- outliner_do_id_set_operation(
- space_outliner, idlevel, &space_outliner->tree, (ID *)act, actionset_id_fn);
+ outliner_do_id_set_operation(space_outliner, idlevel, (ID *)act, actionset_id_fn);
}
else {
return OPERATOR_CANCELLED;
@@ -2799,8 +2713,7 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
switch (event) {
case OUTLINER_ANIMOP_CLEAR_ADT:
/* Remove Animation Data - this may remove the active action, in some cases... */
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, clear_animdata_fn, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, clear_animdata_fn, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Clear Animation Data");
@@ -2817,32 +2730,23 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_ANIMOP_CLEAR_ACT:
/* clear active action - using standard rules */
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, unlinkact_animdata_fn, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, unlinkact_animdata_fn, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Unlink action");
break;
case OUTLINER_ANIMOP_REFRESH_DRV:
- outliner_do_data_operation(space_outliner,
- datalevel,
- event,
- &space_outliner->tree,
- refreshdrivers_animdata_fn,
- nullptr);
+ outliner_do_data_operation(
+ space_outliner, datalevel, event, refreshdrivers_animdata_fn, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
// ED_undo_push(C, "Refresh Drivers"); /* No undo needed - shouldn't have any impact? */
break;
case OUTLINER_ANIMOP_CLEAR_DRV:
- outliner_do_data_operation(space_outliner,
- datalevel,
- event,
- &space_outliner->tree,
- cleardrivers_animdata_fn,
- nullptr);
+ outliner_do_data_operation(
+ space_outliner, datalevel, event, cleardrivers_animdata_fn, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
ED_undo_push(C, "Clear Drivers");
@@ -2892,8 +2796,7 @@ static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
eOutliner_PropConstraintOps event = (eOutliner_PropConstraintOps)RNA_enum_get(op->ptr, "type");
- outliner_do_data_operation(
- space_outliner, TSE_CONSTRAINT, event, &space_outliner->tree, constraint_fn, C);
+ outliner_do_data_operation(space_outliner, TSE_CONSTRAINT, event, constraint_fn, C);
if (event == OL_CONSTRAINTOP_DELETE) {
outliner_cleanup_tree(space_outliner);
@@ -2939,8 +2842,7 @@ static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
eOutliner_PropModifierOps event = (eOutliner_PropModifierOps)RNA_enum_get(op->ptr, "type");
- outliner_do_data_operation(
- space_outliner, TSE_MODIFIER, event, &space_outliner->tree, modifier_fn, C);
+ outliner_do_data_operation(space_outliner, TSE_MODIFIER, event, modifier_fn, C);
if (event == OL_MODIFIER_OP_DELETE) {
outliner_cleanup_tree(space_outliner);
@@ -2983,24 +2885,21 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
eOutliner_PropDataOps event = (eOutliner_PropDataOps)RNA_enum_get(op->ptr, "type");
switch (datalevel) {
case TSE_POSE_CHANNEL: {
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, pchan_fn, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, pchan_fn, nullptr);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "PoseChannel operation");
break;
}
case TSE_BONE: {
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, bone_fn, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, bone_fn, nullptr);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "Bone operation");
break;
}
case TSE_EBONE: {
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, ebone_fn, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, ebone_fn, nullptr);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "EditBone operation");
@@ -3008,16 +2907,14 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
}
case TSE_SEQUENCE: {
Scene *scene = CTX_data_scene(C);
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, sequence_fn, scene);
+ outliner_do_data_operation(space_outliner, datalevel, event, sequence_fn, scene);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
ED_undo_push(C, "Sequencer operation");
break;
}
case TSE_GP_LAYER: {
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, gpencil_layer_fn, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, gpencil_layer_fn, nullptr);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, nullptr);
ED_undo_push(C, "Grease Pencil Layer operation");
@@ -3025,8 +2922,7 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
}
case TSE_RNA_STRUCT:
if (event == OL_DOP_SELECT_LINKED) {
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, data_select_linked_fn, C);
+ outliner_do_data_operation(space_outliner, datalevel, event, data_select_linked_fn, C);
}
break;
diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc
index bbd9b48c260..7b3ce499929 100644
--- a/source/blender/editors/space_outliner/outliner_tree.cc
+++ b/source/blender/editors/space_outliner/outliner_tree.cc
@@ -919,10 +919,6 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
BLI_assert_msg(false, "Element type should already use new AbstractTreeElement design");
}
- if (tree_element_warnings_get(te, nullptr, nullptr)) {
- te->flag |= TE_HAS_WARNING;
- }
-
return te;
}
diff --git a/source/blender/editors/space_outliner/outliner_utils.cc b/source/blender/editors/space_outliner/outliner_utils.cc
index 4b947154864..0db612ce6db 100644
--- a/source/blender/editors/space_outliner/outliner_utils.cc
+++ b/source/blender/editors/space_outliner/outliner_utils.cc
@@ -27,6 +27,9 @@
#include "UI_view2d.h"
#include "outliner_intern.hh"
+#include "tree/tree_iterator.hh"
+
+using namespace blender::ed::outliner;
/* -------------------------------------------------------------------- */
/** \name Tree View Context
diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc
index 97dc659155f..5bcd1edebc0 100644
--- a/source/blender/editors/space_outliner/space_outliner.cc
+++ b/source/blender/editors/space_outliner/space_outliner.cc
@@ -438,7 +438,7 @@ static void outliner_deactivate(struct ScrArea *area)
{
/* Remove hover highlights */
SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
- outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED_ANY, false);
+ outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY, false);
ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc
index 141c68594e8..6ab497b3fbb 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display.cc
@@ -45,9 +45,9 @@ std::unique_ptr<AbstractTreeDisplay> AbstractTreeDisplay::createFromDisplayMode(
return nullptr;
}
-bool AbstractTreeDisplay::hasWarnings() const
+bool AbstractTreeDisplay::supportsModeColumn() const
{
- return has_warnings;
+ return false;
}
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index 327f29aa15e..190e35c81d6 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -75,12 +75,16 @@ class AbstractTreeDisplay {
*/
virtual ListBase buildTree(const TreeSourceData &source_data) = 0;
- /** Accessor to whether given tree has some warnings to display. */
- bool hasWarnings() const;
+ /**
+ * Define if the display mode should be allowed to show a mode column on the left. This column
+ * adds an icon to indicate which objects are in the current mode (edit mode, pose mode, etc.)
+ * and allows adding other objects to the mode by clicking the icon.
+ *
+ * Returns false by default.
+ */
+ virtual bool supportsModeColumn() const;
protected:
- bool has_warnings = false;
-
/** All derived classes will need a handle to this, so storing it in the base for convenience. */
SpaceOutliner &space_outliner_;
};
@@ -100,6 +104,8 @@ class TreeDisplayViewLayer final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
+ bool supportsModeColumn() const override;
+
private:
void add_view_layer(Scene &, ListBase &, TreeElement *);
void add_layer_collections_recursive(ListBase &, ListBase &, TreeElement &);
@@ -212,6 +218,8 @@ class TreeDisplayScenes final : public AbstractTreeDisplay {
TreeDisplayScenes(SpaceOutliner &space_outliner);
ListBase buildTree(const TreeSourceData &source_data) override;
+
+ bool supportsModeColumn() const override;
};
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
index 476bbdb63ae..46a89f17687 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
@@ -136,9 +136,6 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase
tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
tenlib->name = IFACE_("Current File");
}
- if (tenlib->flag & TE_HAS_WARNING) {
- has_warnings = true;
- }
}
/* Create data-block list parent element on demand. */
diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
index 9e00a425a5a..6b1de7f8b95 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
@@ -26,6 +26,11 @@ TreeDisplayScenes::TreeDisplayScenes(SpaceOutliner &space_outliner)
{
}
+bool TreeDisplayScenes::supportsModeColumn() const
+{
+ return true;
+}
+
ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data)
{
/* On first view we open scenes. */
diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
index 19811e45b90..80b3365766a 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
@@ -55,6 +55,11 @@ TreeDisplayViewLayer::TreeDisplayViewLayer(SpaceOutliner &space_outliner)
{
}
+bool TreeDisplayViewLayer::supportsModeColumn() const
+{
+ return true;
+}
+
ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data)
{
ListBase tree = {nullptr};
diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc
index 1e3fd2df7c2..94d55b70e3c 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element.cc
@@ -100,6 +100,11 @@ std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const i
return nullptr;
}
+StringRefNull AbstractTreeElement::getWarning() const
+{
+ return "";
+}
+
void AbstractTreeElement::uncollapse_by_default(TreeElement *legacy_te)
{
if (!TREESTORE(legacy_te)->used) {
@@ -118,39 +123,4 @@ void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner
tree_element.expand(space_outliner);
}
-bool tree_element_warnings_get(TreeElement *te, int *r_icon, const char **r_message)
-{
- TreeStoreElem *tselem = te->store_elem;
-
- if (tselem->type != TSE_SOME_ID) {
- return false;
- }
- if (te->idcode != ID_LI) {
- return false;
- }
-
- Library *library = (Library *)tselem->id;
- if (library->tag & LIBRARY_TAG_RESYNC_REQUIRED) {
- if (r_icon) {
- *r_icon = ICON_ERROR;
- }
- if (r_message) {
- *r_message = TIP_(
- "Contains linked library overrides that need to be resynced, updating the library is "
- "recommended");
- }
- return true;
- }
- if (library->id.tag & LIB_TAG_MISSING) {
- if (r_icon) {
- *r_icon = ICON_ERROR;
- }
- if (r_message) {
- *r_message = TIP_("Missing library");
- }
- return true;
- }
- return false;
-}
-
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh
index c6593a517dd..0dcd75d340d 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element.hh
@@ -8,6 +8,8 @@
#include <memory>
+#include "BLI_string_ref.hh"
+
struct ListBase;
struct SpaceOutliner;
struct TreeElement;
@@ -56,6 +58,12 @@ class AbstractTreeElement {
}
/**
+ * By letting this return a warning message, the tree element will display a warning icon with
+ * the message in the tooltip.
+ */
+ virtual StringRefNull getWarning() const;
+
+ /**
* Expand this tree element if it is displayed for the first time (as identified by its
* tree-store element).
*
@@ -96,13 +104,4 @@ struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner);
-/**
- * Get actual warning data of a tree element, if any.
- *
- * \param r_icon: The icon to display as warning.
- * \param r_message: The message to display as warning.
- * \return true if there is a warning, false otherwise.
- */
-bool tree_element_warnings_get(struct TreeElement *te, int *r_icon, const char **r_message);
-
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
index 0dcaec0385a..4f1b951ccaf 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
@@ -4,6 +4,8 @@
* \ingroup spoutliner
*/
+#include "BLT_translation.h"
+
#include "DNA_ID.h"
#include "DNA_listBase.h"
@@ -24,4 +26,21 @@ bool TreeElementIDLibrary::isExpandValid() const
return true;
}
+StringRefNull TreeElementIDLibrary::getWarning() const
+{
+ Library &library = reinterpret_cast<Library &>(id_);
+
+ if (library.tag & LIBRARY_TAG_RESYNC_REQUIRED) {
+ return TIP_(
+ "Contains linked library overrides that need to be resynced, updating the library is "
+ "recommended");
+ }
+
+ if (library.id.tag & LIB_TAG_MISSING) {
+ return TIP_("Missing library");
+ }
+
+ return {};
+}
+
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
index ed599cf04da..2d89b55813f 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
@@ -17,6 +17,8 @@ class TreeElementIDLibrary final : public TreeElementID {
TreeElementIDLibrary(TreeElement &legacy_te, Library &library);
bool isExpandValid() const override;
+
+ blender::StringRefNull getWarning() const override;
};
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
index 3a039da86c2..53e7b88c923 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -38,6 +38,19 @@ TreeElementOverridesBase::TreeElementOverridesBase(TreeElement &legacy_te, ID &i
}
}
+StringRefNull TreeElementOverridesBase::getWarning() const
+{
+ if (id.flag & LIB_LIB_OVERRIDE_RESYNC_LEFTOVER) {
+ return TIP_("This override data-block is not needed anymore, but was detected as user-edited");
+ }
+
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(&id) && ID_REAL_USERS(&id) == 0) {
+ return TIP_("This override data-block is unused");
+ }
+
+ return {};
+}
+
void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
{
BLI_assert(id.override_library != nullptr);
@@ -93,4 +106,15 @@ TreeElementOverridesProperty::TreeElementOverridesProperty(TreeElement &legacy_t
legacy_te.name = override_data.override_property.rna_path;
}
+StringRefNull TreeElementOverridesProperty::getWarning() const
+{
+ if (!is_rna_path_valid) {
+ return TIP_(
+ "This override property does not exist in current data, it will be removed on "
+ "next .blend file save");
+ }
+
+ return {};
+}
+
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
index b42e1c37a0f..1db46d9af1d 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
@@ -34,6 +34,8 @@ class TreeElementOverridesBase final : public AbstractTreeElement {
TreeElementOverridesBase(TreeElement &legacy_te, ID &id);
void expand(SpaceOutliner &) const override;
+
+ StringRefNull getWarning() const override;
};
class TreeElementOverridesProperty final : public AbstractTreeElement {
@@ -46,6 +48,8 @@ class TreeElementOverridesProperty final : public AbstractTreeElement {
public:
TreeElementOverridesProperty(TreeElement &legacy_te, TreeElementOverridesData &override_data);
+
+ StringRefNull getWarning() const override;
};
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.cc b/source/blender/editors/space_outliner/tree/tree_iterator.cc
new file mode 100644
index 00000000000..85ff9e6437e
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_iterator.cc
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "DNA_space_types.h"
+
+#include "BLI_listbase.h"
+
+#include "../outliner_intern.hh"
+
+#include "tree_iterator.hh"
+
+namespace blender::ed::outliner::tree_iterator {
+
+void all(const SpaceOutliner &space_outliner, const VisitorFn visitor)
+{
+ all_open(space_outliner, space_outliner.tree, visitor);
+}
+
+void all(const ListBase &subtree, const VisitorFn visitor)
+{
+ LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) {
+ /* Get needed data out in case element gets freed. */
+ const ListBase subtree = element->subtree;
+
+ visitor(element);
+ /* Don't access element from now on, it may be freed. */
+
+ all(subtree, visitor);
+ }
+}
+
+void all_open(const SpaceOutliner &space_outliner, const VisitorFn visitor)
+{
+ all_open(space_outliner, space_outliner.tree, visitor);
+}
+
+void all_open(const SpaceOutliner &space_outliner,
+ const ListBase &subtree,
+ const VisitorFn visitor)
+{
+ LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) {
+ /* Get needed data out in case element gets freed. */
+ const bool is_open = TSELEM_OPEN(element->store_elem, &space_outliner);
+ const ListBase subtree = element->subtree;
+
+ visitor(element);
+ /* Don't access element from now on, it may be freed. */
+
+ if (is_open) {
+ all_open(space_outliner, subtree, visitor);
+ }
+ }
+}
+
+} // namespace blender::ed::outliner::tree_iterator
diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.hh b/source/blender/editors/space_outliner/tree/tree_iterator.hh
new file mode 100644
index 00000000000..e3b3c90eaad
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_iterator.hh
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#pragma once
+
+#include "BLI_function_ref.hh"
+
+struct ListBase;
+struct SpaceOutliner;
+struct TreeElement;
+
+namespace blender::ed::outliner {
+namespace tree_iterator {
+
+using VisitorFn = FunctionRef<void(TreeElement *)>;
+
+/**
+ * Preorder (meaning depth-first) traversal of all elements (regardless of collapsed state).
+ * Freeing the currently visited element in \a visitor is fine.
+ */
+void all(const SpaceOutliner &space_outliner, VisitorFn visitor);
+void all(const ListBase &subtree, VisitorFn visitor);
+
+/**
+ * Preorder (meaning depth-first) traversal of all elements not part of a collapsed sub-tree.
+ * Freeing the currently visited element in \a visitor is fine.
+ */
+void all_open(const SpaceOutliner &, VisitorFn visitor);
+void all_open(const SpaceOutliner &, const ListBase &subtree, VisitorFn visitor);
+
+} // namespace tree_iterator
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index a02058fde6b..48abe71e35f 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -590,16 +590,15 @@ static bool view3d_mat_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
static char *view3d_mat_drop_tooltip(bContext *C,
wmDrag *drag,
const int xy[2],
- struct wmDropBox *drop)
+ wmDropBox *UNUSED(drop))
{
const char *name = WM_drag_get_item_name(drag);
ARegion *region = CTX_wm_region(C);
- RNA_string_set(drop->ptr, "name", name);
int mval[2] = {
xy[0] - region->winrct.xmin,
xy[1] - region->winrct.ymin,
};
- return ED_object_ot_drop_named_material_tooltip(C, drop->ptr, mval);
+ return ED_object_ot_drop_named_material_tooltip(C, name, mval);
}
static bool view3d_world_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -716,7 +715,7 @@ static void view3d_ob_drop_copy_local_id(bContext *UNUSED(C), wmDrag *drag, wmDr
{
ID *id = WM_drag_get_local_ID(drag, ID_OB);
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_int_set(drop->ptr, "session_uuid", id->session_uuid);
/* Don't duplicate ID's which were just imported. Only do that for existing, local IDs. */
BLI_assert(drag->type != WM_DRAG_ASSET);
@@ -751,7 +750,7 @@ static void view3d_ob_drop_copy_external_asset(bContext *UNUSED(C), wmDrag *drag
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_int_set(drop->ptr, "session_uuid", id->session_uuid);
Base *base = BKE_view_layer_base_find(view_layer, (Object *)id);
if (base != NULL) {
@@ -823,15 +822,15 @@ static void view3d_id_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *dr
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ WM_operator_properties_id_lookup_set_from_id(drop->ptr, id);
}
static void view3d_id_drop_copy_with_type(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
- RNA_string_set(drop->ptr, "name", id->name + 2);
RNA_enum_set(drop->ptr, "type", GS(id->name));
+ WM_operator_properties_id_lookup_set_from_id(drop->ptr, id);
}
static void view3d_id_path_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
@@ -839,7 +838,7 @@ static void view3d_id_path_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBo
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
if (id) {
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ WM_operator_properties_id_lookup_set_from_id(drop->ptr, id);
RNA_struct_property_unset(drop->ptr, "filepath");
}
else if (drag->path[0]) {
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index e52ff062302..9f8d7afd9a8 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -608,7 +608,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign");
+ WM_operator_properties_id_lookup(ot, true);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
@@ -678,10 +678,8 @@ static int drop_world_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- char name[MAX_ID_NAME - 2];
-
- RNA_string_get(op->ptr, "name", name);
- World *world = (World *)BKE_libblock_find_name(bmain, ID_WO, name);
+ World *world = (World *)WM_operator_properties_id_lookup_from_name_or_session_uuid(
+ bmain, op->ptr, ID_WO);
if (world == NULL) {
return OPERATOR_CANCELLED;
}
@@ -718,7 +716,7 @@ void VIEW3D_OT_drop_world(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
- RNA_def_string(ot->srna, "name", "World", MAX_ID_NAME - 2, "Name", "World to assign");
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index cbc2cab0a7a..deae51a1149 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -197,11 +197,7 @@ void recalcData_sequencer_image(TransInfo *t)
/* Rotation. Scaling can cause negative rotation. */
if (t->mode == TFM_ROTATION) {
- const float orig_dir[2] = {cosf(tdseq->orig_rotation), sinf(tdseq->orig_rotation)};
- float rotation = angle_signed_v2v2(handle_x, orig_dir) * mirror[0] * mirror[1];
- transform->rotation = tdseq->orig_rotation + rotation;
- transform->rotation += DEG2RAD(360.0);
- transform->rotation = fmod(transform->rotation, DEG2RAD(360.0));
+ transform->rotation = tdseq->orig_rotation - t->values_final[0];
}
SEQ_relations_invalidate_cache_preprocessed(t->scene, seq);
}
@@ -209,9 +205,6 @@ void recalcData_sequencer_image(TransInfo *t)
void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *t)
{
- if (t->state == TRANS_CANCEL) {
- return;
- }
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
TransData *td = NULL;
@@ -225,8 +218,14 @@ void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *
TransDataSeq *tdseq = td->extra;
Sequence *seq = tdseq->seq;
StripTransform *transform = seq->strip->transform;
- Scene *scene = t->scene;
+ if (t->state == TRANS_CANCEL) {
+ if (t->mode == TFM_ROTATION) {
+ transform->rotation = tdseq->orig_rotation;
+ }
+ continue;
+ }
+ Scene *scene = t->scene;
RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr);
if (t->mode == TFM_ROTATION) {
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index c0ea753ed51..84dca352c9f 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -103,7 +103,7 @@ static bool ED_uvedit_ensure_uvs(Object *obedit)
int cd_loop_uv_offset;
if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
- ED_mesh_uv_texture_add(obedit->data, NULL, true, true, NULL);
+ ED_mesh_uv_add(obedit->data, NULL, true, true, NULL);
}
/* Happens when there are no faces. */
@@ -339,7 +339,6 @@ static ParamHandle *construct_param_handle(const Scene *scene,
const UnwrapOptions *options,
UnwrapResultInfo *result_info)
{
- ParamHandle *handle;
BMFace *efa;
BMLoop *l;
BMEdge *eed;
@@ -348,7 +347,7 @@ static ParamHandle *construct_param_handle(const Scene *scene,
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- handle = GEO_uv_parametrizer_construct_begin();
+ ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
if (options->correct_aspect) {
float aspx, aspy;
@@ -417,14 +416,13 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
const UnwrapOptions *options,
int *count_fail)
{
- ParamHandle *handle;
BMFace *efa;
BMLoop *l;
BMEdge *eed;
BMIter iter, liter;
int i;
- handle = GEO_uv_parametrizer_construct_begin();
+ ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
if (options->correct_aspect) {
Object *ob = objects[0];
@@ -539,7 +537,6 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
const UnwrapOptions *options,
UnwrapResultInfo *result_info)
{
- ParamHandle *handle;
/* index pointers */
MPoly *mpoly;
MLoop *mloop;
@@ -571,7 +568,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- handle = GEO_uv_parametrizer_construct_begin();
+ ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
if (options->correct_aspect) {
float aspx, aspy;
@@ -1023,8 +1020,7 @@ static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm)
bool rotate = true;
bool ignore_pinned = false;
- ParamHandle *handle;
- handle = construct_param_handle(scene, ob, bm, &options, NULL);
+ ParamHandle *handle = construct_param_handle(scene, ob, bm, &options, NULL);
GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
@@ -1043,8 +1039,7 @@ static void uvedit_pack_islands_multi(const Scene *scene,
bool rotate,
bool ignore_pinned)
{
- ParamHandle *handle;
- handle = construct_param_handle_multi(scene, objects, objects_len, options, NULL);
+ ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options, NULL);
GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
@@ -3038,7 +3033,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
* since we are not in edit mode we need to ensure only the uv flags are tested */
scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION;
- ED_mesh_uv_texture_ensure(me, NULL);
+ ED_mesh_uv_ensure(me, NULL);
BM_mesh_bm_from_me(bm,
me,
diff --git a/source/blender/geometry/GEO_uv_parametrizer.h b/source/blender/geometry/GEO_uv_parametrizer.h
index a5194883cf2..624b0695aa3 100644
--- a/source/blender/geometry/GEO_uv_parametrizer.h
+++ b/source/blender/geometry/GEO_uv_parametrizer.h
@@ -12,8 +12,8 @@
extern "C" {
#endif
-typedef void ParamHandle; /* handle to a set of charts */
-typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */
+typedef struct ParamHandle ParamHandle; /* Handle to an array of charts. */
+typedef intptr_t ParamKey; /* Key (hash) for identifying verts and faces. */
typedef enum ParamBool {
PARAM_TRUE = 1,
PARAM_FALSE = 0,
diff --git a/source/blender/geometry/intern/uv_parametrizer.c b/source/blender/geometry/intern/uv_parametrizer.c
index e25fff0d6b8..ad4b051a6c2 100644
--- a/source/blender/geometry/intern/uv_parametrizer.c
+++ b/source/blender/geometry/intern/uv_parametrizer.c
@@ -59,7 +59,6 @@ typedef struct PHash {
struct PChart;
struct PEdge;
struct PFace;
-struct PHandle;
struct PVert;
/* Simplices */
@@ -171,7 +170,7 @@ typedef struct PChart {
} u;
uchar flag;
- struct PHandle *handle;
+ ParamHandle *handle;
} PChart;
enum PChartFlag {
@@ -185,7 +184,7 @@ enum PHandleState {
PHANDLE_STATE_STRETCH,
};
-typedef struct PHandle {
+typedef struct ParamHandle {
enum PHandleState state;
MemArena *arena;
MemArena *polyfill_arena;
@@ -204,7 +203,7 @@ typedef struct PHandle {
RNG *rng;
float blend;
bool do_aspect;
-} PHandle;
+} ParamHandle;
/* PHash
* - special purpose hash that keeps all its elements in a single linked list.
@@ -637,7 +636,7 @@ static void p_chart_topological_sanity_check(PChart *chart)
/* Loading / Flushing */
-static void p_vert_load_pin_select_uvs(PHandle *handle, PVert *v)
+static void p_vert_load_pin_select_uvs(ParamHandle *handle, PVert *v)
{
PEdge *e;
int nedges = 0, npins = 0;
@@ -679,7 +678,7 @@ static void p_vert_load_pin_select_uvs(PHandle *handle, PVert *v)
}
}
-static void p_flush_uvs(PHandle *handle, PChart *chart)
+static void p_flush_uvs(ParamHandle *handle, PChart *chart)
{
PEdge *e;
@@ -691,7 +690,7 @@ static void p_flush_uvs(PHandle *handle, PChart *chart)
}
}
-static void p_flush_uvs_blend(PHandle *handle, PChart *chart, float blend)
+static void p_flush_uvs_blend(ParamHandle *handle, PChart *chart, float blend)
{
PEdge *e;
float invblend = 1.0f - blend;
@@ -742,7 +741,7 @@ static void p_face_restore_uvs(PFace *f)
/* Construction (use only during construction, relies on u.key being set */
-static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge *e)
+static PVert *p_vert_add(ParamHandle *handle, PHashKey key, const float co[3], PEdge *e)
{
PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v));
copy_v3_v3(v->co, co);
@@ -765,7 +764,7 @@ static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge
return v;
}
-static PVert *p_vert_lookup(PHandle *handle, PHashKey key, const float co[3], PEdge *e)
+static PVert *p_vert_lookup(ParamHandle *handle, PHashKey key, const float co[3], PEdge *e)
{
PVert *v = (PVert *)phash_lookup(handle->hash_verts, key);
@@ -789,7 +788,7 @@ static PVert *p_vert_copy(PChart *chart, PVert *v)
return nv;
}
-static PEdge *p_edge_lookup(PHandle *handle, const PHashKey *vkeys)
+static PEdge *p_edge_lookup(ParamHandle *handle, const PHashKey *vkeys)
{
PHashKey key = PHASH_edge(vkeys[0], vkeys[1]);
PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
@@ -808,9 +807,8 @@ static PEdge *p_edge_lookup(PHandle *handle, const PHashKey *vkeys)
return NULL;
}
-static int p_face_exists(ParamHandle *phandle, ParamKey *pvkeys, int i1, int i2, int i3)
+static int p_face_exists(ParamHandle *handle, ParamKey *pvkeys, int i1, int i2, int i3)
{
- PHandle *handle = (PHandle *)phandle;
PHashKey *vkeys = (PHashKey *)pvkeys;
PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]);
PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
@@ -833,7 +831,7 @@ static int p_face_exists(ParamHandle *phandle, ParamKey *pvkeys, int i1, int i2,
return P_FALSE;
}
-static PChart *p_chart_new(PHandle *handle)
+static PChart *p_chart_new(ParamHandle *handle)
{
PChart *chart = (PChart *)MEM_callocN(sizeof(*chart), "PChart");
chart->handle = handle;
@@ -881,7 +879,10 @@ static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep)
return P_FALSE;
}
-static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs, PEdge **r_pair)
+static PBool p_edge_has_pair(ParamHandle *handle,
+ PEdge *e,
+ PBool topology_from_uvs,
+ PEdge **r_pair)
{
PHashKey key;
PEdge *pe;
@@ -930,7 +931,7 @@ static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs,
return (*r_pair != NULL);
}
-static PBool p_edge_connect_pair(PHandle *handle,
+static PBool p_edge_connect_pair(ParamHandle *handle,
PEdge *e,
PBool topology_from_uvs,
PEdge ***stack)
@@ -954,7 +955,7 @@ static PBool p_edge_connect_pair(PHandle *handle,
return (e->pair != NULL);
}
-static int p_connect_pairs(PHandle *handle, PBool topology_from_uvs)
+static int p_connect_pairs(ParamHandle *handle, PBool topology_from_uvs)
{
PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces),
"Pstackbase");
@@ -1061,7 +1062,7 @@ static void p_split_vert(PChart *chart, PEdge *e)
}
}
-static PChart **p_split_charts(PHandle *handle, PChart *chart, int ncharts)
+static PChart **p_split_charts(ParamHandle *handle, PChart *chart, int ncharts)
{
PChart **charts = MEM_mallocN(sizeof(*charts) * ncharts, "PCharts"), *nchart;
PFace *f, *nextf;
@@ -1100,7 +1101,7 @@ static PChart **p_split_charts(PHandle *handle, PChart *chart, int ncharts)
return charts;
}
-static PFace *p_face_add(PHandle *handle)
+static PFace *p_face_add(ParamHandle *handle)
{
PFace *f;
PEdge *e1, *e2, *e3;
@@ -1132,7 +1133,7 @@ static PFace *p_face_add(PHandle *handle)
return f;
}
-static PFace *p_face_add_construct(PHandle *handle,
+static PFace *p_face_add_construct(ParamHandle *handle,
ParamKey key,
const ParamKey *vkeys,
float *co[4],
@@ -1219,7 +1220,7 @@ static PFace *p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3)
return f;
}
-static PBool p_quad_split_direction(PHandle *handle, float **co, PHashKey *vkeys)
+static PBool p_quad_split_direction(ParamHandle *handle, float **co, PHashKey *vkeys)
{
/* Slight bias to prefer one edge over the other in case they are equal, so
* that in symmetric models we choose the same split direction instead of
@@ -3212,7 +3213,7 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
}
}
-static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
+static PBool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
{
LinearSolver *context = chart->u.lscm.context;
PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2;
@@ -4361,7 +4362,7 @@ static void p_smooth(PChart *chart)
ParamHandle *GEO_uv_parametrizer_construct_begin(void)
{
- PHandle *handle = MEM_callocN(sizeof(*handle), "PHandle");
+ ParamHandle *handle = MEM_callocN(sizeof(*handle), "ParamHandle");
handle->construction_chart = p_chart_new(handle);
handle->state = PHANDLE_STATE_ALLOCATED;
handle->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param construct arena");
@@ -4375,21 +4376,18 @@ ParamHandle *GEO_uv_parametrizer_construct_begin(void)
handle->hash_edges = phash_new((PHashLink **)&handle->construction_chart->edges, 1);
handle->hash_faces = phash_new((PHashLink **)&handle->construction_chart->faces, 1);
- return (ParamHandle *)handle;
+ return handle;
}
-void GEO_uv_parametrizer_aspect_ratio(ParamHandle *handle, float aspx, float aspy)
+void GEO_uv_parametrizer_aspect_ratio(ParamHandle *phandle, float aspx, float aspy)
{
- PHandle *phandle = (PHandle *)handle;
-
phandle->aspx = aspx;
phandle->aspy = aspy;
phandle->do_aspect = true;
}
-void GEO_uv_parametrizer_delete(ParamHandle *handle)
+void GEO_uv_parametrizer_delete(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
int i;
param_assert(ELEM(phandle->state, PHANDLE_STATE_ALLOCATED, PHANDLE_STATE_CONSTRUCTED));
@@ -4426,9 +4424,8 @@ static void p_add_ngon(ParamHandle *handle,
ParamBool *select)
{
/* Allocate memory for polyfill. */
- PHandle *phandle = (PHandle *)handle;
- MemArena *arena = phandle->polyfill_arena;
- Heap *heap = phandle->polyfill_heap;
+ MemArena *arena = handle->polyfill_arena;
+ Heap *heap = handle->polyfill_heap;
uint nfilltri = nverts - 2;
uint(*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri);
float(*projverts)[2] = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts);
@@ -4478,7 +4475,7 @@ static void p_add_ngon(ParamHandle *handle,
BLI_memarena_clear(arena);
}
-void GEO_uv_parametrizer_face_add(ParamHandle *handle,
+void GEO_uv_parametrizer_face_add(ParamHandle *phandle,
ParamKey key,
int nverts,
ParamKey *vkeys,
@@ -4487,15 +4484,13 @@ void GEO_uv_parametrizer_face_add(ParamHandle *handle,
ParamBool *pin,
ParamBool *select)
{
- PHandle *phandle = (PHandle *)handle;
-
param_assert(phash_lookup(phandle->hash_faces, key) == NULL);
param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
param_assert(ELEM(nverts, 3, 4));
if (nverts > 4) {
/* ngon */
- p_add_ngon(handle, key, nverts, vkeys, co, uv, pin, select);
+ p_add_ngon(phandle, key, nverts, vkeys, co, uv, pin, select);
}
else if (nverts == 4) {
/* quad */
@@ -4514,9 +4509,8 @@ void GEO_uv_parametrizer_face_add(ParamHandle *handle,
}
}
-void GEO_uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
+void GEO_uv_parametrizer_edge_set_seam(ParamHandle *phandle, ParamKey *vkeys)
{
- PHandle *phandle = (PHandle *)handle;
PEdge *e;
param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
@@ -4527,12 +4521,11 @@ void GEO_uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
}
}
-void GEO_uv_parametrizer_construct_end(ParamHandle *handle,
+void GEO_uv_parametrizer_construct_end(ParamHandle *phandle,
ParamBool fill,
ParamBool topology_from_uvs,
int *count_fail)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart = phandle->construction_chart;
int i, j, nboundaries = 0;
PEdge *outer;
@@ -4572,7 +4565,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *handle,
}
for (v = chart->verts; v; v = v->nextlink) {
- p_vert_load_pin_select_uvs(handle, v);
+ p_vert_load_pin_select_uvs(phandle, v);
}
}
@@ -4581,9 +4574,8 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *handle,
phandle->state = PHANDLE_STATE_CONSTRUCTED;
}
-void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf)
+void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, ParamBool live, ParamBool abf)
{
- PHandle *phandle = (PHandle *)handle;
PFace *f;
int i;
@@ -4598,9 +4590,8 @@ void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, ParamBool live, ParamBo
}
}
-void GEO_uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed)
+void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, int *count_failed)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
int i;
@@ -4638,9 +4629,8 @@ void GEO_uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int
}
}
-void GEO_uv_parametrizer_lscm_end(ParamHandle *handle)
+void GEO_uv_parametrizer_lscm_end(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
int i;
param_assert(phandle->state == PHANDLE_STATE_LSCM);
@@ -4655,9 +4645,8 @@ void GEO_uv_parametrizer_lscm_end(ParamHandle *handle)
phandle->state = PHANDLE_STATE_CONSTRUCTED;
}
-void GEO_uv_parametrizer_stretch_begin(ParamHandle *handle)
+void GEO_uv_parametrizer_stretch_begin(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
PVert *v;
PFace *f;
@@ -4685,17 +4674,14 @@ void GEO_uv_parametrizer_stretch_begin(ParamHandle *handle)
}
}
-void GEO_uv_parametrizer_stretch_blend(ParamHandle *handle, float blend)
+void GEO_uv_parametrizer_stretch_blend(ParamHandle *phandle, float blend)
{
- PHandle *phandle = (PHandle *)handle;
-
param_assert(phandle->state == PHANDLE_STATE_STRETCH);
phandle->blend = blend;
}
-void GEO_uv_parametrizer_stretch_iter(ParamHandle *handle)
+void GEO_uv_parametrizer_stretch_iter(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
int i;
@@ -4707,10 +4693,8 @@ void GEO_uv_parametrizer_stretch_iter(ParamHandle *handle)
}
}
-void GEO_uv_parametrizer_stretch_end(ParamHandle *handle)
+void GEO_uv_parametrizer_stretch_end(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
-
param_assert(phandle->state == PHANDLE_STATE_STRETCH);
phandle->state = PHANDLE_STATE_CONSTRUCTED;
@@ -4718,9 +4702,8 @@ void GEO_uv_parametrizer_stretch_end(ParamHandle *handle)
phandle->rng = NULL;
}
-void GEO_uv_parametrizer_smooth_area(ParamHandle *handle)
+void GEO_uv_parametrizer_smooth_area(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
int i;
param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
@@ -4738,13 +4721,11 @@ void GEO_uv_parametrizer_smooth_area(ParamHandle *handle)
}
/* don't pack, just rotate (used for better packing) */
-static void GEO_uv_parametrizer_pack_rotate(ParamHandle *handle, bool ignore_pinned)
+static void GEO_uv_parametrizer_pack_rotate(ParamHandle *phandle, bool ignore_pinned)
{
PChart *chart;
int i;
- PHandle *phandle = (PHandle *)handle;
-
for (i = 0; i < phandle->ncharts; i++) {
chart = phandle->charts[i];
@@ -4770,9 +4751,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
float trans[2];
double area = 0.0;
- PHandle *phandle = (PHandle *)handle;
-
- if (phandle->ncharts == 0) {
+ if (handle->ncharts == 0) {
return;
}
@@ -4781,15 +4760,15 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
GEO_uv_parametrizer_pack_rotate(handle, ignore_pinned);
}
- if (phandle->aspx != phandle->aspy) {
- GEO_uv_parametrizer_scale(handle, 1.0f / phandle->aspx, 1.0f / phandle->aspy);
+ if (handle->aspx != handle->aspy) {
+ GEO_uv_parametrizer_scale(handle, 1.0f / handle->aspx, 1.0f / handle->aspy);
}
/* we may not use all these boxes */
- boxarray = MEM_mallocN(phandle->ncharts * sizeof(BoxPack), "BoxPack box");
+ boxarray = MEM_mallocN(handle->ncharts * sizeof(BoxPack), "BoxPack box");
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
+ for (i = 0; i < handle->ncharts; i++) {
+ chart = handle->charts[i];
if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
unpacked++;
@@ -4821,8 +4800,8 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
* 0.0 to 1.0 but not give a massive margin */
margin = (margin * (float)area) * 0.1f;
unpacked = 0;
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
+ for (i = 0; i < handle->ncharts; i++) {
+ chart = handle->charts[i];
if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
unpacked++;
@@ -4838,7 +4817,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
}
}
- BLI_box_pack_2d(boxarray, phandle->ncharts - unpacked, &tot_width, &tot_height);
+ BLI_box_pack_2d(boxarray, handle->ncharts - unpacked, &tot_width, &tot_height);
if (tot_height > tot_width) {
scale = tot_height != 0.0f ? (1.0f / tot_height) : 1.0f;
@@ -4847,30 +4826,29 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
scale = tot_width != 0.0f ? (1.0f / tot_width) : 1.0f;
}
- for (i = 0; i < phandle->ncharts - unpacked; i++) {
+ for (i = 0; i < handle->ncharts - unpacked; i++) {
box = boxarray + i;
trans[0] = box->x;
trans[1] = box->y;
- chart = phandle->charts[box->index];
+ chart = handle->charts[box->index];
p_chart_uv_translate(chart, trans);
p_chart_uv_scale(chart, scale);
}
MEM_freeN(boxarray);
- if (phandle->aspx != phandle->aspy) {
- GEO_uv_parametrizer_scale(handle, phandle->aspx, phandle->aspy);
+ if (handle->aspx != handle->aspy) {
+ GEO_uv_parametrizer_scale(handle, handle->aspx, handle->aspy);
}
}
-void GEO_uv_parametrizer_average(ParamHandle *handle, bool ignore_pinned)
+void GEO_uv_parametrizer_average(ParamHandle *phandle, bool ignore_pinned)
{
PChart *chart;
int i;
float tot_uvarea = 0.0f, tot_facearea = 0.0f;
float tot_fac, fac;
float minv[2], maxv[2], trans[2];
- PHandle *phandle = (PHandle *)handle;
if (phandle->ncharts == 0) {
return;
@@ -4930,9 +4908,8 @@ void GEO_uv_parametrizer_average(ParamHandle *handle, bool ignore_pinned)
}
}
-void GEO_uv_parametrizer_scale(ParamHandle *handle, float x, float y)
+void GEO_uv_parametrizer_scale(ParamHandle *phandle, float x, float y)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
int i;
@@ -4942,9 +4919,8 @@ void GEO_uv_parametrizer_scale(ParamHandle *handle, float x, float y)
}
}
-void GEO_uv_parametrizer_flush(ParamHandle *handle)
+void GEO_uv_parametrizer_flush(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
int i;
@@ -4964,9 +4940,8 @@ void GEO_uv_parametrizer_flush(ParamHandle *handle)
}
}
-void GEO_uv_parametrizer_flush_restore(ParamHandle *handle)
+void GEO_uv_parametrizer_flush_restore(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
PFace *f;
int i;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
index 930ebb78b46..88515d849bc 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -109,7 +109,7 @@ static void reduce_stroke_points(bGPdata *gpd,
const int points_num,
const eBuildGpencil_Transition transition)
{
- if (points_num == 0) {
+ if ((points_num == 0) || (gps->points == NULL)) {
clear_stroke(gpf, gps);
return;
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
index c576cfbe525..414231fcae5 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
@@ -122,6 +122,30 @@ static int remapTime(struct GpencilModifierData *md,
nfra = (efra + 1 - (cfra + offset - 1) % (efra - sfra + 1)) - 1;
}
}
+
+ if (mmd->mode == GP_TIME_MODE_PINGPONG) {
+ if ((mmd->flag & GP_TIME_KEEP_LOOP) == 0) {
+ if (((int)(cfra + offset - 1) / (efra - sfra)) % (2)) {
+ nfra = efra - (cfra + offset - 1) % (efra - sfra);
+ }
+ else {
+ nfra = sfra + (cfra + offset - 1) % (efra - sfra);
+ }
+ if (cfra > (efra - sfra) * 2) {
+ nfra = sfra + offset;
+ }
+ }
+ else {
+
+ if (((int)(cfra + offset - 1) / (efra - sfra)) % (2)) {
+ nfra = efra - (cfra + offset - 1) % (efra - sfra);
+ }
+ else {
+ nfra = sfra + (cfra + offset - 1) % (efra - sfra);
+ }
+ }
+ }
+
return nfra;
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc
index 174399618a5..5e741ccbd55 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc
@@ -21,5 +21,5 @@ static bool cmp_adjacent_items(const LineartAdjacentEdge &p1, const LineartAdjac
void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length)
{
- blender::parallel_sort(ai, ai + length - 1, cmp_adjacent_items);
+ blender::parallel_sort(ai, ai + length, cmp_adjacent_items);
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index fe1bbc3fc23..016b70cedb0 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -1753,6 +1753,11 @@ static void lineart_finalize_object_edge_array_reserve(LineartPendingEdges *pe,
static void lineart_finalize_object_edge_array(LineartPendingEdges *pe, LineartObjectInfo *obi)
{
+ /* In case of line art "occlusion only" or contour not enabled, it's possible for an object to
+ * not produce any feature lines. */
+ if (!obi->pending_edges.array) {
+ return;
+ }
memcpy(&pe->array[pe->next],
obi->pending_edges.array,
sizeof(LineartEdge *) * obi->pending_edges.next);
@@ -2357,6 +2362,11 @@ static void lineart_object_load_single_instance(LineartRenderBuffer *rb,
}
if (ob->type == OB_MESH) {
use_mesh = BKE_object_get_evaluated_mesh(ob);
+ if (use_mesh->edit_mesh) {
+ /* If the object is being edited, then the mesh is not evaluated fully into the final
+ * result, do not load them. */
+ return;
+ }
}
else {
use_mesh = BKE_mesh_new_from_object(depsgraph, ob, true, true);
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index ec9078983f9..e78c86ae196 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -406,8 +406,6 @@ set(GLSL_SRC
shaders/gpu_shader_cfg_world_clip_lib.glsl
shaders/gpu_shader_colorspace_lib.glsl
- shaders/gpu_shader_common_obinfos_lib.glsl
-
GPU_shader_shared_utils.h
)
diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h
index 061b850619f..7fe467de402 100644
--- a/source/blender/gpu/GPU_capabilities.h
+++ b/source/blender/gpu/GPU_capabilities.h
@@ -35,7 +35,7 @@ int GPU_max_compute_shader_storage_blocks(void);
int GPU_extensions_len(void);
const char *GPU_extension_get(int i);
-int GPU_texture_size_with_limit(int res, bool limit_gl_texture_size);
+int GPU_texture_size_with_limit(int res);
bool GPU_mip_render_workaround(void);
bool GPU_depth_blitting_workaround(void);
diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
index 4ec215c2d3b..eb69a1d2635 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -33,11 +33,10 @@ int GPU_max_texture_size()
return GCaps.max_texture_size;
}
-int GPU_texture_size_with_limit(int res, bool limit_gl_texture_size)
+int GPU_texture_size_with_limit(int res)
{
int size = GPU_max_texture_size();
- int reslimit = (limit_gl_texture_size && (U.glreslimit != 0)) ? min_ii(U.glreslimit, size) :
- size;
+ int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size;
return min_ii(reslimit, res);
}
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 1cd2301aa4e..0c796ddc765 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -291,26 +291,12 @@ static void detect_workarounds()
}
/* See T82856: AMD drivers since 20.11 running on a polaris architecture doesn't support the
* `GL_INT_2_10_10_10_REV` data type correctly. This data type is used to pack normals and flags.
- * The work around uses `GPU_RGBA16I`.
+ * The work around uses `GPU_RGBA16I`. In 22.?.? drivers this has been fixed for
+ * polaris platform. Keeping legacy platforms around just in case.
*/
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) {
- const Vector<std::string> matches = {"RX 460",
- "RX 470",
- "RX 480",
- "RX 490",
- "RX 560",
- "RX 560X",
- "RX 570",
- "RX 580",
- "RX 580X",
- "RX 590",
- "RX550/550",
- "(TM) 520",
- "(TM) 530",
- "(TM) 535",
- "R5",
- "R7",
- "R9"};
+ const Vector<std::string> matches = {
+ "RX550/550", "(TM) 520", "(TM) 530", "(TM) 535", "R5", "R7", "R9"};
if (match_renderer(renderer, matches)) {
GCaps.use_hq_normals_workaround = true;
diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
deleted file mode 100644
index f5b6de4899f..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
+++ /dev/null
@@ -1,23 +0,0 @@
-
-#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-
-#ifndef GPU_OBINFOS_UBO
-# define GPU_OBINFOS_UBO
-struct ObjectInfos {
- vec4 drw_OrcoTexCoFactors[2];
- vec4 drw_ObjectColor;
- vec4 drw_Infos;
-};
-
-# ifndef USE_GPU_SHADER_CREATE_INFO
-layout(std140) uniform infoBlock
-{
- /* DRW_RESOURCE_CHUNK_LEN = 512 */
- ObjectInfos drw_infos[512];
-};
-# endif
-
-# define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
-# define ObjectInfo (drw_infos[resource_id].drw_Infos)
-# define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl
index d0111aa3839..e257483f364 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl
@@ -1,13 +1,5 @@
void node_blackbody(float temperature, sampler1DArray spectrummap, float layer, out vec4 color)
{
- if (temperature >= 12000.0) {
- color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0);
- }
- else if (temperature < 965.0) {
- color = vec4(4.70366907, 0.0, 0.0, 1.0);
- }
- else {
- float t = (temperature - 965.0) / (12000.0 - 965.0);
- color = vec4(texture(spectrummap, vec2(t, layer)).rgb, 1.0);
- }
+ float t = (temperature - 800.0) / (12000.0 - 800.0);
+ color = vec4(texture(spectrummap, vec2(t, layer)).rgb, 1.0);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
index e219e2b9bbe..a54dc59ddfe 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
@@ -1,3 +1,5 @@
+
+#ifdef OBINFO_LIB
void node_normal_map(vec4 tangent, vec3 texnormal, out vec3 outnormal)
{
if (all(equal(tangent, vec4(0.0, 0.0, 0.0, 1.0)))) {
@@ -10,6 +12,7 @@ void node_normal_map(vec4 tangent, vec3 texnormal, out vec3 outnormal)
outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * g_data.N;
outnormal = normalize(outnormal);
}
+#endif
void color_to_normal_new_shading(vec3 color, out vec3 normal)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl
index 2c5d38eabbe..48d627dcd0b 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl
@@ -1,15 +1,7 @@
-void node_wavelength(float wavelength,
- sampler1DArray spectrummap,
- float layer,
- vec3 xyz_to_r,
- vec3 xyz_to_g,
- vec3 xyz_to_b,
- out vec4 color)
+void node_wavelength(float wavelength, sampler1DArray spectrummap, float layer, out vec4 color)
{
- mat3 xyz_to_rgb = mat3(xyz_to_r, xyz_to_g, xyz_to_b);
float t = (wavelength - 380.0) / (780.0 - 380.0);
- vec3 xyz = texture(spectrummap, vec2(t, layer)).rgb;
- vec3 rgb = xyz * xyz_to_rgb;
+ vec3 rgb = texture(spectrummap, vec2(t, layer)).rgb;
rgb *= 1.0 / 2.52; /* Empirical scale from lg to make all comps <= 1. */
color = vec4(clamp(rgb, 0.0, 1.0), 1.0);
}
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 97030d44047..512dc674fc7 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -54,6 +54,7 @@ bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_name_is_data(const char *name);
bool IMB_colormanagement_space_name_is_scene_linear(const char *name);
+bool IMB_colormanagement_space_name_is_srgb(const char *name);
/**
* Convert a float RGB triplet to the correct luminance weighted average.
@@ -71,9 +72,21 @@ BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]);
* Byte equivalent of #IMB_colormanagement_get_luminance().
*/
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
-BLI_INLINE void IMB_colormanagement_xyz_to_rgb(float rgb[3], const float xyz[3]);
-BLI_INLINE void IMB_colormanagement_rgb_to_xyz(float xyz[3], const float rgb[3]);
-const float *IMB_colormanagement_get_xyz_to_rgb(void);
+
+/**
+ * Conversion between scene linear and other color spaces.
+ */
+BLI_INLINE void IMB_colormanagement_xyz_to_scene_linear(float scene_linear[3], const float xyz[3]);
+BLI_INLINE void IMB_colormanagement_scene_linear_to_xyz(float xyz[3], const float scene_linear[3]);
+BLI_INLINE void IMB_colormanagement_rec709_to_scene_linear(float scene_linear[3],
+ const float rec709[3]);
+BLI_INLINE void IMB_colormanagement_scene_linear_to_rec709(float rec709[3],
+ const float scene_linear[3]);
+BLI_INLINE void IMB_colormanagement_aces_to_scene_linear(float scene_linear[3],
+ const float aces[3]);
+BLI_INLINE void IMB_colormanagement_scene_linear_to_aces(float aces[3],
+ const float scene_linear[3]);
+const float *IMB_colormanagement_get_xyz_to_scene_linear(void);
/** \} */
@@ -187,15 +200,19 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
* - Color picking values 0..1 map to scene linear values in the 0..1 range,
* so that picked albedo values are energy conserving.
*/
-void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3]);
-void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3]);
+void IMB_colormanagement_scene_linear_to_color_picking_v3(float color_picking[3],
+ const float scene_linear[3]);
+void IMB_colormanagement_color_picking_to_scene_linear_v3(float scene_linear[3],
+ const float color_picking[3]);
/**
* Conversion between sRGB, for rare cases like hex color or copy/pasting
* between UI theme and scene linear colors.
*/
-void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3]);
-void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3]);
+BLI_INLINE void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3],
+ const float scene_linear[3]);
+BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3],
+ const float srgb[3]);
/**
* Convert pixel from scene linear to display space using default view
@@ -497,6 +514,18 @@ enum {
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Rendering Tables
+ * \{ */
+
+void IMB_colormanagement_blackbody_temperature_to_rgb_table(float *r_table,
+ const int width,
+ const float min,
+ const float max);
+void IMB_colormanagement_wavelength_to_rgb_table(float *r_table, const int width);
+
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 7493fa3e4af..20c414bb1ad 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -936,8 +936,7 @@ const char *IMB_ffmpeg_last_error(void);
struct GPUTexture *IMB_create_gpu_texture(const char *name,
struct ImBuf *ibuf,
bool use_high_bitdepth,
- bool use_premult,
- bool limit_gl_texture_size);
+ bool use_premult);
/**
* The `ibuf` is only here to detect the storage type. The produced texture will have undefined
* content. It will need to be populated by using #IMB_update_gpu_texture_sub().
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index c89b15480a2..23b3f0191b7 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -18,8 +18,12 @@ struct ImBuf;
struct OCIO_ConstCPUProcessorRcPtr;
extern float imbuf_luma_coefficients[3];
-extern float imbuf_xyz_to_rgb[3][3];
-extern float imbuf_rgb_to_xyz[3][3];
+extern float imbuf_scene_linear_to_xyz[3][3];
+extern float imbuf_xyz_to_scene_linear[3][3];
+extern float imbuf_scene_linear_to_aces[3][3];
+extern float imbuf_aces_to_scene_linear[3][3];
+extern float imbuf_scene_linear_to_rec709[3][3];
+extern float imbuf_rec709_to_scene_linear[3][3];
#define MAX_COLORSPACE_NAME 64
#define MAX_COLORSPACE_DESCRIPTION 512
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 1613595148b..d4c9e78a299 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -73,10 +73,12 @@ static int global_tot_looks = 0;
/* Luma coefficients and XYZ to RGB to be initialized by OCIO. */
float imbuf_luma_coefficients[3] = {0.0f};
-float imbuf_xyz_to_rgb[3][3] = {{0.0f}};
-float imbuf_rgb_to_xyz[3][3] = {{0.0f}};
-static float imbuf_xyz_to_linear_srgb[3][3] = {{0.0f}};
-static float imbuf_linear_srgb_to_xyz[3][3] = {{0.0f}};
+float imbuf_scene_linear_to_xyz[3][3] = {{0.0f}};
+float imbuf_xyz_to_scene_linear[3][3] = {{0.0f}};
+float imbuf_scene_linear_to_rec709[3][3] = {{0.0f}};
+float imbuf_rec709_to_scene_linear[3][3] = {{0.0f}};
+float imbuf_scene_linear_to_aces[3][3] = {{0.0f}};
+float imbuf_aces_to_scene_linear[3][3] = {{0.0f}};
/* lock used by pre-cached processors getters, so processor wouldn't
* be created several times
@@ -573,10 +575,16 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
/* Load luminance coefficients. */
OCIO_configGetDefaultLumaCoefs(config, imbuf_luma_coefficients);
- OCIO_configGetXYZtoRGB(config, imbuf_xyz_to_rgb);
- invert_m3_m3(imbuf_rgb_to_xyz, imbuf_xyz_to_rgb);
- copy_m3_m3(imbuf_xyz_to_linear_srgb, OCIO_XYZ_TO_LINEAR_SRGB);
- invert_m3_m3(imbuf_linear_srgb_to_xyz, imbuf_xyz_to_linear_srgb);
+
+ /* Load standard color spaces. */
+ OCIO_configGetXYZtoSceneLinear(config, imbuf_xyz_to_scene_linear);
+ invert_m3_m3(imbuf_scene_linear_to_xyz, imbuf_xyz_to_scene_linear);
+
+ mul_m3_m3m3(imbuf_scene_linear_to_rec709, OCIO_XYZ_TO_REC709, imbuf_scene_linear_to_xyz);
+ invert_m3_m3(imbuf_rec709_to_scene_linear, imbuf_scene_linear_to_rec709);
+
+ mul_m3_m3m3(imbuf_aces_to_scene_linear, imbuf_xyz_to_scene_linear, OCIO_ACES_TO_XYZ);
+ invert_m3_m3(imbuf_scene_linear_to_aces, imbuf_aces_to_scene_linear);
}
static void colormanage_free_config(void)
@@ -1412,9 +1420,15 @@ bool IMB_colormanagement_space_name_is_scene_linear(const char *name)
return (colorspace && IMB_colormanagement_space_is_scene_linear(colorspace));
}
-const float *IMB_colormanagement_get_xyz_to_rgb()
+bool IMB_colormanagement_space_name_is_srgb(const char *name)
+{
+ ColorSpace *colorspace = colormanage_colorspace_get_named(name);
+ return (colorspace && IMB_colormanagement_space_is_srgb(colorspace));
+}
+
+const float *IMB_colormanagement_get_xyz_to_scene_linear()
{
- return &imbuf_xyz_to_rgb[0][0];
+ return &imbuf_xyz_to_scene_linear[0][0];
}
/** \} */
@@ -2307,7 +2321,8 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
}
}
-void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
+void IMB_colormanagement_scene_linear_to_color_picking_v3(float color_picking[3],
+ const float scene_linear[3])
{
if (!global_color_picking_state.cpu_processor_to && !global_color_picking_state.failed) {
/* Create processor if none exists. */
@@ -2329,12 +2344,15 @@ void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
BLI_mutex_unlock(&processor_lock);
}
+ copy_v3_v3(color_picking, scene_linear);
+
if (global_color_picking_state.cpu_processor_to) {
- OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_to, pixel);
+ OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_to, color_picking);
}
}
-void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
+void IMB_colormanagement_color_picking_to_scene_linear_v3(float scene_linear[3],
+ const float color_picking[3])
{
if (!global_color_picking_state.cpu_processor_from && !global_color_picking_state.failed) {
/* Create processor if none exists. */
@@ -2356,25 +2374,13 @@ void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
BLI_mutex_unlock(&processor_lock);
}
+ copy_v3_v3(scene_linear, color_picking);
+
if (global_color_picking_state.cpu_processor_from) {
- OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_from, pixel);
+ OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_from, scene_linear);
}
}
-void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3])
-{
- mul_m3_v3(imbuf_rgb_to_xyz, pixel);
- mul_m3_v3(imbuf_xyz_to_linear_srgb, pixel);
- linearrgb_to_srgb_v3_v3(pixel, pixel);
-}
-
-void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3])
-{
- srgb_to_linearrgb_v3_v3(pixel, pixel);
- mul_m3_v3(imbuf_linear_srgb_to_xyz, pixel);
- mul_m3_v3(imbuf_xyz_to_rgb, pixel);
-}
-
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
{
OCIO_ConstCPUProcessorRcPtr *processor = display_from_scene_linear_processor(display);
@@ -4111,3 +4117,170 @@ void IMB_colormanagement_finish_glsl_draw(void)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rendering Tables
+ * \{ */
+
+/* Calculate color in range 800..12000 using an approximation
+ * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
+ *
+ * The result of this can be negative to support gamut wider than
+ * than rec.709, just needs to be clamped. */
+
+static const float blackbody_table_r[7][3] = {{1.61919106e+03f, -2.05010916e-03f, 5.02995757e+00f},
+ {2.48845471e+03f, -1.11330907e-03f, 3.22621544e+00f},
+ {3.34143193e+03f, -4.86551192e-04f, 1.76486769e+00f},
+ {4.09461742e+03f, -1.27446582e-04f, 7.25731635e-01f},
+ {4.67028036e+03f, 2.91258199e-05f, 1.26703442e-01f},
+ {4.59509185e+03f, 2.87495649e-05f, 1.50345020e-01f},
+ {3.78717450e+03f, 9.35907826e-06f, 3.99075871e-01f}};
+
+static const float blackbody_table_g[7][3] = {
+ {-4.88999748e+02f, 6.04330754e-04f, -7.55807526e-02f},
+ {-7.55994277e+02f, 3.16730098e-04f, 4.78306139e-01f},
+ {-1.02363977e+03f, 1.20223470e-04f, 9.36662319e-01f},
+ {-1.26571316e+03f, 4.87340896e-06f, 1.27054498e+00f},
+ {-1.42529332e+03f, -4.01150431e-05f, 1.43972784e+00f},
+ {-1.17554822e+03f, -2.16378048e-05f, 1.30408023e+00f},
+ {-5.00799571e+02f, -4.59832026e-06f, 1.09098763e+00f}};
+
+static const float blackbody_table_b[7][4] = {
+ {5.96945309e-11f, -4.85742887e-08f, -9.70622247e-05f, -4.07936148e-03f},
+ {2.40430366e-11f, 5.55021075e-08f, -1.98503712e-04f, 2.89312858e-02f},
+ {-1.40949732e-11f, 1.89878968e-07f, -3.56632824e-04f, 9.10767778e-02f},
+ {-3.61460868e-11f, 2.84822009e-07f, -4.93211319e-04f, 1.56723440e-01f},
+ {-1.97075738e-11f, 1.75359352e-07f, -2.50542825e-04f, -2.22783266e-02f},
+ {-1.61997957e-13f, -1.64216008e-08f, 3.86216271e-04f, -7.38077418e-01f},
+ {6.72650283e-13f, -2.73078809e-08f, 4.24098264e-04f, -7.52335691e-01f}};
+
+static void blackbody_temperature_to_rec709(float rec709[3], float t)
+{
+ if (t >= 12000.0f) {
+ rec709[0] = 0.8262954810464208f;
+ rec709[1] = 0.9945080501520986f;
+ rec709[2] = 1.566307710274283f;
+ }
+ else if (t < 800.0f) {
+ rec709[0] = 5.413294490189271f;
+ rec709[1] = -0.20319390035873933f;
+ rec709[2] = -0.0822535242887164f;
+ }
+ else {
+ int i = (t >= 6365.0f) ? 6 :
+ (t >= 3315.0f) ? 5 :
+ (t >= 1902.0f) ? 4 :
+ (t >= 1449.0f) ? 3 :
+ (t >= 1167.0f) ? 2 :
+ (t >= 965.0f) ? 1 :
+ 0;
+
+ const float *r = blackbody_table_r[i];
+ const float *g = blackbody_table_g[i];
+ const float *b = blackbody_table_b[i];
+
+ const float t_inv = 1.0f / t;
+ rec709[0] = r[0] * t_inv + r[1] * t + r[2];
+ rec709[1] = g[0] * t_inv + g[1] * t + g[2];
+ rec709[2] = ((b[0] * t + b[1]) * t + b[2]) * t + b[3];
+ }
+}
+
+void IMB_colormanagement_blackbody_temperature_to_rgb_table(float *r_table,
+ const int width,
+ const float min,
+ const float max)
+{
+ for (int i = 0; i < width; i++) {
+ float temperature = min + (max - min) / (float)width * (float)i;
+
+ float rec709[3];
+ blackbody_temperature_to_rec709(rec709, temperature);
+
+ float rgb[3];
+ IMB_colormanagement_rec709_to_scene_linear(rgb, rec709);
+ clamp_v3(rgb, 0.0f, FLT_MAX);
+
+ copy_v3_v3(&r_table[i * 4], rgb);
+ r_table[i * 4 + 3] = 0.0f;
+ }
+}
+
+/**
+ * CIE color matching functions `xBar`, `yBar`, and `zBar` for
+ * wavelengths from 380 through 780 nanometers, every 5 nanometers.
+ *
+ * For a wavelength lambda in this range:
+ * \code{.txt}
+ * cie_color_match[(lambda - 380) / 5][0] = xBar
+ * cie_color_match[(lambda - 380) / 5][1] = yBar
+ * cie_color_match[(lambda - 380) / 5][2] = zBar
+ * \endcode
+ */
+
+static float cie_colour_match[81][3] = {
+ {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
+ {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
+ {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
+ {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
+ {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
+ {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
+ {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
+ {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
+ {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
+ {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
+ {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
+ {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
+ {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
+ {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
+ {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
+ {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
+ {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
+ {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
+ {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
+ {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
+ {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
+ {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
+ {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
+ {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
+ {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
+ {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
+ {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}};
+
+static void wavelength_to_xyz(float xyz[3], float lambda_nm)
+{
+ float ii = (lambda_nm - 380.0f) * (1.0f / 5.0f); /* Scaled 0..80. */
+ int i = (int)ii;
+
+ if (i < 0 || i >= 80) {
+ xyz[0] = 0.0f;
+ xyz[1] = 0.0f;
+ xyz[2] = 0.0f;
+ }
+ else {
+ ii -= (float)i;
+ const float *c = cie_colour_match[i];
+ xyz[0] = c[0] + ii * (c[3] - c[0]);
+ xyz[1] = c[1] + ii * (c[4] - c[1]);
+ xyz[2] = c[2] + ii * (c[5] - c[2]);
+ }
+}
+
+void IMB_colormanagement_wavelength_to_rgb_table(float *r_table, const int width)
+{
+ for (int i = 0; i < width; i++) {
+ float temperature = 380 + 400 / (float)width * (float)i;
+
+ float xyz[3];
+ wavelength_to_xyz(xyz, temperature);
+
+ float rgb[3];
+ IMB_colormanagement_xyz_to_scene_linear(rgb, xyz);
+ clamp_v3(rgb, 0.0f, FLT_MAX);
+
+ copy_v3_v3(&r_table[i * 4], rgb);
+ r_table[i * 4 + 3] = 0.0f;
+ }
+}
+
+/** \} */
diff --git a/source/blender/imbuf/intern/colormanagement_inline.c b/source/blender/imbuf/intern/colormanagement_inline.c
index 411cf9af802..668307ec802 100644
--- a/source/blender/imbuf/intern/colormanagement_inline.c
+++ b/source/blender/imbuf/intern/colormanagement_inline.c
@@ -27,14 +27,46 @@ unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
return unit_float_to_uchar_clamp(val);
}
-void IMB_colormanagement_xyz_to_rgb(float rgb[3], const float xyz[3])
+void IMB_colormanagement_xyz_to_scene_linear(float scene_linear[3], const float xyz[3])
{
- mul_v3_m3v3(rgb, imbuf_xyz_to_rgb, xyz);
+ mul_v3_m3v3(scene_linear, imbuf_xyz_to_scene_linear, xyz);
}
-void IMB_colormanagement_rgb_to_xyz(float xyz[3], const float rgb[3])
+void IMB_colormanagement_scene_linear_to_xyz(float xyz[3], const float scene_linear[3])
{
- mul_v3_m3v3(xyz, imbuf_rgb_to_xyz, rgb);
+ mul_v3_m3v3(xyz, imbuf_scene_linear_to_xyz, scene_linear);
+}
+
+void IMB_colormanagement_rec709_to_scene_linear(float scene_linear[3], const float rec709[3])
+{
+ mul_v3_m3v3(scene_linear, imbuf_rec709_to_scene_linear, rec709);
+}
+
+void IMB_colormanagement_scene_linear_to_rec709(float rec709[3], const float scene_linear[3])
+{
+ mul_v3_m3v3(rec709, imbuf_scene_linear_to_rec709, scene_linear);
+}
+
+void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3], const float scene_linear[3])
+{
+ mul_v3_m3v3(srgb, imbuf_scene_linear_to_rec709, scene_linear);
+ linearrgb_to_srgb_v3_v3(srgb, srgb);
+}
+
+void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
+{
+ srgb_to_linearrgb_v3_v3(scene_linear, srgb);
+ mul_m3_v3(imbuf_rec709_to_scene_linear, scene_linear);
+}
+
+void IMB_colormanagement_aces_to_scene_linear(float scene_linear[3], const float aces[3])
+{
+ mul_v3_m3v3(scene_linear, imbuf_aces_to_scene_linear, aces);
+}
+
+void IMB_colormanagement_scene_linear_to_aces(float aces[3], const float scene_linear[3])
+{
+ mul_v3_m3v3(aces, imbuf_scene_linear_to_aces, scene_linear);
}
#endif /* __IMB_COLORMANAGEMENT_INLINE_H__ */
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 8da9eb9ccf7..8e004938a89 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -197,12 +197,10 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex,
GPUTexture *IMB_create_gpu_texture(const char *name,
ImBuf *ibuf,
bool use_high_bitdepth,
- bool use_premult,
- bool limit_gl_texture_size)
+ bool use_premult)
{
GPUTexture *tex = NULL;
- int size[2] = {GPU_texture_size_with_limit(ibuf->x, limit_gl_texture_size),
- GPU_texture_size_with_limit(ibuf->y, limit_gl_texture_size)};
+ int size[2] = {GPU_texture_size_with_limit(ibuf->x), GPU_texture_size_with_limit(ibuf->y)};
bool do_rescale = (ibuf->x != size[0]) || (ibuf->y != size[1]);
#ifdef WITH_DDS
diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt
index 7a7c95b29f9..1205ae74e6f 100644
--- a/source/blender/io/usd/CMakeLists.txt
+++ b/source/blender/io/usd/CMakeLists.txt
@@ -43,6 +43,7 @@ set(INC
../../bmesh
../../depsgraph
../../editors/include
+ ../../imbuf
../../makesdna
../../makesrna
../../windowmanager
@@ -114,6 +115,7 @@ set(SRC
set(LIB
bf_blenkernel
bf_blenlib
+ bf_imbuf
bf_io_common
)
diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc
index a24877a20bd..857896b9330 100644
--- a/source/blender/io/usd/intern/usd_writer_material.cc
+++ b/source/blender/io/usd/intern/usd_writer_material.cc
@@ -10,6 +10,8 @@
#include "BKE_main.h"
#include "BKE_node.h"
+#include "IMB_colormanagement.h"
+
#include "BLI_fileops.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
@@ -414,13 +416,10 @@ static pxr::TfToken get_node_tex_image_color_space(bNode *node)
Image *ima = reinterpret_cast<Image *>(node->id);
- if (strcmp(ima->colorspace_settings.name, "Raw") == 0) {
- return usdtokens::raw;
- }
- if (strcmp(ima->colorspace_settings.name, "Non-Color") == 0) {
+ if (IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) {
return usdtokens::raw;
}
- if (strcmp(ima->colorspace_settings.name, "sRGB") == 0) {
+ if (IMB_colormanagement_space_name_is_srgb(ima->colorspace_settings.name)) {
return usdtokens::sRGB;
}
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
index f7bf678310f..bebad06d37f 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -92,12 +92,14 @@ struct OBJImportParams {
};
/**
- * Time the full import process.
+ * Perform the full import process.
+ * Import also changes the selection & the active object; callers
+ * need to update the UI bits if needed.
*/
void OBJ_import(bContext *C, const struct OBJImportParams *import_params);
/**
- * C-interface for the exporter.
+ * Perform the full export process.
*/
void OBJ_export(bContext *C, const struct OBJExportParams *export_params);
diff --git a/source/blender/io/wavefront_obj/importer/obj_importer.cc b/source/blender/io/wavefront_obj/importer/obj_importer.cc
index b18ff2cf454..f2051d195c8 100644
--- a/source/blender/io/wavefront_obj/importer/obj_importer.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_importer.cc
@@ -88,7 +88,6 @@ void importer_main(bContext *C, const OBJImportParams &import_params)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
importer_main(bmain, scene, view_layer, import_params);
- static_cast<void>(CTX_data_ensure_evaluated_depsgraph(C));
}
void importer_main(Main *bmain,
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index 535533565dd..c20fb180fcd 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -229,6 +229,7 @@ typedef enum eTimeGpencil_Mode {
GP_TIME_MODE_NORMAL = 0,
GP_TIME_MODE_REVERSE = 1,
GP_TIME_MODE_FIX = 2,
+ GP_TIME_MODE_PINGPONG = 3,
} eTimeGpencil_Mode;
typedef enum eModifyColorGpencil_Flag {
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 80f592bb66d..6e4e515a0fe 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -80,17 +80,11 @@ typedef struct RenderSlot {
struct RenderResult *render;
} RenderSlot;
-typedef struct ImageTile_RuntimeTextureSlot {
+typedef struct ImageTile_Runtime {
int tilearray_layer;
int _pad;
int tilearray_offset[2];
int tilearray_size[2];
-} ImageTile_RuntimeTextureSlot;
-
-typedef struct ImageTile_Runtime {
- /* Data per `eImageTextureResolution`.
- * Should match `IMA_TEXTURE_RESOLUTION_LEN` */
- ImageTile_RuntimeTextureSlot slots[2];
} ImageTile_Runtime;
typedef struct ImageTile {
@@ -109,10 +103,7 @@ typedef struct ImageTile {
/* #define IMA_UNUSED_2 (1 << 2) */
#define IMA_NEED_FRAME_RECALC (1 << 3)
#define IMA_SHOW_STEREO (1 << 4)
-/* Do not limit the resolution by the limit texture size option in the user preferences.
- * Images in the image editor or used as a backdrop are always shown using the maximum
- * possible resolution. */
-#define IMA_SHOW_MAX_RESOLUTION (1 << 5)
+/* #define IMA_UNUSED_5 (1 << 5) */
/* Used to get the correct gpu texture from an Image datablock. */
typedef enum eGPUTextureTarget {
@@ -122,15 +113,6 @@ typedef enum eGPUTextureTarget {
TEXTARGET_COUNT,
} eGPUTextureTarget;
-/* Resolution variations that can be cached for an image. */
-typedef enum eImageTextureResolution {
- IMA_TEXTURE_RESOLUTION_FULL = 0,
- IMA_TEXTURE_RESOLUTION_LIMITED,
-
- /* Not an option, but holds the number of options defined for this struct. */
- IMA_TEXTURE_RESOLUTION_LEN
-} eImageTextureResolution;
-
/* Defined in BKE_image.h. */
struct PartialUpdateRegister;
struct PartialUpdateUser;
@@ -155,8 +137,8 @@ typedef struct Image {
/** Not written in file. */
struct MovieCache *cache;
- /** Not written in file 3 = TEXTARGET_COUNT, 2 = stereo eyes, 2 = IMA_TEXTURE_RESOLUTION_LEN. */
- struct GPUTexture *gputexture[3][2][2];
+ /** Not written in file 3 = TEXTARGET_COUNT, 2 = stereo eyes. */
+ struct GPUTexture *gputexture[3][2];
/* sources from: */
ListBase anims;
@@ -244,11 +226,6 @@ enum {
enum {
/** All mipmap levels in OpenGL texture set? */
IMA_GPU_MIPMAP_COMPLETE = (1 << 0),
- /* Reuse the max resolution textures as they fit in the limited scale. */
- IMA_GPU_REUSE_MAX_RESOLUTION = (1 << 1),
- /* Has any limited scale textures been allocated.
- * Adds additional checks to reuse max resolution images when they fit inside limited scale. */
- IMA_GPU_HAS_LIMITED_SCALE_TEXTURES = (1 << 2),
};
/* Image.source, where the image comes from */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index e9c12e52bce..3be4f82ecb0 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -610,6 +610,8 @@ typedef enum eNodeTreeExecutionMode {
typedef enum eNodeTreeRuntimeFlag {
/** There is a node that references an image with animation. */
NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION = 1 << 0,
+ /** There is a material output node in the group. */
+ NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT = 1 << 1,
} eNodeTreeRuntimeFlag;
/* socket value structs for input buttons
diff --git a/source/blender/makesdna/DNA_volume_defaults.h b/source/blender/makesdna/DNA_volume_defaults.h
index ee98f0ea4fd..1057fc75d34 100644
--- a/source/blender/makesdna/DNA_volume_defaults.h
+++ b/source/blender/makesdna/DNA_volume_defaults.h
@@ -23,6 +23,7 @@
#define _DNA_DEFAULT_VolumeRender \
{ \
+ .precision = VOLUME_PRECISION_HALF, \
.space = VOLUME_SPACE_OBJECT, \
.step_size = 0.0f, \
.clipping = 0.001f, \
diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h
index a2e558aa790..a25bfe0ebec 100644
--- a/source/blender/makesdna/DNA_volume_types.h
+++ b/source/blender/makesdna/DNA_volume_types.h
@@ -126,6 +126,13 @@ typedef enum VolumeWireframeDetail {
VOLUME_WIREFRAME_FINE = 1,
} VolumeWireframeDetail;
+/** #VolumeRender.precision */
+typedef enum VolumeRenderPrecision {
+ VOLUME_PRECISION_HALF = 0,
+ VOLUME_PRECISION_FULL = 1,
+ VOLUME_PRECISION_VARIABLE = 2,
+} VolumeRenderPrecision;
+
/** #VolumeRender.space */
typedef enum VolumeRenderSpace {
VOLUME_SPACE_OBJECT = 0,
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index e1e655fad4b..4267ce47d81 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -177,7 +177,7 @@ int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dime
/**
* Used by BPY to make an array from the python object.
*/
-int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[]);
+int RNA_property_array_dimension(const PointerRNA *ptr, PropertyRNA *prop, int length[]);
char RNA_property_array_item_char(PropertyRNA *prop, int index);
int RNA_property_array_item_index(PropertyRNA *prop, char name);
@@ -358,6 +358,21 @@ char *RNA_property_string_get_alloc(
PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len);
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value);
void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len);
+
+eStringPropertySearchFlag RNA_property_string_search_flag(PropertyRNA *prop);
+/**
+ * Search candidates for string `prop` by calling `visit_fn` with each string.
+ * Typically these strings are collected in `visit_user_data` in a format defined by the caller.
+ *
+ * See #PropStringSearchFunc for details.
+ */
+void RNA_property_string_search(const struct bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
/**
* \return the length without `\0` terminator.
*/
@@ -402,7 +417,9 @@ int RNA_property_collection_length(PointerRNA *ptr, PropertyRNA *prop);
* without having to iterate over items in the collection (needed for some kinds of collections).
*/
bool RNA_property_collection_is_empty(PointerRNA *ptr, PropertyRNA *prop);
-int RNA_property_collection_lookup_index(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *t_ptr);
+int RNA_property_collection_lookup_index(PointerRNA *ptr,
+ PropertyRNA *prop,
+ const PointerRNA *t_ptr);
int RNA_property_collection_lookup_int(PointerRNA *ptr,
PropertyRNA *prop,
int key,
@@ -468,7 +485,7 @@ bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop);
* UI code or Actions, though efficiency is a concern. */
char *RNA_path_append(
- const char *path, PointerRNA *ptr, PropertyRNA *prop, int intkey, const char *strkey);
+ const char *path, const PointerRNA *ptr, PropertyRNA *prop, int intkey, const char *strkey);
#if 0 /* UNUSED. */
char *RNA_path_back(const char *path);
#endif
@@ -486,7 +503,10 @@ char *RNA_path_back(const char *path);
* \note Assumes all pointers provided are valid
* \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
*/
-bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop);
+bool RNA_path_resolve(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop);
/**
* Resolve the given RNA Path to find the pointer and/or property + array index
@@ -495,16 +515,22 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop
* \note Assumes all pointers provided are valid.
* \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
*/
-bool RNA_path_resolve_full(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
+bool RNA_path_resolve_full(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index);
/**
* A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data.
*
* \note While it's correct to ignore the value of #PointerRNA.data
* most callers need to know if the resulting pointer was found and not null.
*/
-bool RNA_path_resolve_full_maybe_null(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
+bool RNA_path_resolve_full_maybe_null(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index);
/* RNA_path_resolve_property() variants ensure that pointer + property both exist. */
@@ -516,7 +542,7 @@ bool RNA_path_resolve_full_maybe_null(
* \note Assumes all pointers provided are valid
* \return True only if both a valid pointer and property are found after resolving the path
*/
-bool RNA_path_resolve_property(PointerRNA *ptr,
+bool RNA_path_resolve_property(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop);
@@ -529,8 +555,11 @@ bool RNA_path_resolve_property(PointerRNA *ptr,
* \note Assumes all pointers provided are valid
* \return True only if both a valid pointer and property are found after resolving the path
*/
-bool RNA_path_resolve_property_full(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
+bool RNA_path_resolve_property_full(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index);
/* RNA_path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist,
* and resolve last Pointer value if possible (Pointer prop or item of a Collection prop). */
@@ -547,7 +576,7 @@ bool RNA_path_resolve_property_full(
* You must check for its validity before use!
* \return True only if both a valid pointer and property are found after resolving the path
*/
-bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
+bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
@@ -566,7 +595,7 @@ bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
* You must check for its validity before use!
* \return True only if both a valid pointer and property are found after resolving the path
*/
-bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
+bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
@@ -614,21 +643,23 @@ struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const ch
char *RNA_path_from_ID_to_struct(const PointerRNA *ptr);
-char *RNA_path_from_real_ID_to_struct(struct Main *bmain, PointerRNA *ptr, struct ID **r_real);
+char *RNA_path_from_real_ID_to_struct(struct Main *bmain,
+ const PointerRNA *ptr,
+ struct ID **r_real);
-char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
+char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop);
/**
* \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`,
* this is expanded when used with multi-dimensional arrays.
*/
-char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
+char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
int index);
char *RNA_path_from_real_ID_to_property_index(struct Main *bmain,
- PointerRNA *ptr,
+ const PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
int index,
@@ -638,8 +669,8 @@ char *RNA_path_from_real_ID_to_property_index(struct Main *bmain,
* \return the path to given ptr/prop from the closest ancestor of given type,
* if any (else return NULL).
*/
-char *RNA_path_resolve_from_type_to_property(struct PointerRNA *ptr,
- struct PropertyRNA *prop,
+char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr,
+ PropertyRNA *prop,
const struct StructRNA *type);
/**
@@ -651,27 +682,27 @@ char *RNA_path_full_ID_py(struct Main *bmain, struct ID *id);
* Get the ID.struct as a python representation, eg:
* bpy.data.foo["bar"].some_struct
*/
-char *RNA_path_full_struct_py(struct Main *bmain, struct PointerRNA *ptr);
+char *RNA_path_full_struct_py(struct Main *bmain, const PointerRNA *ptr);
/**
* Get the ID.struct.property as a python representation, eg:
* bpy.data.foo["bar"].some_struct.some_prop[10]
*/
char *RNA_path_full_property_py_ex(
- struct Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
+ struct Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
char *RNA_path_full_property_py(struct Main *bmain,
- struct PointerRNA *ptr,
- struct PropertyRNA *prop,
+ const PointerRNA *ptr,
+ PropertyRNA *prop,
int index);
/**
* Get the struct.property as a python representation, eg:
* some_struct.some_prop[10]
*/
-char *RNA_path_struct_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
+char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index);
/**
* Get the struct.property as a python representation, eg:
* some_prop[10]
*/
-char *RNA_path_property_py(const struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
+char *RNA_path_property_py(const PointerRNA *ptr, PropertyRNA *prop, int index);
/* Quick name based property access
*
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 13a5ec66a16..0389d1b3b16 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -446,6 +446,9 @@ void RNA_def_property_string_funcs(PropertyRNA *prop,
const char *get,
const char *length,
const char *set);
+void RNA_def_property_string_search_func(PropertyRNA *prop,
+ const char *search,
+ eStringPropertySearchFlag search_flag);
void RNA_def_property_pointer_funcs(
PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll);
void RNA_def_property_collection_funcs(PropertyRNA *prop,
@@ -490,6 +493,9 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
StringPropertyGetFunc getfunc,
StringPropertyLengthFunc lengthfunc,
StringPropertySetFunc setfunc);
+void RNA_def_property_string_search_func_runtime(PropertyRNA *prop,
+ StringPropertySearchFunc search_fn,
+ eStringPropertySearchFlag search_flag);
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context);
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 3ebcae5f947..75b514cdb13 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -515,6 +515,55 @@ typedef int (*StringPropertyLengthFunc)(struct PointerRNA *ptr, struct PropertyR
typedef void (*StringPropertySetFunc)(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const char *value);
+
+typedef struct StringPropertySearchVisitParams {
+ /** Text being searched for (never NULL). */
+ const char *text;
+ /** Additional information to display (optional, may be NULL). */
+ const char *info;
+} StringPropertySearchVisitParams;
+
+typedef enum eStringPropertySearchFlag {
+ /**
+ * Used so the result of #RNA_property_string_search_flag can be used to check
+ * if search is supported.
+ */
+ PROP_STRING_SEARCH_SUPPORTED = (1 << 0),
+ /** Items resulting from the search must be sorted. */
+ PROP_STRING_SEARCH_SORT = (1 << 1),
+ /**
+ * Allow members besides the ones listed to be entered.
+ *
+ * \warning disabling this options causes the search callback to run on redraw and should
+ * only be enabled this doesn't cause performance issues.
+ */
+ PROP_STRING_SEARCH_SUGGESTION = (1 << 2),
+} eStringPropertySearchFlag;
+
+/**
+ * Visit string search candidates, `text` may be freed once this callback has finished,
+ * so references to it should not be held.
+ */
+typedef void (*StringPropertySearchVisitFunc)(void *visit_user_data,
+ const StringPropertySearchVisitParams *params);
+/**
+ * \param C: context, may be NULL (in this case all available items should be shown).
+ * \param ptr: RNA pointer.
+ * \param prop: RNA property. This must have it's #StringPropertyRNA.search callback set,
+ * to check this use `RNA_property_string_search_flag(prop) & PROP_STRING_SEARCH_SUPPORTED`.
+ * \param edit_text: Optionally use the string being edited by the user as a basis
+ * for the search results (auto-complete Python attributes for e.g.).
+ * \param visit_fn: This function is called with every search candidate and is typically
+ * responsible for storing the search results.
+ * \param visit_user_data: Caller defined data, passed to `visit_fn`.
+ */
+typedef void (*StringPropertySearchFunc)(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
typedef int (*EnumPropertyGetFunc)(struct PointerRNA *ptr, struct PropertyRNA *prop);
typedef void (*EnumPropertySetFunc)(struct PointerRNA *ptr, struct PropertyRNA *prop, int value);
/* same as PropEnumItemFunc */
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index c3ca57b38bf..400944d60d4 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -1039,6 +1039,38 @@ static void rna_clamp_value(FILE *f, PropertyRNA *prop, int array)
}
}
+static char *rna_def_property_search_func(FILE *f,
+ StructRNA *srna,
+ PropertyRNA *prop,
+ PropertyDefRNA *UNUSED(dp),
+ const char *manualfunc)
+{
+ char *func;
+
+ if (prop->flag & PROP_IDPROPERTY && manualfunc == NULL) {
+ return NULL;
+ }
+ if (!manualfunc) {
+ return NULL;
+ }
+
+ func = rna_alloc_function_name(srna->identifier, rna_safe_id(prop->identifier), "search");
+
+ fprintf(f,
+ "void %s("
+ "const bContext *C, "
+ "PointerRNA *ptr, "
+ "PropertyRNA *prop, "
+ "const char *edit_text, "
+ "StringPropertySearchVisitFunc visit_fn, "
+ "void *visit_user_data)\n",
+ func);
+ fprintf(f, "{\n");
+ fprintf(f, "\n %s(C, ptr, prop, edit_text, visit_fn, visit_user_data);\n", manualfunc);
+ fprintf(f, "}\n\n");
+ return func;
+}
+
static char *rna_def_property_set_func(
FILE *f, StructRNA *srna, PropertyRNA *prop, PropertyDefRNA *dp, const char *manualfunc)
{
@@ -1895,6 +1927,8 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
sprop->length = (void *)rna_def_property_length_func(
f, srna, prop, dp, (const char *)sprop->length);
sprop->set = (void *)rna_def_property_set_func(f, srna, prop, dp, (const char *)sprop->set);
+ sprop->search = (void *)rna_def_property_search_func(
+ f, srna, prop, dp, (const char *)sprop->search);
break;
}
case PROP_POINTER: {
@@ -4081,13 +4115,15 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
fprintf(f,
- "\t%s, %s, %s, %s, %s, %s, %d, ",
+ "\t%s, %s, %s, %s, %s, %s, %s, %d, %d, ",
rna_function_string(sprop->get),
rna_function_string(sprop->length),
rna_function_string(sprop->set),
rna_function_string(sprop->get_ex),
rna_function_string(sprop->length_ex),
rna_function_string(sprop->set_ex),
+ rna_function_string(sprop->search),
+ (int)sprop->search_flag,
sprop->maxlength);
rna_print_c_string(f, sprop->defaultvalue);
fprintf(f, "\n");
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index b0488bbfa7a..b5cf8abaac6 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -722,7 +722,7 @@ static ID *rna_ID_override_hierarchy_create(
ID *id_root_override = NULL;
BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, id, id_instance_hint, &id_root_override);
+ bmain, scene, view_layer, NULL, id, id, id_instance_hint, &id_root_override, false);
WM_main_add_notifier(NC_ID | NA_ADDED, NULL);
WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL);
@@ -1131,7 +1131,7 @@ static void rna_ImagePreview_size_set(PointerRNA *ptr, const int *values, enum e
prv_img->flag[size] |= (PRV_CHANGED | PRV_USER_EDITED);
}
-static int rna_ImagePreview_pixels_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_pixels_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION],
enum eIconSizes size)
{
@@ -1176,7 +1176,7 @@ static void rna_ImagePreview_pixels_set(PointerRNA *ptr, const int *values, enum
prv_img->flag[size] |= PRV_USER_EDITED;
}
-static int rna_ImagePreview_pixels_float_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_pixels_float_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION],
enum eIconSizes size)
{
@@ -1256,7 +1256,7 @@ static void rna_ImagePreview_image_size_set(PointerRNA *ptr, const int *values)
rna_ImagePreview_size_set(ptr, values, ICON_SIZE_PREVIEW);
}
-static int rna_ImagePreview_image_pixels_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_image_pixels_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
return rna_ImagePreview_pixels_get_length(ptr, length, ICON_SIZE_PREVIEW);
@@ -1272,7 +1272,7 @@ static void rna_ImagePreview_image_pixels_set(PointerRNA *ptr, const int *values
rna_ImagePreview_pixels_set(ptr, values, ICON_SIZE_PREVIEW);
}
-static int rna_ImagePreview_image_pixels_float_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_image_pixels_float_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
return rna_ImagePreview_pixels_float_get_length(ptr, length, ICON_SIZE_PREVIEW);
@@ -1303,7 +1303,7 @@ static void rna_ImagePreview_icon_size_set(PointerRNA *ptr, const int *values)
rna_ImagePreview_size_set(ptr, values, ICON_SIZE_ICON);
}
-static int rna_ImagePreview_icon_pixels_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_icon_pixels_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
return rna_ImagePreview_pixels_get_length(ptr, length, ICON_SIZE_ICON);
@@ -1319,7 +1319,7 @@ static void rna_ImagePreview_icon_pixels_set(PointerRNA *ptr, const int *values)
rna_ImagePreview_pixels_set(ptr, values, ICON_SIZE_ICON);
}
-static int rna_ImagePreview_icon_pixels_float_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_icon_pixels_float_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
return rna_ImagePreview_pixels_float_get_length(ptr, length, ICON_SIZE_ICON);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 53fa7a3d923..c8cb0b7ffb8 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -302,7 +302,8 @@ static int rna_ensure_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
{
if (prop->magic == RNA_MAGIC) {
int arraylen[RNA_MAX_ARRAY_DIMENSION];
- return (prop->getlength && ptr->data) ? prop->getlength(ptr, arraylen) : prop->totarraylength;
+ return (prop->getlength && ptr->data) ? prop->getlength(ptr, arraylen) :
+ (int)prop->totarraylength;
}
IDProperty *idprop = (IDProperty *)prop;
@@ -322,7 +323,7 @@ static bool rna_ensure_property_array_check(PropertyRNA *prop)
return (idprop->type == IDP_ARRAY);
}
-static void rna_ensure_property_multi_array_length(PointerRNA *ptr,
+static void rna_ensure_property_multi_array_length(const PointerRNA *ptr,
PropertyRNA *prop,
int length[])
{
@@ -1080,7 +1081,7 @@ bool RNA_property_array_check(PropertyRNA *prop)
return rna_ensure_property_array_check(prop);
}
-int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[])
+int RNA_property_array_dimension(const PointerRNA *ptr, PropertyRNA *prop, int length[])
{
PropertyRNA *rprop = rna_ensure_property(prop);
@@ -3368,6 +3369,34 @@ int RNA_property_string_default_length(PointerRNA *UNUSED(ptr), PropertyRNA *pro
return strlen(sprop->defaultvalue);
}
+eStringPropertySearchFlag RNA_property_string_search_flag(PropertyRNA *prop)
+{
+ StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
+ if (prop->magic != RNA_MAGIC) {
+ return false;
+ }
+ BLI_assert(RNA_property_type(prop) == PROP_STRING);
+ if (sprop->search) {
+ BLI_assert(sprop->search_flag & PROP_STRING_SEARCH_SUPPORTED);
+ }
+ else {
+ BLI_assert(sprop->search_flag == 0);
+ }
+ return sprop->search_flag;
+}
+
+void RNA_property_string_search(const bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ BLI_assert(RNA_property_string_search_flag(prop) & PROP_STRING_SEARCH_SUPPORTED);
+ StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
+ sprop->search(C, ptr, prop, edit_text, visit_fn, visit_user_data);
+}
+
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
@@ -4025,7 +4054,9 @@ void RNA_property_collection_clear(PointerRNA *ptr, PropertyRNA *prop)
}
}
-int RNA_property_collection_lookup_index(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *t_ptr)
+int RNA_property_collection_lookup_index(PointerRNA *ptr,
+ PropertyRNA *prop,
+ const PointerRNA *t_ptr)
{
CollectionPropertyIterator iter;
int index = 0;
@@ -5105,7 +5136,7 @@ static bool rna_path_parse_array_index(const char **path,
*
* \return \a true on success, \a false if the path is somehow invalid.
*/
-static bool rna_path_parse(PointerRNA *ptr,
+static bool rna_path_parse(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
@@ -5262,7 +5293,10 @@ static bool rna_path_parse(PointerRNA *ptr,
return true;
}
-bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
+bool RNA_path_resolve(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop)
{
if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, true)) {
return false;
@@ -5272,7 +5306,7 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop
}
bool RNA_path_resolve_full(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+ const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true)) {
return false;
@@ -5282,12 +5316,12 @@ bool RNA_path_resolve_full(
}
bool RNA_path_resolve_full_maybe_null(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+ const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
return rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true);
}
-bool RNA_path_resolve_property(PointerRNA *ptr,
+bool RNA_path_resolve_property(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop)
@@ -5300,7 +5334,7 @@ bool RNA_path_resolve_property(PointerRNA *ptr,
}
bool RNA_path_resolve_property_full(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+ const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, false)) {
return false;
@@ -5309,7 +5343,7 @@ bool RNA_path_resolve_property_full(
return r_ptr->data != NULL && *r_prop != NULL;
}
-bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
+bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
@@ -5322,7 +5356,7 @@ bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
return r_ptr->data != NULL && *r_prop != NULL;
}
-bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
+bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
@@ -5340,8 +5374,11 @@ bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_el
return rna_path_parse(ptr, path, NULL, NULL, NULL, NULL, r_elements, false);
}
-char *RNA_path_append(
- const char *path, PointerRNA *UNUSED(ptr), PropertyRNA *prop, int intkey, const char *strkey)
+char *RNA_path_append(const char *path,
+ const PointerRNA *UNUSED(ptr),
+ PropertyRNA *prop,
+ int intkey,
+ const char *strkey)
{
DynStr *dynstr;
char *result;
@@ -5724,7 +5761,7 @@ char *RNA_path_from_ID_to_struct(const PointerRNA *ptr)
return ptrpath;
}
-char *RNA_path_from_real_ID_to_struct(Main *bmain, PointerRNA *ptr, struct ID **r_real)
+char *RNA_path_from_real_ID_to_struct(Main *bmain, const PointerRNA *ptr, struct ID **r_real)
{
char *path = RNA_path_from_ID_to_struct(ptr);
@@ -5753,7 +5790,7 @@ static void rna_path_array_multi_from_flat_index(const int dimsize[RNA_MAX_ARRAY
BLI_assert(index == 0);
}
-static void rna_path_array_multi_string_from_flat_index(PointerRNA *ptr,
+static void rna_path_array_multi_string_from_flat_index(const PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
int index,
@@ -5772,7 +5809,7 @@ static void rna_path_array_multi_string_from_flat_index(PointerRNA *ptr,
}
}
-char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
+char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
int index)
@@ -5828,13 +5865,17 @@ char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
return path;
}
-char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
+char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
{
return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1);
}
-char *RNA_path_from_real_ID_to_property_index(
- Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index, ID **r_real_id)
+char *RNA_path_from_real_ID_to_property_index(Main *bmain,
+ const PointerRNA *ptr,
+ PropertyRNA *prop,
+ int index_dim,
+ int index,
+ ID **r_real_id)
{
char *path = RNA_path_from_ID_to_property_index(ptr, prop, index_dim, index);
@@ -5843,7 +5884,7 @@ char *RNA_path_from_real_ID_to_property_index(
return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL;
}
-char *RNA_path_resolve_from_type_to_property(PointerRNA *ptr,
+char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr,
PropertyRNA *prop,
const StructRNA *type)
{
@@ -5916,7 +5957,7 @@ char *RNA_path_full_ID_py(Main *bmain, ID *id)
path);
}
-char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
+char *RNA_path_full_struct_py(Main *bmain, const PointerRNA *ptr)
{
char *id_path;
char *data_path;
@@ -5945,7 +5986,7 @@ char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
}
char *RNA_path_full_property_py_ex(
- Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
+ Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
{
char *id_path;
const char *data_delim;
@@ -5992,7 +6033,7 @@ char *RNA_path_full_property_py_ex(
return ret;
}
-char *RNA_path_full_property_py(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index)
+char *RNA_path_full_property_py(Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index)
{
return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false);
}
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 76d2087d904..a1266443631 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -340,7 +340,7 @@ bool rna_Action_actedit_assign_poll(PointerRNA *ptr, PointerRNA value)
return 0;
}
-static char *rna_DopeSheet_path(PointerRNA *UNUSED(ptr))
+static char *rna_DopeSheet_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("dopesheet");
}
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index df92601dd0c..a4094630266 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -216,10 +216,10 @@ static void rna_Bone_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
WM_main_add_notifier(NC_ANIMATION | ND_ANIMCHAN, id);
}
-static char *rna_Bone_path(PointerRNA *ptr)
+static char *rna_Bone_path(const PointerRNA *ptr)
{
- ID *id = ptr->owner_id;
- Bone *bone = (Bone *)ptr->data;
+ const ID *id = ptr->owner_id;
+ const Bone *bone = (const Bone *)ptr->data;
char name_esc[sizeof(bone->name) * 2];
BLI_str_escape(name_esc, bone->name, sizeof(name_esc));
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index 2d9517ce1ee..36706c82366 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -118,9 +118,9 @@ const EnumPropertyItem rna_enum_color_attribute_domain_items[] = {
/* Attribute */
-static char *rna_Attribute_path(PointerRNA *ptr)
+static char *rna_Attribute_path(const PointerRNA *ptr)
{
- CustomDataLayer *layer = ptr->data;
+ const CustomDataLayer *layer = ptr->data;
return BLI_sprintfN("attributes['%s']", layer->name);
}
diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c
index 0818f009d1f..d65c8a1b4e3 100644
--- a/source/blender/makesrna/intern/rna_boid.c
+++ b/source/blender/makesrna/intern/rna_boid.c
@@ -162,9 +162,9 @@ static StructRNA *rna_BoidRule_refine(struct PointerRNA *ptr)
}
}
-static char *rna_BoidRule_path(PointerRNA *ptr)
+static char *rna_BoidRule_path(const PointerRNA *ptr)
{
- BoidRule *rule = (BoidRule *)ptr->data;
+ const BoidRule *rule = (BoidRule *)ptr->data;
char name_esc[sizeof(rule->name) * 2];
BLI_str_escape(name_esc, rule->name, sizeof(name_esc));
@@ -222,16 +222,16 @@ static void rna_BoidState_active_boid_rule_index_set(struct PointerRNA *ptr, int
}
}
-static int particle_id_check(PointerRNA *ptr)
+static int particle_id_check(const PointerRNA *ptr)
{
- ID *id = ptr->owner_id;
+ const ID *id = ptr->owner_id;
return (GS(id->name) == ID_PA);
}
-static char *rna_BoidSettings_path(PointerRNA *ptr)
+static char *rna_BoidSettings_path(const PointerRNA *ptr)
{
- BoidSettings *boids = (BoidSettings *)ptr->data;
+ const BoidSettings *boids = (BoidSettings *)ptr->data;
if (particle_id_check(ptr)) {
ParticleSettings *part = (ParticleSettings *)ptr->owner_id;
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 4767ef2c017..72f5bd1923c 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -934,7 +934,7 @@ static const EnumPropertyItem *rna_Brush_stroke_itemf(bContext *C,
}
/* Grease Pencil Drawing Brushes Settings */
-static char *rna_BrushGpencilSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_BrushGpencilSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_paint.brush.gpencil_settings");
}
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index f535cdcee96..92df7293c2e 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -117,7 +117,7 @@ static void rna_Camera_dof_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
}
-char *rna_CameraDOFSettings_path(PointerRNA *ptr)
+char *rna_CameraDOFSettings_path(const PointerRNA *ptr)
{
/* if there is ID-data, resolve the path using the index instead of by name,
* since the name used is the name of the texture assigned, but the texture
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index 3ad901e5397..e45a1a3cc33 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -436,10 +436,10 @@ static void rna_ClothSettings_gravity_set(PointerRNA *ptr, const float *values)
sim->gravity[2] = values[2];
}
-static char *rna_ClothSettings_path(PointerRNA *ptr)
+static char *rna_ClothSettings_path(const PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
+ const Object *ob = (Object *)ptr->owner_id;
+ const ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
if (md) {
char name_esc[sizeof(md->name) * 2];
@@ -451,10 +451,10 @@ static char *rna_ClothSettings_path(PointerRNA *ptr)
}
}
-static char *rna_ClothCollisionSettings_path(PointerRNA *ptr)
+static char *rna_ClothCollisionSettings_path(const PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
+ const Object *ob = (Object *)ptr->owner_id;
+ const ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
if (md) {
char name_esc[sizeof(md->name) * 2];
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 840674c7bc6..92cdcc6d781 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -157,7 +157,7 @@ static void rna_CurveMapping_clipmaxy_range(
*max = 100.0f;
}
-static char *rna_ColorRamp_path(PointerRNA *ptr)
+static char *rna_ColorRamp_path(const PointerRNA *ptr)
{
char *path = NULL;
@@ -208,7 +208,7 @@ static char *rna_ColorRamp_path(PointerRNA *ptr)
return path;
}
-static char *rna_ColorRampElement_path(PointerRNA *ptr)
+static char *rna_ColorRampElement_path(const PointerRNA *ptr)
{
PointerRNA ramp_ptr;
PropertyRNA *prop;
@@ -438,7 +438,7 @@ static void rna_ColorManagedDisplaySettings_display_device_update(Main *bmain,
}
}
-static char *rna_ColorManagedDisplaySettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ColorManagedDisplaySettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("display_settings");
}
@@ -526,7 +526,7 @@ static void rna_ColorManagedViewSettings_use_curves_set(PointerRNA *ptr, bool va
}
}
-static char *rna_ColorManagedViewSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ColorManagedViewSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("view_settings");
}
@@ -662,12 +662,12 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain,
}
}
-static char *rna_ColorManagedSequencerColorspaceSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ColorManagedSequencerColorspaceSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("sequencer_colorspace_settings");
}
-static char *rna_ColorManagedInputColorspaceSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ColorManagedInputColorspaceSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("colorspace_settings");
}
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 63d8876ec8b..8829c655030 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -440,7 +440,7 @@ static char *rna_Constraint_do_compute_path(Object *ob, bConstraint *con)
}
}
-static char *rna_Constraint_path(PointerRNA *ptr)
+static char *rna_Constraint_path(const PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
bConstraint *con = ptr->data;
@@ -448,7 +448,7 @@ static char *rna_Constraint_path(PointerRNA *ptr)
return rna_Constraint_do_compute_path(ob, con);
}
-static bConstraint *rna_constraint_from_target(PointerRNA *ptr)
+static bConstraint *rna_constraint_from_target(const PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
bConstraintTarget *tgt = ptr->data;
@@ -456,7 +456,7 @@ static bConstraint *rna_constraint_from_target(PointerRNA *ptr)
return BKE_constraint_find_from_target(ob, tgt, NULL);
}
-static char *rna_ConstraintTarget_path(PointerRNA *ptr)
+static char *rna_ConstraintTarget_path(const PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
bConstraintTarget *tgt = ptr->data;
@@ -691,11 +691,11 @@ static void rna_ActionConstraint_minmax_range(
}
}
-static int rna_SplineIKConstraint_joint_bindings_get_length(PointerRNA *ptr,
+static int rna_SplineIKConstraint_joint_bindings_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
- bConstraint *con = (bConstraint *)ptr->data;
- bSplineIKConstraint *ikData = (bSplineIKConstraint *)con->data;
+ const bConstraint *con = (bConstraint *)ptr->data;
+ const bSplineIKConstraint *ikData = (bSplineIKConstraint *)con->data;
if (ikData) {
length[0] = ikData->numpoints;
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index fb911725836..49b78e90024 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -770,7 +770,7 @@ static void rna_Curve_active_spline_set(PointerRNA *ptr,
}
}
-static char *rna_Curve_spline_path(PointerRNA *ptr)
+static char *rna_Curve_spline_path(const PointerRNA *ptr)
{
Curve *cu = (Curve *)ptr->owner_id;
ListBase *nubase = BKE_curve_nurbs_get(cu);
@@ -786,7 +786,7 @@ static char *rna_Curve_spline_path(PointerRNA *ptr)
}
/* use for both bezier and nurbs */
-static char *rna_Curve_spline_point_path(PointerRNA *ptr)
+static char *rna_Curve_spline_point_path(const PointerRNA *ptr)
{
Curve *cu = (Curve *)ptr->owner_id;
Nurb *nu;
@@ -808,10 +808,10 @@ static char *rna_Curve_spline_point_path(PointerRNA *ptr)
}
}
-static char *rna_TextBox_path(PointerRNA *ptr)
+static char *rna_TextBox_path(const PointerRNA *ptr)
{
- Curve *cu = (Curve *)ptr->owner_id;
- TextBox *tb = ptr->data;
+ const Curve *cu = (Curve *)ptr->owner_id;
+ const TextBox *tb = ptr->data;
int index = (int)(tb - cu->tb);
if (index >= 0 && index < cu->totbox) {
diff --git a/source/blender/makesrna/intern/rna_curves.c b/source/blender/makesrna/intern/rna_curves.c
index 2b406125409..7cf34db4cf4 100644
--- a/source/blender/makesrna/intern/rna_curves.c
+++ b/source/blender/makesrna/intern/rna_curves.c
@@ -30,7 +30,7 @@
# include "WM_api.h"
# include "WM_types.h"
-static Curves *rna_curves(PointerRNA *ptr)
+static Curves *rna_curves(const PointerRNA *ptr)
{
return (Curves *)ptr->owner_id;
}
@@ -52,13 +52,18 @@ static void rna_Curves_curve_offset_data_begin(CollectionPropertyIterator *iter,
NULL);
}
-static int rna_CurvePoint_index_get(PointerRNA *ptr)
+static int rna_CurvePoint_index_get_const(const PointerRNA *ptr)
{
const Curves *curves = rna_curves(ptr);
const float(*co)[3] = ptr->data;
return (int)(co - curves->geometry.position);
}
+static int rna_CurvePoint_index_get(PointerRNA *ptr)
+{
+ return rna_CurvePoint_index_get_const(ptr);
+}
+
static void rna_CurvePoint_location_get(PointerRNA *ptr, float value[3])
{
copy_v3_v3(value, (const float *)ptr->data);
@@ -89,20 +94,25 @@ static void rna_CurvePoint_radius_set(PointerRNA *ptr, float value)
curves->geometry.radius[co - curves->geometry.position] = value;
}
-static char *rna_CurvePoint_path(PointerRNA *ptr)
+static char *rna_CurvePoint_path(const PointerRNA *ptr)
{
- return BLI_sprintfN("points[%d]", rna_CurvePoint_index_get(ptr));
+ return BLI_sprintfN("points[%d]", rna_CurvePoint_index_get_const(ptr));
}
-static int rna_CurveSlice_index_get(PointerRNA *ptr)
+static int rna_CurveSlice_index_get_const(const PointerRNA *ptr)
{
Curves *curves = rna_curves(ptr);
return (int)((int *)ptr->data - curves->geometry.curve_offsets);
}
-static char *rna_CurveSlice_path(PointerRNA *ptr)
+static int rna_CurveSlice_index_get(PointerRNA *ptr)
+{
+ return rna_CurveSlice_index_get_const(ptr);
+}
+
+static char *rna_CurveSlice_path(const PointerRNA *ptr)
{
- return BLI_sprintfN("curves[%d]", rna_CurveSlice_index_get(ptr));
+ return BLI_sprintfN("curves[%d]", rna_CurveSlice_index_get_const(ptr));
}
static void rna_CurveSlice_points_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 1e950b883ab..dfb551fcb05 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -3316,6 +3316,33 @@ void RNA_def_property_string_funcs(PropertyRNA *prop,
}
}
+void RNA_def_property_string_search_func(PropertyRNA *prop,
+ const char *search,
+ const eStringPropertySearchFlag search_flag)
+{
+ StructRNA *srna = DefRNA.laststruct;
+
+ if (!DefRNA.preprocess) {
+ CLOG_ERROR(&LOG, "only during preprocessing.");
+ return;
+ }
+
+ switch (prop->type) {
+ case PROP_STRING: {
+ StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
+ sprop->search = (StringPropertySearchFunc)search;
+ if (search != NULL) {
+ sprop->search_flag = search_flag | PROP_STRING_SEARCH_SUPPORTED;
+ }
+ break;
+ }
+ default:
+ CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
+ DefRNA.error = true;
+ break;
+ }
+}
+
void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
StringPropertyGetFunc getfunc,
StringPropertyLengthFunc lengthfunc,
@@ -3343,6 +3370,18 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
}
}
+void RNA_def_property_string_search_func_runtime(PropertyRNA *prop,
+ StringPropertySearchFunc search_fn,
+ const eStringPropertySearchFlag search_flag)
+{
+ StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
+
+ sprop->search = search_fn;
+ if (search_fn != NULL) {
+ sprop->search_flag = search_flag | PROP_STRING_SEARCH_SUPPORTED;
+ }
+}
+
void RNA_def_property_pointer_funcs(
PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll)
{
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index ed6d4996c1e..6f9fe3741f7 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -37,30 +37,30 @@ const EnumPropertyItem rna_enum_prop_dynamicpaint_type_items[] = {
# include "DEG_depsgraph.h"
# include "DEG_depsgraph_build.h"
-static char *rna_DynamicPaintCanvasSettings_path(PointerRNA *ptr)
+static char *rna_DynamicPaintCanvasSettings_path(const PointerRNA *ptr)
{
- DynamicPaintCanvasSettings *settings = (DynamicPaintCanvasSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->pmd;
+ const DynamicPaintCanvasSettings *settings = (DynamicPaintCanvasSettings *)ptr->data;
+ const ModifierData *md = (ModifierData *)settings->pmd;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].canvas_settings", name_esc);
}
-static char *rna_DynamicPaintBrushSettings_path(PointerRNA *ptr)
+static char *rna_DynamicPaintBrushSettings_path(const PointerRNA *ptr)
{
- DynamicPaintBrushSettings *settings = (DynamicPaintBrushSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->pmd;
+ const DynamicPaintBrushSettings *settings = (DynamicPaintBrushSettings *)ptr->data;
+ const ModifierData *md = (ModifierData *)settings->pmd;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].brush_settings", name_esc);
}
-static char *rna_DynamicPaintSurface_path(PointerRNA *ptr)
+static char *rna_DynamicPaintSurface_path(const PointerRNA *ptr)
{
- DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data;
- ModifierData *md = (ModifierData *)surface->canvas->pmd;
+ const DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data;
+ const ModifierData *md = (ModifierData *)surface->canvas->pmd;
char name_esc[sizeof(md->name) * 2];
char name_esc_surface[sizeof(surface->name) * 2];
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index af14a169d68..e14a291dd01 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -786,11 +786,11 @@ static void rna_FModifier_active_update(Main *bmain, Scene *scene, PointerRNA *p
rna_FModifier_update(bmain, scene, ptr);
}
-static int rna_FModifierGenerator_coefficients_get_length(PointerRNA *ptr,
+static int rna_FModifierGenerator_coefficients_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
- FModifier *fcm = (FModifier *)ptr->data;
- FMod_Generator *gen = fcm->data;
+ const FModifier *fcm = (FModifier *)ptr->data;
+ const FMod_Generator *gen = fcm->data;
if (gen) {
length[0] = gen->arraysize;
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index e0ec146a248..3b22ae9d40f 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -857,30 +857,30 @@ static void rna_Fluid_domaintype_set(struct PointerRNA *ptr, int value)
BKE_fluid_fields_sanitize(settings);
}
-static char *rna_FluidDomainSettings_path(PointerRNA *ptr)
+static char *rna_FluidDomainSettings_path(const PointerRNA *ptr)
{
- FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->fmd;
+ const FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ const ModifierData *md = (ModifierData *)settings->fmd;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].domain_settings", name_esc);
}
-static char *rna_FluidFlowSettings_path(PointerRNA *ptr)
+static char *rna_FluidFlowSettings_path(const PointerRNA *ptr)
{
- FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->fmd;
+ const FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data;
+ const ModifierData *md = (ModifierData *)settings->fmd;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].flow_settings", name_esc);
}
-static char *rna_FluidEffectorSettings_path(PointerRNA *ptr)
+static char *rna_FluidEffectorSettings_path(const PointerRNA *ptr)
{
- FluidEffectorSettings *settings = (FluidEffectorSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->fmd;
+ const FluidEffectorSettings *settings = (FluidEffectorSettings *)ptr->data;
+ const ModifierData *md = (ModifierData *)settings->fmd;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
@@ -893,9 +893,10 @@ static char *rna_FluidEffectorSettings_path(PointerRNA *ptr)
# ifdef WITH_FLUID
-static int rna_FluidModifier_grid_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_FluidModifier_grid_get_length(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
+ const FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
float *density = NULL;
int size = 0;
@@ -918,7 +919,7 @@ static int rna_FluidModifier_grid_get_length(PointerRNA *ptr, int length[RNA_MAX
return length[0];
}
-static int rna_FluidModifier_color_grid_get_length(PointerRNA *ptr,
+static int rna_FluidModifier_color_grid_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
rna_FluidModifier_grid_get_length(ptr, length);
@@ -927,10 +928,10 @@ static int rna_FluidModifier_color_grid_get_length(PointerRNA *ptr,
return length[0];
}
-static int rna_FluidModifier_velocity_grid_get_length(PointerRNA *ptr,
+static int rna_FluidModifier_velocity_grid_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
- FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
+ const FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
float *vx = NULL;
float *vy = NULL;
float *vz = NULL;
@@ -948,10 +949,10 @@ static int rna_FluidModifier_velocity_grid_get_length(PointerRNA *ptr,
return length[0];
}
-static int rna_FluidModifier_heat_grid_get_length(PointerRNA *ptr,
+static int rna_FluidModifier_heat_grid_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
- FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
+ const FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
float *heat = NULL;
int size = 0;
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 9a9b6d582e5..6854ce37c94 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -307,7 +307,7 @@ bool rna_GPencil_datablocks_obdata_poll(PointerRNA *UNUSED(ptr), const PointerRN
return (gpd->flag & GP_DATA_ANNOTATIONS) == 0;
}
-static char *rna_GPencilLayer_path(PointerRNA *ptr)
+static char *rna_GPencilLayer_path(const PointerRNA *ptr)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
char name_esc[sizeof(gpl->info) * 2];
@@ -407,7 +407,7 @@ static void rna_GPencilLayer_parent_bone_set(PointerRNA *ptr, const char *value)
}
}
-static char *rna_GPencilLayerMask_path(PointerRNA *ptr)
+static char *rna_GPencilLayerMask_path(const PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->owner_id;
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
@@ -1122,7 +1122,7 @@ static void rna_GPencil_clear(bGPdata *gpd)
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
-static char *rna_GreasePencilGrid_path(PointerRNA *UNUSED(ptr))
+static char *rna_GreasePencilGrid_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("grid");
}
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 778f5647417..8bbc33d2381 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -195,6 +195,7 @@ static const EnumPropertyItem rna_enum_time_mode_items[] = {
{GP_TIME_MODE_NORMAL, "NORMAL", 0, "Regular", "Apply offset in usual animation direction"},
{GP_TIME_MODE_REVERSE, "REVERSE", 0, "Reverse", "Apply offset in reverse animation direction"},
{GP_TIME_MODE_FIX, "FIX", 0, "Fixed Frame", "Keep frame and do not change with time"},
+ {GP_TIME_MODE_PINGPONG, "PINGPONG", 0, "Ping Pong", "Loop back and forth"},
{0, NULL, 0, NULL, NULL},
};
@@ -340,9 +341,9 @@ static void rna_GpencilModifier_name_set(PointerRNA *ptr, const char *value)
BKE_animdata_fix_paths_rename_all(NULL, "grease_pencil_modifiers", oldname, gmd->name);
}
-static char *rna_GpencilModifier_path(PointerRNA *ptr)
+static char *rna_GpencilModifier_path(const PointerRNA *ptr)
{
- GpencilModifierData *gmd = ptr->data;
+ const GpencilModifierData *gmd = ptr->data;
char name_esc[sizeof(gmd->name) * 2];
BLI_str_escape(name_esc, gmd->name, sizeof(name_esc));
@@ -751,11 +752,11 @@ static void rna_GpencilDash_segments_begin(CollectionPropertyIterator *iter, Poi
iter, dmd->segments, sizeof(DashGpencilModifierSegment), dmd->segments_len, false, NULL);
}
-static char *rna_DashGpencilModifierSegment_path(PointerRNA *ptr)
+static char *rna_DashGpencilModifierSegment_path(const PointerRNA *ptr)
{
- DashGpencilModifierSegment *ds = (DashGpencilModifierSegment *)ptr->data;
+ const DashGpencilModifierSegment *ds = (DashGpencilModifierSegment *)ptr->data;
- DashGpencilModifierData *dmd = (DashGpencilModifierData *)ds->dmd;
+ const DashGpencilModifierData *dmd = (DashGpencilModifierData *)ds->dmd;
BLI_assert(dmd != NULL);
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 81708ac8e65..269ebe1581f 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -175,7 +175,7 @@ static void rna_ImageUser_relations_update(Main *bmain, Scene *scene, PointerRNA
DEG_relations_tag_update(bmain);
}
-static char *rna_ImageUser_path(PointerRNA *ptr)
+static char *rna_ImageUser_path(const PointerRNA *ptr)
{
if (ptr->owner_id) {
/* ImageUser *iuser = ptr->data; */
@@ -397,7 +397,7 @@ static void rna_Image_resolution_set(PointerRNA *ptr, const float *values)
static int rna_Image_bindcode_get(PointerRNA *ptr)
{
Image *ima = (Image *)ptr->data;
- GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0][IMA_TEXTURE_RESOLUTION_FULL];
+ GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
return (tex) ? GPU_texture_opengl_bindcode(tex) : 0;
}
@@ -446,7 +446,7 @@ static int rna_Image_frame_duration_get(PointerRNA *ptr)
return duration;
}
-static int rna_Image_pixels_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_Image_pixels_get_length(const PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
{
Image *ima = (Image *)ptr->owner_id;
ImBuf *ibuf;
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index b385f576585..bac8f214441 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -156,6 +156,7 @@ static void rna_Image_update(Image *image, ReportList *reports)
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ BKE_image_partial_update_mark_full_update(image);
BKE_image_release_ibuf(image, ibuf, NULL);
}
@@ -197,7 +198,7 @@ static int rna_Image_gl_touch(
BKE_image_tag_time(image);
- if (image->gputexture[TEXTARGET_2D][0][IMA_TEXTURE_RESOLUTION_FULL] == NULL) {
+ if (image->gputexture[TEXTARGET_2D][0] == NULL) {
error = rna_Image_gl_load(image, reports, frame, layer_index, pass_index);
}
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index bf4eec433c4..058c63f640a 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -373,7 +373,7 @@ void rna_ViewLayer_active_lightgroup_index_set(PointerRNA *ptr, int value);
* `rna_path_buffer_size` should be at least `sizeof(ViewLayer.name) * 3`.
* \return actual length of the generated RNA path.
*/
-size_t rna_ViewLayer_path_buffer_get(struct ViewLayer *view_layer,
+size_t rna_ViewLayer_path_buffer_get(const struct ViewLayer *view_layer,
char *r_rna_path,
const size_t rna_path_buffer_size);
@@ -402,8 +402,8 @@ bool rna_GPencil_datablocks_annotations_poll(struct PointerRNA *ptr,
const struct PointerRNA value);
bool rna_GPencil_datablocks_obdata_poll(struct PointerRNA *ptr, const struct PointerRNA value);
-char *rna_TextureSlot_path(struct PointerRNA *ptr);
-char *rna_Node_ImageUser_path(struct PointerRNA *ptr);
+char *rna_TextureSlot_path(const struct PointerRNA *ptr);
+char *rna_Node_ImageUser_path(const struct PointerRNA *ptr);
/* Set U.is_dirty and redraw. */
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 4db438f04b4..4f88959b5ba 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -50,9 +50,10 @@ typedef int (*EditableFunc)(struct PointerRNA *ptr, const char **r_info);
typedef int (*ItemEditableFunc)(struct PointerRNA *ptr, int index);
typedef struct IDProperty **(*IDPropertiesFunc)(struct PointerRNA *ptr);
typedef struct StructRNA *(*StructRefineFunc)(struct PointerRNA *ptr);
-typedef char *(*StructPathFunc)(struct PointerRNA *ptr);
+typedef char *(*StructPathFunc)(const struct PointerRNA *ptr);
-typedef int (*PropArrayLengthGetFunc)(struct PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]);
+typedef int (*PropArrayLengthGetFunc)(const struct PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION]);
typedef bool (*PropBooleanGetFunc)(struct PointerRNA *ptr);
typedef void (*PropBooleanSetFunc)(struct PointerRNA *ptr, bool value);
typedef void (*PropBooleanArrayGetFunc)(struct PointerRNA *ptr, bool *values);
@@ -439,6 +440,15 @@ typedef struct StringPropertyRNA {
PropStringLengthFuncEx length_ex;
PropStringSetFuncEx set_ex;
+ /**
+ * Optional callback to list candidates for a string.
+ * This is only for use as suggestions in UI, other values may be assigned.
+ *
+ * \note The callback type is public, hence the difference in naming convention.
+ */
+ StringPropertySearchFunc search;
+ eStringPropertySearchFlag search_flag;
+
int maxlength; /* includes string terminator! */
const char *defaultvalue;
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index 50b25157989..2f6fb30dc49 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -159,7 +159,7 @@ static void rna_ShapeKey_slider_max_set(PointerRNA *ptr, float value)
* such case looks rather unlikely - and not worth adding some kind of caching in key-blocks.
*/
-static Mesh *rna_KeyBlock_normals_get_mesh(PointerRNA *ptr, ID *id)
+static Mesh *rna_KeyBlock_normals_get_mesh(const PointerRNA *ptr, ID *id)
{
Key *key = rna_ShapeKey_find_key((id == NULL && ptr != NULL) ? ptr->owner_id : id);
id = key ? key->from : NULL;
@@ -182,9 +182,10 @@ static Mesh *rna_KeyBlock_normals_get_mesh(PointerRNA *ptr, ID *id)
return NULL;
}
-static int rna_KeyBlock_normals_vert_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_KeyBlock_normals_vert_len(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
+ const Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
length[0] = me ? me->totvert : 0;
length[1] = 3;
@@ -211,9 +212,10 @@ static void rna_KeyBlock_normals_vert_calc(ID *id,
BKE_keyblock_mesh_calc_normals(data, me, (float(*)[3])(*normals), NULL, NULL);
}
-static int rna_KeyBlock_normals_poly_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_KeyBlock_normals_poly_len(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
+ const Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
length[0] = me ? me->totpoly : 0;
length[1] = 3;
@@ -240,9 +242,10 @@ static void rna_KeyBlock_normals_poly_calc(ID *id,
BKE_keyblock_mesh_calc_normals(data, me, NULL, (float(*)[3])(*normals), NULL);
}
-static int rna_KeyBlock_normals_loop_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_KeyBlock_normals_loop_len(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
+ const Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
length[0] = me ? me->totloop : 0;
length[1] = 3;
@@ -656,10 +659,10 @@ int rna_ShapeKey_data_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
return false;
}
-static char *rna_ShapeKey_path(PointerRNA *ptr)
+static char *rna_ShapeKey_path(const PointerRNA *ptr)
{
- KeyBlock *kb = (KeyBlock *)ptr->data;
- ID *id = ptr->owner_id;
+ const KeyBlock *kb = (KeyBlock *)ptr->data;
+ const ID *id = ptr->owner_id;
char name_esc[sizeof(kb->name) * 2];
BLI_str_escape(name_esc, kb->name, sizeof(name_esc));
@@ -750,7 +753,7 @@ static int rna_ShapeKeyPoint_get_index(Key *key, KeyBlock *kb, float *point)
return (int)(pt - start) / key->elemsize;
}
-static char *rna_ShapeKeyPoint_path(PointerRNA *ptr)
+static char *rna_ShapeKeyPoint_path(const PointerRNA *ptr)
{
ID *id = ptr->owner_id;
Key *key = rna_ShapeKey_find_key(ptr->owner_id);
diff --git a/source/blender/makesrna/intern/rna_lattice.c b/source/blender/makesrna/intern/rna_lattice.c
index 8fb36c035b7..f94804cb609 100644
--- a/source/blender/makesrna/intern/rna_lattice.c
+++ b/source/blender/makesrna/intern/rna_lattice.c
@@ -209,11 +209,11 @@ static void rna_Lattice_vg_name_set(PointerRNA *ptr, const char *value)
}
/* annoying, but is a consequence of RNA structures... */
-static char *rna_LatticePoint_path(PointerRNA *ptr)
+static char *rna_LatticePoint_path(const PointerRNA *ptr)
{
- Lattice *lt = (Lattice *)ptr->owner_id;
- void *point = ptr->data;
- BPoint *points = NULL;
+ const Lattice *lt = (Lattice *)ptr->owner_id;
+ const void *point = ptr->data;
+ const BPoint *points = NULL;
if (lt->editlatt && lt->editlatt->latt->def) {
points = lt->editlatt->latt->def;
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index 42414a9931b..8c9c66bffcf 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -98,7 +98,7 @@ static void rna_LayerObjects_active_object_set(PointerRNA *ptr,
}
}
-size_t rna_ViewLayer_path_buffer_get(ViewLayer *view_layer,
+size_t rna_ViewLayer_path_buffer_get(const ViewLayer *view_layer,
char *r_rna_path,
const size_t rna_path_buffer_size)
{
@@ -108,9 +108,9 @@ size_t rna_ViewLayer_path_buffer_get(ViewLayer *view_layer,
return BLI_snprintf_rlen(r_rna_path, rna_path_buffer_size, "view_layers[\"%s\"]", name_esc);
}
-static char *rna_ViewLayer_path(PointerRNA *ptr)
+static char *rna_ViewLayer_path(const PointerRNA *ptr)
{
- ViewLayer *view_layer = (ViewLayer *)ptr->data;
+ const ViewLayer *view_layer = (ViewLayer *)ptr->data;
char rna_path[sizeof(view_layer->name) * 3];
rna_ViewLayer_path_buffer_get(view_layer, rna_path, sizeof(rna_path));
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index 2a8a3a76c6d..c18ee461fae 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -239,33 +239,33 @@ static StructRNA *rna_LineStyle_geometry_modifier_refine(struct PointerRNA *ptr)
}
}
-static char *rna_LineStyle_color_modifier_path(PointerRNA *ptr)
+static char *rna_LineStyle_color_modifier_path(const PointerRNA *ptr)
{
- LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+ const LineStyleModifier *m = (LineStyleModifier *)ptr->data;
char name_esc[sizeof(m->name) * 2];
BLI_str_escape(name_esc, m->name, sizeof(name_esc));
return BLI_sprintfN("color_modifiers[\"%s\"]", name_esc);
}
-static char *rna_LineStyle_alpha_modifier_path(PointerRNA *ptr)
+static char *rna_LineStyle_alpha_modifier_path(const PointerRNA *ptr)
{
- LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+ const LineStyleModifier *m = (LineStyleModifier *)ptr->data;
char name_esc[sizeof(m->name) * 2];
BLI_str_escape(name_esc, m->name, sizeof(name_esc));
return BLI_sprintfN("alpha_modifiers[\"%s\"]", name_esc);
}
-static char *rna_LineStyle_thickness_modifier_path(PointerRNA *ptr)
+static char *rna_LineStyle_thickness_modifier_path(const PointerRNA *ptr)
{
- LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+ const LineStyleModifier *m = (LineStyleModifier *)ptr->data;
char name_esc[sizeof(m->name) * 2];
BLI_str_escape(name_esc, m->name, sizeof(name_esc));
return BLI_sprintfN("thickness_modifiers[\"%s\"]", name_esc);
}
-static char *rna_LineStyle_geometry_modifier_path(PointerRNA *ptr)
+static char *rna_LineStyle_geometry_modifier_path(const PointerRNA *ptr)
{
- LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+ const LineStyleModifier *m = (LineStyleModifier *)ptr->data;
char name_esc[sizeof(m->name) * 2];
BLI_str_escape(name_esc, m->name, sizeof(name_esc));
return BLI_sprintfN("geometry_modifiers[\"%s\"]", name_esc);
diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c
index 2247a16a7a0..3dac148f7d4 100644
--- a/source/blender/makesrna/intern/rna_mask.c
+++ b/source/blender/makesrna/intern/rna_mask.c
@@ -165,9 +165,9 @@ static void rna_Mask_layer_active_index_range(
*softmax = *max;
}
-static char *rna_MaskLayer_path(PointerRNA *ptr)
+static char *rna_MaskLayer_path(const PointerRNA *ptr)
{
- MaskLayer *masklay = (MaskLayer *)ptr->data;
+ const MaskLayer *masklay = (MaskLayer *)ptr->data;
char name_esc[sizeof(masklay->name) * 2];
BLI_str_escape(name_esc, masklay->name, sizeof(name_esc));
return BLI_sprintfN("layers[\"%s\"]", name_esc);
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 15e7e12bbf8..1de144d81ef 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -362,7 +362,7 @@ static void rna_gpcolordata_uv_update(Main *bmain, Scene *scene, PointerRNA *ptr
rna_MaterialGpencil_update(bmain, scene, ptr);
}
-static char *rna_GpencilColorData_path(PointerRNA *UNUSED(ptr))
+static char *rna_GpencilColorData_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("grease_pencil");
}
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 2ba3cf1096c..da4be3cd0da 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -71,7 +71,7 @@ static const EnumPropertyItem rna_enum_mesh_remesh_mode_items[] = {
/** \name Generic Helpers
* \{ */
-static Mesh *rna_mesh(PointerRNA *ptr)
+static Mesh *rna_mesh(const PointerRNA *ptr)
{
Mesh *me = (Mesh *)ptr->owner_id;
return me;
@@ -102,7 +102,7 @@ static CustomData *rna_mesh_fdata_helper(Mesh *me)
return (me->edit_mesh) ? NULL : &me->fdata;
}
-static CustomData *rna_mesh_vdata(PointerRNA *ptr)
+static CustomData *rna_mesh_vdata(const PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return rna_mesh_vdata_helper(me);
@@ -114,13 +114,13 @@ static CustomData *rna_mesh_edata(PointerRNA *ptr)
return rna_mesh_edata_helper(me);
}
# endif
-static CustomData *rna_mesh_pdata(PointerRNA *ptr)
+static CustomData *rna_mesh_pdata(const PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return rna_mesh_pdata_helper(me);
}
-static CustomData *rna_mesh_ldata(PointerRNA *ptr)
+static CustomData *rna_mesh_ldata(const PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return rna_mesh_ldata_helper(me);
@@ -689,9 +689,9 @@ DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_layer, ldata, CD_MLOOPUV, rende
/* MeshUVLoopLayer */
-static char *rna_MeshUVLoopLayer_path(PointerRNA *ptr)
+static char *rna_MeshUVLoopLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("uv_layers[\"%s\"]", name_esc);
@@ -932,16 +932,16 @@ static int rna_Mesh_polygon_string_layers_length(PointerRNA *ptr)
/* Skin vertices */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(skin_vertice, vdata, CD_MVERT_SKIN)
-static char *rna_MeshSkinVertexLayer_path(PointerRNA *ptr)
+static char *rna_MeshSkinVertexLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("skin_vertices[\"%s\"]", name_esc);
}
-static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type);
-static char *rna_MeshSkinVertex_path(PointerRNA *ptr)
+static char *rna_VertCustomData_data_path(const PointerRNA *ptr, const char *collection, int type);
+static char *rna_MeshSkinVertex_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "skin_vertices", CD_MVERT_SKIN);
}
@@ -964,8 +964,7 @@ static int rna_MeshSkinVertexLayer_data_length(PointerRNA *ptr)
/* Vertex creases */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_crease, vdata, CD_CREASE)
-static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type);
-static char *rna_MeshVertexCreaseLayer_path(PointerRNA *ptr)
+static char *rna_MeshVertexCreaseLayer_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_creases", CD_CREASE);
}
@@ -988,15 +987,15 @@ static int rna_MeshVertexCreaseLayer_data_length(PointerRNA *ptr)
/* Paint mask */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_paint_mask, vdata, CD_PAINT_MASK)
-static char *rna_MeshPaintMaskLayer_path(PointerRNA *ptr)
+static char *rna_MeshPaintMaskLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("vertex_paint_masks[\"%s\"]", name_esc);
}
-static char *rna_MeshPaintMask_path(PointerRNA *ptr)
+static char *rna_MeshPaintMask_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_paint_masks", CD_PAINT_MASK);
}
@@ -1023,9 +1022,9 @@ DEFINE_CUSTOMDATA_LAYER_COLLECTION(face_map, pdata, CD_FACEMAP)
DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(
face_map, pdata, CD_FACEMAP, active, MeshFaceMapLayer)
-static char *rna_MeshFaceMapLayer_path(PointerRNA *ptr)
+static char *rna_MeshFaceMapLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("face_maps[\"%s\"]", name_esc);
@@ -1090,9 +1089,10 @@ static void rna_Mesh_face_map_remove(struct Mesh *me,
/* End face maps */
/* poly.vertices - this is faked loop access for convenience */
-static int rna_MeshPoly_vertices_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_MeshPoly_vertices_get_length(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- MPoly *mp = (MPoly *)ptr->data;
+ const MPoly *mp = (MPoly *)ptr->data;
/* NOTE: raw access uses dummy item, this _could_ crash,
* watch out for this, mface uses it but it can't work here. */
return (length[0] = mp->totloop);
@@ -1182,11 +1182,11 @@ static int rna_MeshLoop_index_get(PointerRNA *ptr)
/* path construction */
-static char *rna_VertexGroupElement_path(PointerRNA *ptr)
+static char *rna_VertexGroupElement_path(const PointerRNA *ptr)
{
- Mesh *me = rna_mesh(ptr); /* XXX not always! */
- MDeformWeight *dw = (MDeformWeight *)ptr->data;
- MDeformVert *dvert;
+ const Mesh *me = rna_mesh(ptr); /* XXX not always! */
+ const MDeformWeight *dw = (MDeformWeight *)ptr->data;
+ const MDeformVert *dvert;
int a, b;
for (a = 0, dvert = me->dvert; a < me->totvert; a++, dvert++) {
@@ -1200,37 +1200,37 @@ static char *rna_VertexGroupElement_path(PointerRNA *ptr)
return NULL;
}
-static char *rna_MeshPolygon_path(PointerRNA *ptr)
+static char *rna_MeshPolygon_path(const PointerRNA *ptr)
{
return BLI_sprintfN("polygons[%d]", (int)((MPoly *)ptr->data - rna_mesh(ptr)->mpoly));
}
-static char *rna_MeshLoopTriangle_path(PointerRNA *ptr)
+static char *rna_MeshLoopTriangle_path(const PointerRNA *ptr)
{
return BLI_sprintfN("loop_triangles[%d]",
(int)((MLoopTri *)ptr->data - rna_mesh(ptr)->runtime.looptris.array));
}
-static char *rna_MeshEdge_path(PointerRNA *ptr)
+static char *rna_MeshEdge_path(const PointerRNA *ptr)
{
return BLI_sprintfN("edges[%d]", (int)((MEdge *)ptr->data - rna_mesh(ptr)->medge));
}
-static char *rna_MeshLoop_path(PointerRNA *ptr)
+static char *rna_MeshLoop_path(const PointerRNA *ptr)
{
return BLI_sprintfN("loops[%d]", (int)((MLoop *)ptr->data - rna_mesh(ptr)->mloop));
}
-static char *rna_MeshVertex_path(PointerRNA *ptr)
+static char *rna_MeshVertex_path(const PointerRNA *ptr)
{
return BLI_sprintfN("vertices[%d]", (int)((MVert *)ptr->data - rna_mesh(ptr)->mvert));
}
-static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type)
+static char *rna_VertCustomData_data_path(const PointerRNA *ptr, const char *collection, int type)
{
- CustomDataLayer *cdl;
- Mesh *me = rna_mesh(ptr);
- CustomData *vdata = rna_mesh_vdata(ptr);
+ const CustomDataLayer *cdl;
+ const Mesh *me = rna_mesh(ptr);
+ const CustomData *vdata = rna_mesh_vdata(ptr);
int a, b, totvert = (me->edit_mesh) ? 0 : me->totvert;
for (cdl = vdata->layers, a = 0; a < vdata->totlayer; cdl++, a++) {
@@ -1247,11 +1247,11 @@ static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collectio
return NULL;
}
-static char *rna_PolyCustomData_data_path(PointerRNA *ptr, const char *collection, int type)
+static char *rna_PolyCustomData_data_path(const PointerRNA *ptr, const char *collection, int type)
{
- CustomDataLayer *cdl;
- Mesh *me = rna_mesh(ptr);
- CustomData *pdata = rna_mesh_pdata(ptr);
+ const CustomDataLayer *cdl;
+ const Mesh *me = rna_mesh(ptr);
+ const CustomData *pdata = rna_mesh_pdata(ptr);
int a, b, totpoly = (me->edit_mesh) ? 0 : me->totpoly;
for (cdl = pdata->layers, a = 0; a < pdata->totlayer; cdl++, a++) {
@@ -1268,11 +1268,11 @@ static char *rna_PolyCustomData_data_path(PointerRNA *ptr, const char *collectio
return NULL;
}
-static char *rna_LoopCustomData_data_path(PointerRNA *ptr, const char *collection, int type)
+static char *rna_LoopCustomData_data_path(const PointerRNA *ptr, const char *collection, int type)
{
- CustomDataLayer *cdl;
- Mesh *me = rna_mesh(ptr);
- CustomData *ldata = rna_mesh_ldata(ptr);
+ const CustomDataLayer *cdl;
+ const Mesh *me = rna_mesh(ptr);
+ const CustomData *ldata = rna_mesh_ldata(ptr);
int a, b, totloop = (me->edit_mesh) ? 0 : me->totloop;
for (cdl = ldata->layers, a = 0; a < ldata->totlayer; cdl++, a++) {
@@ -1315,58 +1315,58 @@ static int rna_Mesh_poly_normals_length(PointerRNA *ptr)
return mesh->totpoly;
}
-static char *rna_MeshUVLoop_path(PointerRNA *ptr)
+static char *rna_MeshUVLoop_path(const PointerRNA *ptr)
{
return rna_LoopCustomData_data_path(ptr, "uv_layers", CD_MLOOPUV);
}
-static char *rna_MeshLoopColorLayer_path(PointerRNA *ptr)
+static char *rna_MeshLoopColorLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("vertex_colors[\"%s\"]", name_esc);
}
-static char *rna_MeshColor_path(PointerRNA *ptr)
+static char *rna_MeshColor_path(const PointerRNA *ptr)
{
return rna_LoopCustomData_data_path(ptr, "vertex_colors", CD_PROP_BYTE_COLOR);
}
-static char *rna_MeshVertColorLayer_path(PointerRNA *ptr)
+static char *rna_MeshVertColorLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("sculpt_vertex_colors[\"%s\"]", name_esc);
}
-static char *rna_MeshVertColor_path(PointerRNA *ptr)
+static char *rna_MeshVertColor_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "sculpt_vertex_colors", CD_PROP_COLOR);
}
/**** Float Property Layer API ****/
-static char *rna_MeshVertexFloatPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshVertexFloatPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("vertex_float_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshPolygonFloatPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshPolygonFloatPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("polygon_float_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshVertexFloatProperty_path(PointerRNA *ptr)
+static char *rna_MeshVertexFloatProperty_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_layers_float", CD_PROP_FLOAT);
}
-static char *rna_MeshPolygonFloatProperty_path(PointerRNA *ptr)
+static char *rna_MeshPolygonFloatProperty_path(const PointerRNA *ptr)
{
return rna_PolyCustomData_data_path(ptr, "polygon_layers_float", CD_PROP_FLOAT);
}
@@ -1398,26 +1398,26 @@ static int rna_MeshPolygonFloatPropertyLayer_data_length(PointerRNA *ptr)
}
/**** Int Property Layer API ****/
-static char *rna_MeshVertexIntPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshVertexIntPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("vertex_int_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshPolygonIntPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshPolygonIntPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("polygon_int_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshVertexIntProperty_path(PointerRNA *ptr)
+static char *rna_MeshVertexIntProperty_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_layers_int", CD_PROP_INT32);
}
-static char *rna_MeshPolygonIntProperty_path(PointerRNA *ptr)
+static char *rna_MeshPolygonIntProperty_path(const PointerRNA *ptr)
{
return rna_PolyCustomData_data_path(ptr, "polygon_layers_int", CD_PROP_INT32);
}
@@ -1449,26 +1449,26 @@ static int rna_MeshPolygonIntPropertyLayer_data_length(PointerRNA *ptr)
}
/**** String Property Layer API ****/
-static char *rna_MeshVertexStringPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshVertexStringPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("vertex_string_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshPolygonStringPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshPolygonStringPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("polygon_string_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshVertexStringProperty_path(PointerRNA *ptr)
+static char *rna_MeshVertexStringProperty_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_layers_string", CD_PROP_STRING);
}
-static char *rna_MeshPolygonStringProperty_path(PointerRNA *ptr)
+static char *rna_MeshPolygonStringProperty_path(const PointerRNA *ptr)
{
return rna_PolyCustomData_data_path(ptr, "polygon_layers_string", CD_PROP_STRING);
}
@@ -1519,7 +1519,7 @@ void rna_MeshStringProperty_s_set(PointerRNA *ptr, const char *value)
BLI_strncpy(ms->s, value, sizeof(ms->s));
}
-static char *rna_MeshFaceMap_path(PointerRNA *ptr)
+static char *rna_MeshFaceMap_path(const PointerRNA *ptr)
{
return rna_PolyCustomData_data_path(ptr, "face_maps", CD_FACEMAP);
}
@@ -1638,7 +1638,7 @@ static PointerRNA rna_Mesh_uv_layers_new(struct Mesh *me,
PointerRNA ptr;
CustomData *ldata;
CustomDataLayer *cdl = NULL;
- int index = ED_mesh_uv_texture_add(me, name, false, do_init, reports);
+ int index = ED_mesh_uv_add(me, name, false, do_init, reports);
if (index != -1) {
ldata = rna_mesh_ldata_helper(me);
@@ -1651,7 +1651,7 @@ static PointerRNA rna_Mesh_uv_layers_new(struct Mesh *me,
static void rna_Mesh_uv_layers_remove(struct Mesh *me, ReportList *reports, CustomDataLayer *layer)
{
- if (ED_mesh_uv_texture_remove_named(me, layer->name) == false) {
+ if (ED_mesh_uv_remove_named(me, layer->name) == false) {
BKE_reportf(reports, RPT_ERROR, "Texture layer '%s' not found", layer->name);
}
}
@@ -2197,7 +2197,7 @@ static void rna_def_mloopcol(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_funcs(
prop, "rna_MeshLoopColor_color_get", "rna_MeshLoopColor_color_set", NULL);
- RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_ui_text(prop, "Color", "Color in sRGB color space");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
@@ -3212,7 +3212,9 @@ static void rna_def_mesh(BlenderRNA *brna)
NULL);
RNA_def_property_struct_type(prop, "MeshLoopColorLayer");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
- RNA_def_property_ui_text(prop, "Vertex Colors", "All vertex colors");
+ RNA_def_property_ui_text(prop,
+ "Vertex Colors",
+ "Legacy vertex color layers. Deprecated, use color attributes instead");
rna_def_loop_colors(brna, prop);
/* Sculpt Vertex colors */
@@ -3230,7 +3232,9 @@ static void rna_def_mesh(BlenderRNA *brna)
NULL);
RNA_def_property_struct_type(prop, "MeshVertColorLayer");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
- RNA_def_property_ui_text(prop, "Sculpt Vertex Colors", "All vertex colors");
+ RNA_def_property_ui_text(prop,
+ "Sculpt Vertex Colors",
+ "Sculpt vertex color layers. Deprecated, use color attributes instead");
rna_def_vert_colors(brna, prop);
/* TODO: edge customdata layers (bmesh py api can access already). */
diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c
index f160388c5d2..e6cf743e167 100644
--- a/source/blender/makesrna/intern/rna_meta.c
+++ b/source/blender/makesrna/intern/rna_meta.c
@@ -156,10 +156,10 @@ static bool rna_Meta_is_editmode_get(PointerRNA *ptr)
return (mb->editelems != NULL);
}
-static char *rna_MetaElement_path(PointerRNA *ptr)
+static char *rna_MetaElement_path(const PointerRNA *ptr)
{
- MetaBall *mb = (MetaBall *)ptr->owner_id;
- MetaElem *ml = ptr->data;
+ const MetaBall *mb = (MetaBall *)ptr->owner_id;
+ const MetaElem *ml = ptr->data;
int index = -1;
if (mb->editelems) {
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 6dd7fe53774..992e306b2bb 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -722,9 +722,9 @@ static void rna_Modifier_name_set(PointerRNA *ptr, const char *value)
BKE_animdata_fix_paths_rename_all(NULL, "modifiers", oldname, md->name);
}
-static char *rna_Modifier_path(PointerRNA *ptr)
+static char *rna_Modifier_path(const PointerRNA *ptr)
{
- ModifierData *md = ptr->data;
+ const ModifierData *md = ptr->data;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
@@ -947,10 +947,10 @@ static void rna_HookModifier_subtarget_set(PointerRNA *ptr, const char *value)
BKE_object_modifier_hook_reset(owner, hmd);
}
-static int rna_HookModifier_vertex_indices_get_length(PointerRNA *ptr,
+static int rna_HookModifier_vertex_indices_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
- HookModifierData *hmd = ptr->data;
+ const HookModifierData *hmd = ptr->data;
int indexar_num = hmd->indexar ? hmd->indexar_num : 0;
return (length[0] = indexar_num);
}
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index f8a35246581..8aa87c1bcaa 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -57,7 +57,7 @@ static void rna_NlaStrip_name_set(PointerRNA *ptr, const char *value)
}
}
-static char *rna_NlaStrip_path(PointerRNA *ptr)
+static char *rna_NlaStrip_path(const PointerRNA *ptr)
{
NlaStrip *strip = (NlaStrip *)ptr->data;
AnimData *adt = BKE_animdata_from_id(ptr->owner_id);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 9b9afadbd05..b9da7a2435e 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -1598,16 +1598,16 @@ static StructRNA *rna_Node_refine(struct PointerRNA *ptr)
}
}
-static char *rna_Node_path(PointerRNA *ptr)
+static char *rna_Node_path(const PointerRNA *ptr)
{
- bNode *node = (bNode *)ptr->data;
+ const bNode *node = (bNode *)ptr->data;
char name_esc[sizeof(node->name) * 2];
BLI_str_escape(name_esc, node->name, sizeof(name_esc));
return BLI_sprintfN("nodes[\"%s\"]", name_esc);
}
-char *rna_Node_ImageUser_path(PointerRNA *ptr)
+char *rna_Node_ImageUser_path(const PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node;
@@ -2756,7 +2756,7 @@ static StructRNA *rna_NodeSocket_refine(PointerRNA *ptr)
}
}
-static char *rna_NodeSocket_path(PointerRNA *ptr)
+static char *rna_NodeSocket_path(const PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocket *sock = (bNodeSocket *)ptr->data;
@@ -3070,10 +3070,10 @@ static StructRNA *rna_NodeSocketInterface_refine(PointerRNA *ptr)
}
}
-static char *rna_NodeSocketInterface_path(PointerRNA *ptr)
+static char *rna_NodeSocketInterface_path(const PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNodeSocket *sock = (bNodeSocket *)ptr->data;
+ const bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
+ const bNodeSocket *sock = (bNodeSocket *)ptr->data;
int socketindex;
socketindex = BLI_findindex(&ntree->inputs, sock);
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 1fb41bf792f..b192a385546 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -1320,12 +1320,17 @@ static int rna_Object_rotation_4d_editable(PointerRNA *ptr, int index)
return PROP_EDITABLE;
}
-static int rna_MaterialSlot_index(PointerRNA *ptr)
+static int rna_MaterialSlot_index(const PointerRNA *ptr)
{
/* There is an offset, so that `ptr->data` is not null and unique across IDs. */
return (uintptr_t)ptr->data - (uintptr_t)ptr->owner_id;
}
+static int rna_MaterialSlot_index_get(PointerRNA *ptr)
+{
+ return rna_MaterialSlot_index(ptr);
+}
+
static int rna_MaterialSlot_material_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Object *ob = (Object *)ptr->owner_id;
@@ -1451,7 +1456,7 @@ static void rna_MaterialSlot_update(Main *bmain, Scene *scene, PointerRNA *ptr)
DEG_relations_tag_update(bmain);
}
-static char *rna_MaterialSlot_path(PointerRNA *ptr)
+static char *rna_MaterialSlot_path(const PointerRNA *ptr)
{
int index = rna_MaterialSlot_index(ptr);
return BLI_sprintfN("material_slots[%d]", index);
@@ -1504,7 +1509,7 @@ static PointerRNA rna_Object_display_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_ObjectDisplay, ptr->data);
}
-static char *rna_ObjectDisplay_path(PointerRNA *UNUSED(ptr))
+static char *rna_ObjectDisplay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("display");
}
@@ -1829,6 +1834,24 @@ bool rna_Object_modifiers_override_apply(Main *bmain,
ModifierData *mod_dst = ED_object_modifier_add(
NULL, bmain, NULL, ob_dst, mod_src->name, mod_src->type);
+ if (mod_dst == NULL) {
+ /* This can happen e.g. when a modifier type is tagged as `eModifierTypeFlag_Single`, and that
+ * modifier has somehow been added already by another code path (e.g.
+ * `rna_CollisionSettings_dependency_update` does add the `eModifierType_Collision` singleton
+ * modifier).
+ *
+ * Try to handle this by finding already existing one here. */
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)mod_src->type);
+ if (mti->flags & eModifierTypeFlag_Single) {
+ mod_dst = BKE_modifiers_findby_type(ob_dst, (ModifierType)mod_src->type);
+ }
+
+ if (mod_dst == NULL) {
+ BLI_assert(mod_src != NULL);
+ return false;
+ }
+ }
+
/* XXX Current handling of 'copy' from particle-system modifier is *very* bad (it keeps same psys
* pointer as source, then calling code copies psys of object separately and do some magic
* remapping of pointers...), unfortunately several pieces of code in Object editing area rely on
@@ -2466,7 +2489,7 @@ static void rna_def_material_slot(BlenderRNA *brna)
prop = RNA_def_property(srna, "slot_index", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_int_funcs(prop, "rna_MaterialSlot_index", NULL, NULL);
+ RNA_def_property_int_funcs(prop, "rna_MaterialSlot_index_get", NULL, NULL);
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index addc8ac0c6c..2ed539aa511 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -130,7 +130,7 @@ static bool rna_Cache_get_valid_owner_ID(PointerRNA *ptr, Object **ob, Scene **s
return (*ob != NULL || *scene != NULL);
}
-static char *rna_PointCache_path(PointerRNA *ptr)
+static char *rna_PointCache_path(const PointerRNA *ptr)
{
ModifierData *md;
Object *ob = (Object *)ptr->owner_id;
@@ -443,7 +443,7 @@ int rna_Cache_info_length(PointerRNA *ptr)
return (int)strlen(cache->info);
}
-static char *rna_CollisionSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_CollisionSettings_path(const PointerRNA *UNUSED(ptr))
{
/* both methods work ok, but return the shorter path */
# if 0
@@ -619,17 +619,17 @@ static void rna_SoftBodySettings_spring_vgroup_set(PointerRNA *ptr, const char *
rna_object_vgroup_name_set(ptr, value, sb->namedVG_Spring_K, sizeof(sb->namedVG_Spring_K));
}
-static char *rna_SoftBodySettings_path(PointerRNA *ptr)
+static char *rna_SoftBodySettings_path(const PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- ModifierData *md = (ModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Softbody);
+ const Object *ob = (Object *)ptr->owner_id;
+ const ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Softbody);
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc);
}
-static int particle_id_check(PointerRNA *ptr)
+static int particle_id_check(const PointerRNA *ptr)
{
ID *id = ptr->owner_id;
@@ -731,7 +731,7 @@ static void rna_FieldSettings_dependency_update(Main *bmain, Scene *scene, Point
}
}
-static char *rna_FieldSettings_path(PointerRNA *ptr)
+static char *rna_FieldSettings_path(const PointerRNA *ptr)
{
PartDeflect *pd = (PartDeflect *)ptr->data;
@@ -787,7 +787,7 @@ static void rna_EffectorWeight_dependency_update(Main *bmain,
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
-static char *rna_EffectorWeight_path(PointerRNA *ptr)
+static char *rna_EffectorWeight_path(const PointerRNA *ptr)
{
EffectorWeights *ew = (EffectorWeights *)ptr->data;
/* Check through all possible places the settings can be to find the right one */
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 8a024fdcfc2..a67b0f7c8e6 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -1208,19 +1208,19 @@ static int rna_ParticleTarget_name_length(PointerRNA *ptr)
return strlen(tstr);
}
-static int particle_id_check(PointerRNA *ptr)
+static int particle_id_check(const PointerRNA *ptr)
{
- ID *id = ptr->owner_id;
+ const ID *id = ptr->owner_id;
return (GS(id->name) == ID_PA);
}
-static char *rna_SPHFluidSettings_path(PointerRNA *ptr)
+static char *rna_SPHFluidSettings_path(const PointerRNA *ptr)
{
- SPHFluidSettings *fluid = (SPHFluidSettings *)ptr->data;
+ const SPHFluidSettings *fluid = (SPHFluidSettings *)ptr->data;
if (particle_id_check(ptr)) {
- ParticleSettings *part = (ParticleSettings *)ptr->owner_id;
+ const ParticleSettings *part = (ParticleSettings *)ptr->owner_id;
if (part->fluid == fluid) {
return BLI_strdup("fluid");
@@ -1463,9 +1463,9 @@ static void psys_vg_name_set__internal(PointerRNA *ptr, const char *value, int i
}
}
-static char *rna_ParticleSystem_path(PointerRNA *ptr)
+static char *rna_ParticleSystem_path(const PointerRNA *ptr)
{
- ParticleSystem *psys = (ParticleSystem *)ptr->data;
+ const ParticleSystem *psys = (ParticleSystem *)ptr->data;
char name_esc[sizeof(psys->name) * 2];
BLI_str_escape(name_esc, psys->name, sizeof(name_esc));
diff --git a/source/blender/makesrna/intern/rna_pointcloud.c b/source/blender/makesrna/intern/rna_pointcloud.c
index 075d660ba2b..4c5dcd5a587 100644
--- a/source/blender/makesrna/intern/rna_pointcloud.c
+++ b/source/blender/makesrna/intern/rna_pointcloud.c
@@ -27,18 +27,23 @@
# include "WM_api.h"
# include "WM_types.h"
-static PointCloud *rna_pointcloud(PointerRNA *ptr)
+static PointCloud *rna_pointcloud(const PointerRNA *ptr)
{
return (PointCloud *)ptr->owner_id;
}
-static int rna_Point_index_get(PointerRNA *ptr)
+static int rna_Point_index_get_const(const PointerRNA *ptr)
{
const PointCloud *pointcloud = rna_pointcloud(ptr);
const float(*co)[3] = ptr->data;
return (int)(co - pointcloud->co);
}
+static int rna_Point_index_get(PointerRNA *ptr)
+{
+ return rna_Point_index_get_const(ptr);
+}
+
static void rna_Point_location_get(PointerRNA *ptr, float value[3])
{
copy_v3_v3(value, (const float *)ptr->data);
@@ -69,9 +74,9 @@ static void rna_Point_radius_set(PointerRNA *ptr, float value)
pointcloud->radius[co - pointcloud->co] = value;
}
-static char *rna_Point_path(PointerRNA *ptr)
+static char *rna_Point_path(const PointerRNA *ptr)
{
- return BLI_sprintfN("points[%d]", rna_Point_index_get(ptr));
+ return BLI_sprintfN("points[%d]", rna_Point_index_get_const(ptr));
}
static void rna_PointCloud_update_data(struct Main *UNUSED(bmain),
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index a80e9573657..4108baca2fa 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -108,14 +108,14 @@ static void rna_Pose_IK_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
BIK_clear_data(ob->pose);
}
-static char *rna_Pose_path(PointerRNA *UNUSED(ptr))
+static char *rna_Pose_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("pose");
}
-static char *rna_PoseBone_path(PointerRNA *ptr)
+static char *rna_PoseBone_path(const PointerRNA *ptr)
{
- bPoseChannel *pchan = ptr->data;
+ const bPoseChannel *pchan = ptr->data;
char name_esc[sizeof(pchan->name) * 2];
BLI_str_escape(name_esc, pchan->name, sizeof(name_esc));
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 997c110134d..11a7be69f68 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -483,9 +483,10 @@ static void rna_RenderLayer_passes_begin(CollectionPropertyIterator *iter, Point
rna_iterator_listbase_begin(iter, &rl->passes, NULL);
}
-static int rna_RenderPass_rect_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_RenderPass_rect_get_length(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- RenderPass *rpass = (RenderPass *)ptr->data;
+ const RenderPass *rpass = (RenderPass *)ptr->data;
length[0] = rpass->rectx * rpass->recty;
length[1] = rpass->channels;
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index c1012f67c5a..0c1fd8cab3c 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -148,7 +148,7 @@ static void rna_RigidBodyWorld_reset(Main *UNUSED(bmain), Scene *UNUSED(scene),
BKE_rigidbody_cache_reset(rbw);
}
-static char *rna_RigidBodyWorld_path(PointerRNA *UNUSED(ptr))
+static char *rna_RigidBodyWorld_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("rigidbody_world");
}
@@ -240,7 +240,7 @@ static void rna_RigidBodyOb_mesh_source_update(Main *bmain, Scene *scene, Pointe
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
}
-static char *rna_RigidBodyOb_path(PointerRNA *UNUSED(ptr))
+static char *rna_RigidBodyOb_path(const PointerRNA *UNUSED(ptr))
{
/* NOTE: this hardcoded path should work as long as only Objects have this */
return BLI_strdup("rigid_body");
@@ -432,7 +432,7 @@ static void rna_RigidBodyOb_angular_damping_set(PointerRNA *ptr, float value)
# endif
}
-static char *rna_RigidBodyCon_path(PointerRNA *UNUSED(ptr))
+static char *rna_RigidBodyCon_path(const PointerRNA *UNUSED(ptr))
{
/* NOTE: this hardcoded path should work as long as only Objects have this */
return BLI_strdup("rigid_body_constraint");
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index d540b51a585..ae67de9228c 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -721,7 +721,7 @@ static int rna_IntProperty_default_get(PointerRNA *ptr)
return ((IntPropertyRNA *)prop)->defaultvalue;
}
/* int/float/bool */
-static int rna_NumberProperty_default_array_get_length(PointerRNA *ptr,
+static int rna_NumberProperty_default_array_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 63a68d04a97..0e423b71f1d 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -1100,12 +1100,12 @@ static void rna_Scene_all_keyingsets_next(CollectionPropertyIterator *iter)
iter->valid = (internal->link != NULL);
}
-static char *rna_SceneEEVEE_path(PointerRNA *UNUSED(ptr))
+static char *rna_SceneEEVEE_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("eevee");
}
-static char *rna_SceneGpencil_path(PointerRNA *UNUSED(ptr))
+static char *rna_SceneGpencil_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("grease_pencil_settings");
}
@@ -1129,17 +1129,17 @@ static void rna_RenderSettings_stereoViews_begin(CollectionPropertyIterator *ite
rna_iterator_listbase_begin(iter, &rd->views, rna_RenderSettings_stereoViews_skip);
}
-static char *rna_RenderSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_RenderSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("render");
}
-static char *rna_BakeSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_BakeSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("render.bake");
}
-static char *rna_ImageFormatSettings_path(PointerRNA *ptr)
+static char *rna_ImageFormatSettings_path(const PointerRNA *ptr)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
ID *id = ptr->owner_id;
@@ -1787,10 +1787,11 @@ void rna_ViewLayer_pass_update(Main *bmain, Scene *activescene, PointerRNA *ptr)
rna_Scene_glsl_update(bmain, activescene, ptr);
}
-static char *rna_ViewLayerEEVEE_path(PointerRNA *ptr)
+static char *rna_ViewLayerEEVEE_path(const PointerRNA *ptr)
{
- ViewLayerEEVEE *view_layer_eevee = (ViewLayerEEVEE *)ptr->data;
- ViewLayer *view_layer = (ViewLayer *)((uint8_t *)view_layer_eevee - offsetof(ViewLayer, eevee));
+ const ViewLayerEEVEE *view_layer_eevee = (ViewLayerEEVEE *)ptr->data;
+ const ViewLayer *view_layer = (ViewLayer *)((uint8_t *)view_layer_eevee -
+ offsetof(ViewLayer, eevee));
char rna_path[sizeof(view_layer->name) * 3];
const size_t view_layer_path_len = rna_ViewLayer_path_buffer_get(
@@ -1801,9 +1802,9 @@ static char *rna_ViewLayerEEVEE_path(PointerRNA *ptr)
return BLI_strdup(rna_path);
}
-static char *rna_SceneRenderView_path(PointerRNA *ptr)
+static char *rna_SceneRenderView_path(const PointerRNA *ptr)
{
- SceneRenderView *srv = (SceneRenderView *)ptr->data;
+ const SceneRenderView *srv = (SceneRenderView *)ptr->data;
char srv_name_esc[sizeof(srv->name) * 2];
BLI_str_escape(srv_name_esc, srv->name, sizeof(srv_name_esc));
return BLI_sprintfN("render.views[\"%s\"]", srv_name_esc);
@@ -2071,10 +2072,10 @@ static void rna_View3DCursor_matrix_set(PointerRNA *ptr, const float *values)
BKE_scene_cursor_from_mat4(cursor, unit_mat, false);
}
-static char *rna_TransformOrientationSlot_path(PointerRNA *ptr)
+static char *rna_TransformOrientationSlot_path(const PointerRNA *ptr)
{
- Scene *scene = (Scene *)ptr->owner_id;
- TransformOrientationSlot *orientation_slot = ptr->data;
+ const Scene *scene = (Scene *)ptr->owner_id;
+ const TransformOrientationSlot *orientation_slot = ptr->data;
if (!ELEM(NULL, scene, orientation_slot)) {
for (int i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) {
@@ -2089,7 +2090,7 @@ static char *rna_TransformOrientationSlot_path(PointerRNA *ptr)
return BLI_strdup("transform_orientation_slots[0]");
}
-static char *rna_View3DCursor_path(PointerRNA *UNUSED(ptr))
+static char *rna_View3DCursor_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("cursor");
}
@@ -2188,17 +2189,17 @@ static void rna_UnifiedPaintSettings_radius_update(bContext *C, PointerRNA *ptr)
rna_UnifiedPaintSettings_update(C, ptr);
}
-static char *rna_UnifiedPaintSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_UnifiedPaintSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.unified_paint_settings");
}
-static char *rna_CurvePaintSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_CurvePaintSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.curve_paint_settings");
}
-static char *rna_SequencerToolSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_SequencerToolSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.sequencer_tool_settings");
}
@@ -2222,7 +2223,7 @@ static void rna_EditMesh_update(bContext *C, PointerRNA *UNUSED(ptr))
}
}
-static char *rna_MeshStatVis_path(PointerRNA *UNUSED(ptr))
+static char *rna_MeshStatVis_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.statvis");
}
@@ -2260,7 +2261,7 @@ static void rna_SceneSequencer_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
SEQ_cache_cleanup((Scene *)ptr->owner_id);
}
-static char *rna_ToolSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ToolSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings");
}
@@ -2701,12 +2702,12 @@ static void rna_UnitSettings_system_update(Main *UNUSED(bmain),
}
}
-static char *rna_UnitSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_UnitSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("unit_settings");
}
-static char *rna_FFmpegSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_FFmpegSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("render.ffmpeg");
}
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 017e8bde7a1..ab5e4c2f0d5 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -259,7 +259,7 @@ static bool rna_ParticleEdit_hair_get(PointerRNA *ptr)
return 0;
}
-static char *rna_ParticleEdit_path(PointerRNA *UNUSED(ptr))
+static char *rna_ParticleEdit_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.particle_edit");
}
@@ -403,15 +403,15 @@ static void rna_Sculpt_ShowMask_update(bContext *C, PointerRNA *UNUSED(ptr))
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, object);
}
-static char *rna_Sculpt_path(PointerRNA *UNUSED(ptr))
+static char *rna_Sculpt_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.sculpt");
}
-static char *rna_VertexPaint_path(PointerRNA *ptr)
+static char *rna_VertexPaint_path(const PointerRNA *ptr)
{
- Scene *scene = (Scene *)ptr->owner_id;
- ToolSettings *ts = scene->toolsettings;
+ const Scene *scene = (Scene *)ptr->owner_id;
+ const ToolSettings *ts = scene->toolsettings;
if (ptr->data == ts->vpaint) {
return BLI_strdup("tool_settings.vertex_paint");
}
@@ -420,47 +420,47 @@ static char *rna_VertexPaint_path(PointerRNA *ptr)
}
}
-static char *rna_ImagePaintSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ImagePaintSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.image_paint");
}
-static char *rna_PaintModeSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_PaintModeSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.paint_mode");
}
-static char *rna_UvSculpt_path(PointerRNA *UNUSED(ptr))
+static char *rna_UvSculpt_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.uv_sculpt");
}
-static char *rna_CurvesSculpt_path(PointerRNA *UNUSED(ptr))
+static char *rna_CurvesSculpt_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.curves_sculpt");
}
-static char *rna_GpPaint_path(PointerRNA *UNUSED(ptr))
+static char *rna_GpPaint_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_paint");
}
-static char *rna_GpVertexPaint_path(PointerRNA *UNUSED(ptr))
+static char *rna_GpVertexPaint_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_vertex_paint");
}
-static char *rna_GpSculptPaint_path(PointerRNA *UNUSED(ptr))
+static char *rna_GpSculptPaint_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_sculpt_paint");
}
-static char *rna_GpWeightPaint_path(PointerRNA *UNUSED(ptr))
+static char *rna_GpWeightPaint_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_weight_paint");
}
-static char *rna_ParticleBrush_path(PointerRNA *UNUSED(ptr))
+static char *rna_ParticleBrush_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.particle_edit.brush");
}
@@ -578,12 +578,12 @@ static bool rna_ImaPaint_detect_data(ImagePaintSettings *imapaint)
return imapaint->missing_data == 0;
}
-static char *rna_GPencilSculptSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_GPencilSculptSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_sculpt");
}
-static char *rna_GPencilSculptGuide_path(PointerRNA *UNUSED(ptr))
+static char *rna_GPencilSculptGuide_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_sculpt.guide");
}
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 1e90d6f75b5..5d583d3edcb 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -504,7 +504,7 @@ static Sequence *sequence_get_by_transform(Editing *ed, StripTransform *transfor
return data.seq;
}
-static char *rna_SequenceTransform_path(PointerRNA *ptr)
+static char *rna_SequenceTransform_path(const PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
Editing *ed = SEQ_editing_get(scene);
@@ -556,7 +556,7 @@ static Sequence *sequence_get_by_crop(Editing *ed, StripCrop *crop)
return data.seq;
}
-static char *rna_SequenceCrop_path(PointerRNA *ptr)
+static char *rna_SequenceCrop_path(const PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
Editing *ed = SEQ_editing_get(scene);
@@ -700,9 +700,9 @@ static StructRNA *rna_Sequence_refine(struct PointerRNA *ptr)
}
}
-static char *rna_Sequence_path(PointerRNA *ptr)
+static char *rna_Sequence_path(const PointerRNA *ptr)
{
- Sequence *seq = (Sequence *)ptr->data;
+ const Sequence *seq = (Sequence *)ptr->data;
/* sequencer data comes from scene...
* TODO: would be nice to make SequenceEditor data a data-block of its own (for shorter paths)
@@ -1034,7 +1034,7 @@ static Sequence *sequence_get_by_colorbalance(Editing *ed,
return data.seq;
}
-static char *rna_SequenceColorBalance_path(PointerRNA *ptr)
+static char *rna_SequenceColorBalance_path(const PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
SequenceModifierData *smd;
@@ -1178,7 +1178,7 @@ static StructRNA *rna_SequenceModifier_refine(struct PointerRNA *ptr)
}
}
-static char *rna_SequenceModifier_path(PointerRNA *ptr)
+static char *rna_SequenceModifier_path(const PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
Editing *ed = SEQ_editing_get(scene);
@@ -1396,7 +1396,7 @@ static void rna_SequenceTimelineChannel_name_set(PointerRNA *ptr, const char *va
sizeof(channel->name));
}
-static char *rna_SeqTimelineChannel_path(PointerRNA *ptr)
+static char *rna_SeqTimelineChannel_path(const PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
Editing *ed = SEQ_editing_get(scene);
diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c
index cefa445740d..0a656222fd5 100644
--- a/source/blender/makesrna/intern/rna_shader_fx.c
+++ b/source/blender/makesrna/intern/rna_shader_fx.c
@@ -142,9 +142,9 @@ static void rna_ShaderFx_name_set(PointerRNA *ptr, const char *value)
BKE_animdata_fix_paths_rename_all(NULL, "shader_effects", oldname, gmd->name);
}
-static char *rna_ShaderFx_path(PointerRNA *ptr)
+static char *rna_ShaderFx_path(const PointerRNA *ptr)
{
- ShaderFxData *gmd = ptr->data;
+ const ShaderFxData *gmd = ptr->data;
char name_esc[sizeof(gmd->name) * 2];
BLI_str_escape(name_esc, gmd->name, sizeof(name_esc));
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index de03e971b8b..4b5802d70ab 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -1586,7 +1586,7 @@ static int rna_SpaceView3D_icon_from_show_object_viewport_get(PointerRNA *ptr)
&v3d->object_type_exclude_select);
}
-static char *rna_View3DShading_path(PointerRNA *UNUSED(ptr))
+static char *rna_View3DShading_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("shading");
}
@@ -1596,7 +1596,7 @@ static PointerRNA rna_SpaceView3D_overlay_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_View3DOverlay, ptr->data);
}
-static char *rna_View3DOverlay_path(PointerRNA *UNUSED(ptr))
+static char *rna_View3DOverlay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("overlay");
}
@@ -1608,12 +1608,12 @@ static PointerRNA rna_SpaceImage_overlay_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_SpaceImageOverlay, ptr->data);
}
-static char *rna_SpaceImageOverlay_path(PointerRNA *UNUSED(ptr))
+static char *rna_SpaceImageOverlay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("overlay");
}
-static char *rna_SpaceUVEditor_path(PointerRNA *UNUSED(ptr))
+static char *rna_SpaceUVEditor_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("uv_editor");
}
@@ -2045,7 +2045,7 @@ static void rna_SpaceProperties_context_update(Main *UNUSED(bmain),
}
}
-static int rna_SpaceProperties_tab_search_results_getlength(PointerRNA *ptr,
+static int rna_SpaceProperties_tab_search_results_getlength(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
SpaceProperties *sbuts = ptr->data;
@@ -2447,12 +2447,12 @@ static void rna_Sequencer_view_type_update(Main *UNUSED(bmain),
ED_area_tag_refresh(area);
}
-static char *rna_SpaceSequencerPreviewOverlay_path(PointerRNA *UNUSED(ptr))
+static char *rna_SpaceSequencerPreviewOverlay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("preview_overlay");
}
-static char *rna_SpaceSequencerTimelineOverlay_path(PointerRNA *UNUSED(ptr))
+static char *rna_SpaceSequencerTimelineOverlay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("timeline_overlay");
}
@@ -2463,7 +2463,7 @@ static PointerRNA rna_SpaceNode_overlay_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_SpaceNodeOverlay, ptr->data);
}
-static char *rna_SpaceNodeOverlay_path(PointerRNA *UNUSED(ptr))
+static char *rna_SpaceNodeOverlay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("overlay");
}
@@ -2656,7 +2656,7 @@ static void rna_SpaceClipEditor_view_type_update(Main *UNUSED(bmain),
/* File browser. */
-static char *rna_FileSelectParams_path(PointerRNA *UNUSED(ptr))
+static char *rna_FileSelectParams_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("params");
}
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 6f7ee966723..eff7c0ca136 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -291,7 +291,7 @@ void rna_TextureSlot_update(bContext *C, PointerRNA *ptr)
}
}
-char *rna_TextureSlot_path(PointerRNA *ptr)
+char *rna_TextureSlot_path(const PointerRNA *ptr)
{
MTex *mtex = ptr->data;
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index aac84f1867e..b9acd57430b 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -41,7 +41,7 @@
# include "WM_api.h"
-static char *rna_tracking_path(PointerRNA *UNUSED(ptr))
+static char *rna_tracking_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tracking");
}
@@ -72,7 +72,7 @@ static void rna_tracking_defaultSettings_searchUpdate(Main *UNUSED(bmain),
}
}
-static char *rna_trackingTrack_path(PointerRNA *ptr)
+static char *rna_trackingTrack_path(const PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->owner_id;
MovieTrackingTrack *track = (MovieTrackingTrack *)ptr->data;
@@ -255,7 +255,7 @@ static void rna_trackingPlaneMarker_frame_set(PointerRNA *ptr, int value)
}
}
-static char *rna_trackingPlaneTrack_path(PointerRNA *ptr)
+static char *rna_trackingPlaneTrack_path(const PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->owner_id;
MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data;
@@ -289,7 +289,7 @@ static void rna_trackingPlaneTrack_name_set(PointerRNA *ptr, const char *value)
}
}
-static char *rna_trackingCamera_path(PointerRNA *UNUSED(ptr))
+static char *rna_trackingCamera_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tracking.camera");
}
@@ -321,7 +321,7 @@ static void rna_trackingCamera_focal_mm_set(PointerRNA *ptr, float value)
}
}
-static char *rna_trackingStabilization_path(PointerRNA *UNUSED(ptr))
+static char *rna_trackingStabilization_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tracking.stabilization");
}
diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c
index 12cb35b239d..6d4ea18fc38 100644
--- a/source/blender/makesrna/intern/rna_volume.c
+++ b/source/blender/makesrna/intern/rna_volume.c
@@ -46,12 +46,12 @@ const EnumPropertyItem rna_enum_volume_grid_data_type_items[] = {
# include "WM_api.h"
# include "WM_types.h"
-static char *rna_VolumeRender_path(PointerRNA *UNUSED(ptr))
+static char *rna_VolumeRender_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("render");
}
-static char *rna_VolumeDisplay_path(PointerRNA *UNUSED(ptr))
+static char *rna_VolumeDisplay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("display");
}
@@ -485,6 +485,21 @@ static void rna_def_volume_render(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "VolumeRender");
RNA_def_struct_path_func(srna, "rna_VolumeRender_path");
+ static const EnumPropertyItem precision_items[] = {
+ {VOLUME_PRECISION_FULL, "FULL", 0, "Full", "Full float (Use 32 bit for all data)"},
+ {VOLUME_PRECISION_HALF, "HALF", 0, "Half", "Half float (Use 16 bit for all data)"},
+ {VOLUME_PRECISION_VARIABLE, "VARIABLE", 0, "Variable", "Use variable bit quantization"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ prop = RNA_def_property(srna, "precision", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, precision_items);
+ RNA_def_property_ui_text(prop,
+ "Precision",
+ "Specify volume data precision. Lower values reduce memory consumption "
+ "at the cost of detail");
+ RNA_def_property_update(prop, 0, "rna_Volume_update_display");
+
static const EnumPropertyItem space_items[] = {
{VOLUME_SPACE_OBJECT,
"OBJECT",
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index ac1b7e53a9b..c80d0e2da39 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -2599,6 +2599,9 @@ static void rna_def_keyconfig(BlenderRNA *brna)
"rna_wmKeyMapItem_idname_get",
"rna_wmKeyMapItem_idname_length",
"rna_wmKeyMapItem_idname_set");
+ RNA_def_property_string_search_func(prop,
+ "WM_operatortype_idname_visit_for_search",
+ PROP_STRING_SEARCH_SORT | PROP_STRING_SEARCH_SUGGESTION);
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index 4fbf5192222..2917861f084 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -89,8 +89,9 @@ class GFieldValueLog : public ValueLog {
struct GeometryAttributeInfo {
std::string name;
- AttributeDomain domain;
- CustomDataType data_type;
+ /** Can be empty when #name does not actually exist on a geometry yet. */
+ std::optional<AttributeDomain> domain;
+ std::optional<CustomDataType> data_type;
};
/** Contains information about a geometry set. In most cases this does not store the entire
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 7dd732e7fad..e0a4d241b3b 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -44,7 +44,7 @@ DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZ
DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
DefNode(ShaderNode, SH_NODE_SEPRGB_LEGACY, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" )
DefNode(ShaderNode, SH_NODE_COMBRGB_LEGACY, 0, "COMBRGB", CombineRGB, "Combine RGB", "" )
-DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation", "" )
+DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue Saturation Value", "" )
DefNode(ShaderNode, SH_NODE_OUTPUT_MATERIAL, def_sh_output, "OUTPUT_MATERIAL", OutputMaterial, "Material Output", "" )
DefNode(ShaderNode, SH_NODE_EEVEE_SPECULAR, 0, "EEVEE_SPECULAR", EeveeSpecular, "Specular BSDF", "" )
@@ -216,7 +216,7 @@ DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOIS
DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" )
DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIALIASING", AntiAliasing, "Anti-Aliasing", "" )
DefNode(CompositorNode, CMP_NODE_POSTERIZE, 0, "POSTERIZE", Posterize, "Posterize", "" )
-DefNode(CompositorNode, CMP_NODE_CONVERT_COLOR_SPACE,def_cmp_convert_color_space, "CONVERT_COLORSPACE", ConvertColorSpace, "Color Space","" )
+DefNode(CompositorNode, CMP_NODE_CONVERT_COLOR_SPACE,def_cmp_convert_color_space, "CONVERT_COLORSPACE", ConvertColorSpace, "Color Space", "" )
DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" )
DefNode(CompositorNode, CMP_NODE_COMBINE_XYZ, 0, "COMBINE_XYZ", CombineXYZ, "Combine XYZ", "" )
DefNode(CompositorNode, CMP_NODE_SEPARATE_XYZ, 0, "SEPARATE_XYZ", SeparateXYZ, "Separate XYZ", "" )
@@ -234,7 +234,7 @@ DefNode(TextureNode, TEX_NODE_VALTORGB, def_colorramp, "VALTOR
DefNode(TextureNode, TEX_NODE_IMAGE, def_tex_image, "IMAGE", Image, "Image", "" )
DefNode(TextureNode, TEX_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", CurveRGB, "RGB Curves", "" )
DefNode(TextureNode, TEX_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
-DefNode(TextureNode, TEX_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation", "" )
+DefNode(TextureNode, TEX_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue Saturation Value", "" )
DefNode(TextureNode, TEX_NODE_CURVE_TIME, def_time, "CURVE_TIME", CurveTime, "Curve Time", "" )
DefNode(TextureNode, TEX_NODE_ROTATE, 0, "ROTATE", Rotate, "Rotate", "" )
DefNode(TextureNode, TEX_NODE_VIEWER, 0, "VIEWER", Viewer, "Viewer", "" )
diff --git a/source/blender/nodes/composite/nodes/node_composite_map_range.cc b/source/blender/nodes/composite/nodes/node_composite_map_range.cc
index 9b88e99060c..e52c6d096b9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_map_range.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_map_range.cc
@@ -18,9 +18,9 @@ static void cmp_node_map_range_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
b.add_input<decl::Float>(N_("From Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>(N_("From Max")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("From Max")).default_value(1.0f).min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>(N_("To Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>(N_("To Max")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("To Max")).default_value(1.0f).min(-10000.0f).max(10000.0f);
b.add_output<decl::Float>(N_("Value"));
}
diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc
index 7bc9d2d79e8..e3f13dc7d6b 100644
--- a/source/blender/nodes/function/nodes/node_fn_compare.cc
+++ b/source/blender/nodes/function/nodes/node_fn_compare.cc
@@ -487,7 +487,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
"Not Equal - Element-wise",
[](float3 a, float3 b, float epsilon) {
- return abs(a.x - b.x) > epsilon && abs(a.y - b.y) > epsilon &&
+ return abs(a.x - b.x) > epsilon || abs(a.y - b.y) > epsilon ||
abs(a.z - b.z) > epsilon;
},
exec_preset_first_two};
@@ -522,7 +522,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{
"Not Equal",
[](ColorGeometry4f a, ColorGeometry4f b, float epsilon) {
- return abs(a.r - b.r) > epsilon && abs(a.g - b.g) > epsilon &&
+ return abs(a.r - b.r) > epsilon || abs(a.g - b.g) > epsilon ||
abs(a.b - b.b) > epsilon;
},
exec_preset_first_two};
diff --git a/source/blender/nodes/function/nodes/node_fn_replace_string.cc b/source/blender/nodes/function/nodes/node_fn_replace_string.cc
index 6abcc79cf29..4b493438a45 100644
--- a/source/blender/nodes/function/nodes/node_fn_replace_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_replace_string.cc
@@ -15,19 +15,17 @@ static void fn_node_replace_string_declare(NodeDeclarationBuilder &b)
b.add_output<decl::String>(N_("String"));
}
-static std::string replace_all(std::string str, const std::string &from, const std::string &to)
+static std::string replace_all(const StringRefNull str,
+ const StringRefNull from,
+ const StringRefNull to)
{
- if (from.length() <= 0) {
+ if (from.is_empty()) {
return str;
}
- const size_t step = to.length() > 0 ? to.length() : 1;
-
- size_t offset = 0;
- while ((offset = str.find(from, offset)) != std::string::npos) {
- str.replace(offset, from.length(), to);
- offset += step;
- }
- return str;
+ char *new_str_ptr = BLI_str_replaceN(str.c_str(), from.c_str(), to.c_str());
+ std::string new_str{new_str_ptr};
+ MEM_freeN(new_str_ptr);
+ return new_str;
}
static void fn_node_replace_string_build_multi_function(NodeMultiFunctionBuilder &builder)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
index 18cf005c965..16967d32673 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -126,30 +126,66 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
output_attribute.save();
}
+static StringRefNull identifier_suffix(CustomDataType data_type)
+{
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ return "_001";
+ case CD_PROP_INT32:
+ return "_004";
+ case CD_PROP_COLOR:
+ return "_002";
+ case CD_PROP_BOOL:
+ return "_003";
+ case CD_PROP_FLOAT3:
+ return "";
+ default:
+ BLI_assert_unreachable();
+ return "";
+ }
+}
+
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ if (!params.output_is_required("Geometry")) {
+ params.error_message_add(
+ NodeWarningType::Info,
+ TIP_("The attribute output can not be used without the geometry output"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
const NodeGeometryAttributeCapture &storage = node_storage(params.node());
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+ const std::string output_identifier = "Attribute" + identifier_suffix(data_type);
+
+ if (!params.output_is_required(output_identifier)) {
+ params.set_output("Geometry", geometry_set);
+ return;
+ }
+
+ const std::string input_identifier = "Value" + identifier_suffix(data_type);
GField field;
+
switch (data_type) {
case CD_PROP_FLOAT:
- field = params.get_input<Field<float>>("Value_001");
+ field = params.get_input<Field<float>>(input_identifier);
break;
case CD_PROP_FLOAT3:
- field = params.get_input<Field<float3>>("Value");
+ field = params.get_input<Field<float3>>(input_identifier);
break;
case CD_PROP_COLOR:
- field = params.get_input<Field<ColorGeometry4f>>("Value_002");
+ field = params.get_input<Field<ColorGeometry4f>>(input_identifier);
break;
case CD_PROP_BOOL:
- field = params.get_input<Field<bool>>("Value_003");
+ field = params.get_input<Field<bool>>(input_identifier);
break;
case CD_PROP_INT32:
- field = params.get_input<Field<int>>("Value_004");
+ field = params.get_input<Field<int>>(input_identifier);
break;
default:
break;
@@ -185,23 +221,23 @@ static void node_geo_exec(GeoNodeExecParams params)
switch (data_type) {
case CD_PROP_FLOAT: {
- params.set_output("Attribute_001", Field<float>(output_field));
+ params.set_output(output_identifier, Field<float>(output_field));
break;
}
case CD_PROP_FLOAT3: {
- params.set_output("Attribute", Field<float3>(output_field));
+ params.set_output(output_identifier, Field<float3>(output_field));
break;
}
case CD_PROP_COLOR: {
- params.set_output("Attribute_002", Field<ColorGeometry4f>(output_field));
+ params.set_output(output_identifier, Field<ColorGeometry4f>(output_field));
break;
}
case CD_PROP_BOOL: {
- params.set_output("Attribute_003", Field<bool>(output_field));
+ params.set_output(output_identifier, Field<bool>(output_field));
break;
}
case CD_PROP_INT32: {
- params.set_output("Attribute_004", Field<int>(output_field));
+ params.set_output(output_identifier, Field<int>(output_field));
break;
}
default:
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index d9cc8bcf023..78a132064ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -73,7 +73,7 @@ static void node_geo_exec(GeoNodeExecParams params)
break;
}
case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
- Field<int> length = params.extract_input<Field<float>>("Length");
+ Field<float> length = params.extract_input<Field<float>>("Length");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
if (!component->is_empty()) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index 658de02fdab..33f5eccd719 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -97,12 +97,8 @@ static void node_update(bNodeTree *ntree, bNode *node)
ntree, socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE);
bNodeSocket *height_socket = (bNodeSocket *)node->inputs.last;
- bNodeSocket *width_socket = height_socket->prev;
nodeSetSocketAvailability(
ntree, height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW);
- node_sock_label(width_socket,
- overflow == GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW ? N_("Max Width") :
- N_("Text Box Width"));
}
static float3 get_pivot_point(GeoNodeExecParams &params, CurveEval &curve)
diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc
index c5f40a46ca3..f107ec73c60 100644
--- a/source/blender/nodes/shader/node_shader_tree.cc
+++ b/source/blender/nodes/shader/node_shader_tree.cc
@@ -587,10 +587,11 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
}
}
}
- /* Recreate links between copied nodes. */
+ /* Recreate links between copied nodes AND incoming links to the copied nodes. */
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (link->fromnode->tmp_flag >= 0 && link->tonode->tmp_flag >= 0) {
- bNode *fromnode = nodes_copy[link->fromnode->tmp_flag];
+ if (link->tonode->tmp_flag >= 0) {
+ bool from_node_copied = link->fromnode->tmp_flag >= 0;
+ bNode *fromnode = from_node_copied ? nodes_copy[link->fromnode->tmp_flag] : link->fromnode;
bNode *tonode = nodes_copy[link->tonode->tmp_flag];
bNodeSocket *fromsock = ntree_shader_node_find_output(fromnode, link->fromsock->identifier);
bNodeSocket *tosock = ntree_shader_node_find_input(tonode, link->tosock->identifier);
diff --git a/source/blender/nodes/shader/node_shader_util.cc b/source/blender/nodes/shader/node_shader_util.cc
index c47b69e6b69..059d7800fc5 100644
--- a/source/blender/nodes/shader/node_shader_util.cc
+++ b/source/blender/nodes/shader/node_shader_util.cc
@@ -329,7 +329,7 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat,
void get_XYZ_to_RGB_for_gpu(XYZ_to_RGB *data)
{
- const float *xyz_to_rgb = IMB_colormanagement_get_xyz_to_rgb();
+ const float *xyz_to_rgb = IMB_colormanagement_get_xyz_to_scene_linear();
data->r[0] = xyz_to_rgb[0];
data->r[1] = xyz_to_rgb[3];
data->r[2] = xyz_to_rgb[6];
diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.cc b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
index 62e631efb57..9f382e5a3bb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
@@ -3,6 +3,8 @@
#include "node_shader_util.hh"
+#include "IMB_colormanagement.h"
+
namespace blender::nodes::node_shader_blackbody_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -20,7 +22,7 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat,
const int size = CM_TABLE + 1;
float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "blackbody texture"));
- blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
+ IMB_colormanagement_blackbody_temperature_to_rgb_table(data, size, 800.0f, 12000.0f);
float layer;
GPUNodeLink *ramp_texture = GPU_color_band(mat, size, data, &layer);
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
index 07e700e550a..4c4122a905f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
@@ -3,6 +3,8 @@
#include "node_shader_util.hh"
+#include "IMB_colormanagement.h"
+
namespace blender::nodes::node_shader_volume_principled_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -109,7 +111,7 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
float *data, layer;
if (use_blackbody) {
data = (float *)MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
- blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
+ IMB_colormanagement_blackbody_temperature_to_rgb_table(data, size, 800.0f, 12000.0f);
}
else {
data = (float *)MEM_callocN(sizeof(float) * size * 4, "blackbody black");
diff --git a/source/blender/nodes/shader/nodes/node_shader_wavelength.cc b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
index 522928a30fa..34fa639dd07 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
@@ -3,6 +3,8 @@
#include "node_shader_util.hh"
+#include "IMB_colormanagement.h"
+
namespace blender::nodes::node_shader_wavelength_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -20,22 +22,11 @@ static int node_shader_gpu_wavelength(GPUMaterial *mat,
const int size = CM_TABLE + 1;
float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "cie_xyz texture"));
- wavelength_to_xyz_table(data, size);
+ IMB_colormanagement_wavelength_to_rgb_table(data, size);
float layer;
GPUNodeLink *ramp_texture = GPU_color_band(mat, size, data, &layer);
- XYZ_to_RGB xyz_to_rgb;
- get_XYZ_to_RGB_for_gpu(&xyz_to_rgb);
- return GPU_stack_link(mat,
- node,
- "node_wavelength",
- in,
- out,
- ramp_texture,
- GPU_constant(&layer),
- GPU_uniform(xyz_to_rgb.r),
- GPU_uniform(xyz_to_rgb.g),
- GPU_uniform(xyz_to_rgb.b));
+ return GPU_stack_link(mat, node, "node_wavelength", in, out, ramp_texture, GPU_constant(&layer));
}
} // namespace blender::nodes::node_shader_wavelength_cc
diff --git a/source/blender/python/gpu/gpu_py_element.c b/source/blender/python/gpu/gpu_py_element.c
index 04975fcef96..616e7da6e9f 100644
--- a/source/blender/python/gpu/gpu_py_element.c
+++ b/source/blender/python/gpu/gpu_py_element.c
@@ -91,15 +91,11 @@ static PyObject *pygpu_IndexBuf__tp_new(PyTypeObject *UNUSED(type), PyObject *ar
/* Use `INT_MAX` instead of the actual number of vertices. */
GPU_indexbuf_init(&builder, prim_type.value_found, index_len, INT_MAX);
-#if 0
uint *buf = pybuffer.buf;
for (uint i = index_len; i--; buf++) {
GPU_indexbuf_add_generic_vert(&builder, *buf);
}
-#else
- memcpy(builder.data, pybuffer.buf, index_len * sizeof(*builder.data));
- builder.index_len = index_len;
-#endif
+
PyBuffer_Release(&pybuffer);
}
else {
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index 80c48e31510..d7369731a98 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -752,28 +752,27 @@ static PyObject *pygpu_shader_unbind(BPyGPUShader *UNUSED(self))
Py_RETURN_NONE;
}
-PyDoc_STRVAR(pygpu_shader_from_builtin_doc,
- ".. function:: from_builtin(shader_name, config='DEFAULT')\n"
- "\n"
- " Shaders that are embedded in the blender internal code:\n"
- "" PYDOC_BUILTIN_SHADER_DESCRIPTION
- "\n"
- " They all read the uniform ``mat4 ModelViewProjectionMatrix``,\n"
- " which can be edited by the :mod:`gpu.matrix` module.\n"
- "\n"
- " You can also choose a shader configuration that uses clip_planes by setting the "
- "``CLIPPED`` value to the config parameter. Note that in this case you also need to "
- "manually set the value of ``mat4 ModelMatrix``.\n"
- "\n"
- " :param shader_name: One of the builtin shader names.\n"
- " :type shader_name: str\n"
- " :param config: One of these types of shader configuration:\n"
- "\n"
- " - ``DEFAULT``\n"
- " - ``CLIPPED``\n"
- " :type config: str\n"
- " :return: Shader object corresponding to the given name.\n"
- " :rtype: :class:`bpy.types.GPUShader`\n");
+PyDoc_STRVAR(
+ pygpu_shader_from_builtin_doc,
+ ".. function:: from_builtin(shader_name, config='DEFAULT')\n"
+ "\n"
+ " Shaders that are embedded in the blender internal code (see :ref:`built-in-shaders`).\n"
+ " They all read the uniform ``mat4 ModelViewProjectionMatrix``,\n"
+ " which can be edited by the :mod:`gpu.matrix` module.\n"
+ "\n"
+ " You can also choose a shader configuration that uses clip_planes by setting the "
+ "``CLIPPED`` value to the config parameter. Note that in this case you also need to "
+ "manually set the value of ``mat4 ModelMatrix``.\n"
+ "\n"
+ " :param shader_name: One of the builtin shader names.\n"
+ " :type shader_name: str\n"
+ " :param config: One of these types of shader configuration:\n"
+ "\n"
+ " - ``DEFAULT``\n"
+ " - ``CLIPPED``\n"
+ " :type config: str\n"
+ " :return: Shader object corresponding to the given name.\n"
+ " :rtype: :class:`bpy.types.GPUShader`\n");
static PyObject *pygpu_shader_from_builtin(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
@@ -854,6 +853,8 @@ static struct PyMethodDef pygpu_shader_module__tp_methods[] = {
PyDoc_STRVAR(pygpu_shader_module__tp_doc,
"This module provides access to GPUShader internal functions.\n"
"\n"
+ ".. _built-in-shaders:\n"
+ "\n"
".. rubric:: Built-in shaders\n"
"\n"
"All built-in shaders have the ``mat4 ModelViewProjectionMatrix`` uniform.\n"
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index a6aa1f46b0c..1ee778ae801 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -191,6 +191,17 @@ static const EnumPropertyItem property_subtype_array_items[] = {
"'XYZ', 'XYZ_LENGTH', 'COLOR_GAMMA', 'COORDINATES', 'LAYER', 'LAYER_MEMBER', 'NONE'].\n" \
" :type subtype: string\n"
+static const EnumPropertyItem property_string_search_options_items[] = {
+ {PROP_STRING_SEARCH_SORT, "SORT", 0, "Sort Search Results", ""},
+ {PROP_STRING_SEARCH_SUGGESTION,
+ "SUGGESTION",
+ 0,
+ "Suggestion",
+ "Search results are suggestions (other values may be entered)"},
+
+ {0, NULL, 0, NULL, NULL},
+};
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -257,6 +268,11 @@ struct BPyPropStore {
/** Wrap: #RNA_def_property_poll_runtime */
PyObject *poll_fn;
} pointer_data;
+ /** #PROP_STRING type. */
+ struct {
+ /** Wrap: #RNA_def_property_string_search_func_runtime */
+ PyObject *search_fn;
+ } string_data;
};
} py_data;
};
@@ -1672,6 +1688,163 @@ static void bpy_prop_string_set_fn(struct PointerRNA *ptr,
}
}
+static bool bpy_prop_string_visit_fn_call(PyObject *py_func,
+ PyObject *item,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ const char *text;
+ const char *info = NULL;
+
+ if (PyTuple_CheckExact(item)) {
+ /* Positional only. */
+ static const char *_keywords[] = {
+ "",
+ "",
+ NULL,
+ };
+ static _PyArg_Parser _parser = {
+ "s" /* `text` */
+ "s" /* `info` */
+ ":search",
+ _keywords,
+ 0,
+ };
+ if (!_PyArg_ParseTupleAndKeywordsFast(item, NULL, &_parser, &text, &info)) {
+ PyC_Err_PrintWithFunc(py_func);
+ return false;
+ }
+ }
+ else {
+ text = PyUnicode_AsUTF8(item);
+ if (UNLIKELY(text == NULL)) {
+ PyErr_Clear();
+ PyErr_Format(PyExc_TypeError,
+ "expected sequence of strings or tuple pairs of strings, not %.200s",
+ Py_TYPE(item)->tp_name);
+ PyC_Err_PrintWithFunc(py_func);
+ return false;
+ }
+ }
+
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = text;
+ visit_params.info = info;
+ visit_fn(visit_user_data, &visit_params);
+ return true;
+}
+
+static void bpy_prop_string_visit_for_search_fn(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
+ PyObject *py_func;
+ PyObject *args;
+ PyObject *self;
+ PyObject *ret;
+ PyGILState_STATE gilstate;
+ PyObject *py_edit_text;
+
+ BLI_assert(prop_store != NULL);
+
+ if (C) {
+ bpy_context_set((struct bContext *)C, &gilstate);
+ }
+ else {
+ gilstate = PyGILState_Ensure();
+ }
+
+ py_func = prop_store->py_data.string_data.search_fn;
+
+ args = PyTuple_New(3);
+ self = pyrna_struct_as_instance(ptr);
+ PyTuple_SET_ITEM(args, 0, self);
+
+ Py_INCREF(bpy_context_module);
+ PyTuple_SET_ITEM(args, 1, (PyObject *)bpy_context_module);
+
+ py_edit_text = PyUnicode_FromString(edit_text);
+ PyTuple_SET_ITEM(args, 2, py_edit_text);
+
+ ret = PyObject_CallObject(py_func, args);
+
+ Py_DECREF(args);
+
+ if (ret == NULL) {
+ PyC_Err_PrintWithFunc(py_func);
+ }
+ else {
+ if (PyIter_Check(ret)) {
+ /* Iterators / generator types. */
+ PyObject *it;
+ PyObject *(*iternext)(PyObject *);
+ it = PyObject_GetIter(ret);
+ if (it == NULL) {
+ PyC_Err_PrintWithFunc(py_func);
+ }
+ else {
+ iternext = *Py_TYPE(it)->tp_iternext;
+ for (;;) {
+ PyObject *py_text = iternext(it);
+ if (py_text == NULL) {
+ break;
+ }
+ const bool ok = bpy_prop_string_visit_fn_call(
+ py_func, py_text, visit_fn, visit_user_data);
+ Py_DECREF(py_text);
+ if (!ok) {
+ break;
+ }
+ }
+ Py_DECREF(it);
+ if (PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
+ PyErr_Clear();
+ }
+ else {
+ PyC_Err_PrintWithFunc(py_func);
+ }
+ }
+ }
+ }
+ else {
+ /* Sequence (typically list/tuple). */
+ PyObject *ret_fast = PySequence_Fast(
+ ret,
+ "StringProperty(...): "
+ "return value from search callback was not a sequence, iterator or generator");
+ if (ret_fast == NULL) {
+ PyC_Err_PrintWithFunc(py_func);
+ }
+ else {
+ const Py_ssize_t ret_num = PySequence_Fast_GET_SIZE(ret_fast);
+ PyObject **ret_fast_items = PySequence_Fast_ITEMS(ret_fast);
+ for (Py_ssize_t i = 0; i < ret_num; i++) {
+ const bool ok = bpy_prop_string_visit_fn_call(
+ py_func, ret_fast_items[i], visit_fn, visit_user_data);
+ if (!ok) {
+ break;
+ }
+ }
+ Py_DECREF(ret_fast);
+ }
+ }
+
+ Py_DECREF(ret);
+ }
+
+ if (C) {
+ bpy_context_clear((struct bContext *)C, &gilstate);
+ }
+ else {
+ PyGILState_Release(gilstate);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2352,11 +2525,14 @@ static void bpy_prop_callback_assign_float_array(struct PropertyRNA *prop,
static void bpy_prop_callback_assign_string(struct PropertyRNA *prop,
PyObject *get_fn,
- PyObject *set_fn)
+ PyObject *set_fn,
+ PyObject *search_fn,
+ const eStringPropertySearchFlag search_flag)
{
StringPropertyGetFunc rna_get_fn = NULL;
StringPropertyLengthFunc rna_length_fn = NULL;
StringPropertySetFunc rna_set_fn = NULL;
+ StringPropertySearchFunc rna_search_fn = NULL;
if (get_fn && get_fn != Py_None) {
struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
@@ -2372,8 +2548,17 @@ static void bpy_prop_callback_assign_string(struct PropertyRNA *prop,
rna_set_fn = bpy_prop_string_set_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
+ if (search_fn) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
+
+ rna_search_fn = bpy_prop_string_visit_for_search_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.string_data.search_fn, search_fn);
+ }
RNA_def_property_string_funcs_runtime(prop, rna_get_fn, rna_length_fn, rna_set_fn);
+ if (rna_search_fn) {
+ RNA_def_property_string_search_func_runtime(prop, rna_search_fn, search_flag);
+ }
}
static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
@@ -2628,6 +2813,24 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
" This function must take 2 values (self, value) and return None.\n" \
" :type set: function\n"
+#define BPY_PROPDEF_SEARCH_DOC \
+ " :arg search: Function to be called to show candidates for this string (shown in the UI).\n" \
+ " This function must take 3 values (self, context, edit_text)\n" \
+ " and return a sequence, iterator or generator where each item must be:\n" \
+ "\n" \
+ " - A single string (representing a candidate to display).\n" \
+ " - A tuple-pair of strings, where the first is a candidate and the second\n" \
+ " is additional information about the candidate.\n" \
+ " :type search: function\n" \
+ " :arg search_options: Set of strings in:\n" \
+ "\n" \
+ " - 'SORT' sorts the resulting items.\n" \
+ " - 'SUGGESTION' lets the user enter values not found in search candidates.\n" \
+ " **WARNING** disabling this flag causes the search callback to run on redraw,\n" \
+ " so only disable this flag if it's not likely to cause performance issues.\n" \
+ "\n" \
+ " :type search_options: set\n"
+
#define BPY_PROPDEF_POINTER_TYPE_DOC \
" :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \
" :type type: class\n"
@@ -3721,7 +3924,9 @@ PyDoc_STRVAR(BPy_StringProperty_doc,
"subtype='NONE', "
"update=None, "
"get=None, "
- "set=None)\n"
+ "set=None, "
+ "search=None, "
+ "search_options={'SUGGESTION'})\n"
"\n"
" Returns a new string property definition.\n"
"\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
@@ -3730,7 +3935,7 @@ PyDoc_STRVAR(BPy_StringProperty_doc,
" :arg maxlen: maximum length of the string.\n"
" :type maxlen: int\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_STRING_DOC BPY_PROPDEF_UPDATE_DOC
- BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
+ BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC BPY_PROPDEF_SEARCH_DOC);
static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3767,6 +3972,11 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
PyObject *update_fn = NULL;
PyObject *get_fn = NULL;
PyObject *set_fn = NULL;
+ PyObject *search_fn = NULL;
+ static struct BPy_EnumProperty_Parse search_options_enum = {
+ .items = property_string_search_options_items,
+ .value = PROP_STRING_SEARCH_SUGGESTION,
+ };
static const char *_keywords[] = {
"attr",
@@ -3781,6 +3991,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
"update",
"get",
"set",
+ "search",
+ "search_options",
NULL,
};
static _PyArg_Parser _parser = {
@@ -3797,6 +4009,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
"O" /* `update` */
"O" /* `get` */
"O" /* `set` */
+ "O" /* `search` */
+ "O&" /* `search_options` */
":StringProperty",
_keywords,
0,
@@ -3820,7 +4034,10 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
&subtype_enum,
&update_fn,
&get_fn,
- &set_fn)) {
+ &set_fn,
+ &search_fn,
+ pyrna_enum_bitfield_parse_set,
+ &search_options_enum)) {
return NULL;
}
@@ -3833,6 +4050,9 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return NULL;
}
+ if (bpy_prop_callback_check(search_fn, "search", 3) == -1) {
+ return NULL;
+ }
if (id_data.prop_free_handle != NULL) {
RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle);
@@ -3858,7 +4078,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
bpy_prop_assign_flag_override(prop, override_enum.value);
}
bpy_prop_callback_assign_update(prop, update_fn);
- bpy_prop_callback_assign_string(prop, get_fn, set_fn);
+ bpy_prop_callback_assign_string(prop, get_fn, set_fn, search_fn, search_options_enum.value);
RNA_def_property_duplicate_pointers(srna, prop);
Py_RETURN_NONE;
diff --git a/source/blender/python/mathutils/CMakeLists.txt b/source/blender/python/mathutils/CMakeLists.txt
index 1be9b568626..747d6c0e8f8 100644
--- a/source/blender/python/mathutils/CMakeLists.txt
+++ b/source/blender/python/mathutils/CMakeLists.txt
@@ -4,6 +4,7 @@ set(INC
.
../../blenkernel
../../blenlib
+ ../../imbuf
../../bmesh
../../depsgraph
../../makesdna
@@ -42,6 +43,7 @@ set(SRC
set(LIB
bf_blenlib
+ bf_imbuf
bf_python_ext
${PYTHON_LINKFLAGS}
diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c
index 8b126639f10..88e8d880360 100644
--- a/source/blender/python/mathutils/mathutils_Color.c
+++ b/source/blender/python/mathutils/mathutils_Color.c
@@ -14,14 +14,48 @@
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
+#include "IMB_colormanagement.h"
+
#ifndef MATH_STANDALONE
# include "BLI_dynstr.h"
#endif
#define COLOR_SIZE 3
-/* ----------------------------------mathutils.Color() ------------------- */
-/* makes a new color for you to play with */
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+/**
+ * \note #BaseMath_ReadCallback must be called beforehand.
+ */
+static PyObject *Color_to_tuple_ex(ColorObject *self, int ndigits)
+{
+ PyObject *ret;
+ int i;
+
+ ret = PyTuple_New(COLOR_SIZE);
+
+ if (ndigits >= 0) {
+ for (i = 0; i < COLOR_SIZE; i++) {
+ PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->col[i], ndigits)));
+ }
+ }
+ else {
+ for (i = 0; i < COLOR_SIZE; i++) {
+ PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->col[i]));
+ }
+ }
+
+ return ret;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: `__new__` / `mathutils.Color()`
+ * \{ */
+
static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
float col[3] = {0.0f, 0.0f, 0.0f};
@@ -52,30 +86,130 @@ static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return Color_CreatePyObject(col, type);
}
-/* -----------------------------METHODS---------------------------- */
+/** \} */
-/* NOTE: BaseMath_ReadCallback must be called beforehand. */
-static PyObject *Color_ToTupleExt(ColorObject *self, int ndigits)
+/* -------------------------------------------------------------------- */
+/** \name Color Methods: Color Space Conversion
+ * \{ */
+
+PyDoc_STRVAR(Color_from_scene_linear_to_srgb_doc,
+ ".. function:: from_scene_linear_to_srgb()\n"
+ "\n"
+ " Convert from scene linear to sRGB color space.\n"
+ "\n"
+ " :return: A color in sRGB color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_srgb(ColorObject *self)
{
- PyObject *ret;
- int i;
+ float col[3];
+ IMB_colormanagement_scene_linear_to_srgb_v3(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
- ret = PyTuple_New(COLOR_SIZE);
+PyDoc_STRVAR(Color_from_srgb_to_scene_linear_doc,
+ ".. function:: from_srgb_to_scene_linear()\n"
+ "\n"
+ " Convert from sRGB to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_srgb_to_scene_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_srgb_to_scene_linear_v3(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
- if (ndigits >= 0) {
- for (i = 0; i < COLOR_SIZE; i++) {
- PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->col[i], ndigits)));
- }
- }
- else {
- for (i = 0; i < COLOR_SIZE; i++) {
- PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->col[i]));
- }
- }
+PyDoc_STRVAR(Color_from_scene_linear_to_xyz_d65_doc,
+ ".. function:: from_scene_linear_to_xyz_d65()\n"
+ "\n"
+ " Convert from scene linear to CIE XYZ (Illuminant D65) color space.\n"
+ "\n"
+ " :return: A color in XYZ color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_xyz_d65(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_scene_linear_to_xyz(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
- return ret;
+PyDoc_STRVAR(Color_from_xyz_d65_to_scene_linear_doc,
+ ".. function:: from_xyz_d65_to_scene_linear()\n"
+ "\n"
+ " Convert from CIE XYZ (Illuminant D65) to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_xyz_d65_to_scene_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_xyz_to_scene_linear(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_scene_linear_to_aces_doc,
+ ".. function:: from_scene_linear_to_aces()\n"
+ "\n"
+ " Convert from scene linear to ACES2065-1 linear color space.\n"
+ "\n"
+ " :return: A color in ACES2065-1 linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_aces(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_scene_linear_to_aces(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_aces_to_scene_linear_doc,
+ ".. function:: from_aces_to_scene_linear()\n"
+ "\n"
+ " Convert from ACES2065-1 linear to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_aces_to_scene_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_aces_to_scene_linear(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
}
+PyDoc_STRVAR(Color_from_scene_linear_to_rec709_linear_doc,
+ ".. function:: from_scene_linear_to_rec709_linear()\n"
+ "\n"
+ " Convert from scene linear to Rec.709 linear color space.\n"
+ "\n"
+ " :return: A color in Rec.709 linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_rec709_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_scene_linear_to_rec709(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_rec709_linear_to_scene_linear_doc,
+ ".. function:: from_rec709_linear_to_scene_linear()\n"
+ "\n"
+ " Convert from Rec.709 linear color space to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_rec709_linear_to_scene_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_rec709_to_scene_linear(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Methods: Color Copy/Deep-Copy
+ * \{ */
+
PyDoc_STRVAR(Color_copy_doc,
".. function:: copy()\n"
"\n"
@@ -102,8 +236,11 @@ static PyObject *Color_deepcopy(ColorObject *self, PyObject *args)
return Color_copy(self);
}
-/* ----------------------------print object (internal)-------------- */
-/* print the object to screen */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: `__repr__` & `__str__`
+ * \{ */
static PyObject *Color_repr(ColorObject *self)
{
@@ -113,7 +250,7 @@ static PyObject *Color_repr(ColorObject *self)
return NULL;
}
- tuple = Color_ToTupleExt(self, -1);
+ tuple = Color_to_tuple_ex(self, -1);
ret = PyUnicode_FromFormat("Color(%R)", tuple);
@@ -139,8 +276,12 @@ static PyObject *Color_str(ColorObject *self)
}
#endif
-/* ------------------------tp_richcmpr */
-/* returns -1 exception, 0 false, 1 true */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Rich Compare
+ * \{ */
+
static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op)
{
PyObject *res;
@@ -179,6 +320,12 @@ static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op)
return Py_INCREF_RET(res);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Hash (`__hash__`)
+ * \{ */
+
static Py_hash_t Color_hash(ColorObject *self)
{
if (BaseMath_ReadCallback(self) == -1) {
@@ -192,15 +339,19 @@ static Py_hash_t Color_hash(ColorObject *self)
return mathutils_array_hash(self->col, COLOR_SIZE);
}
-/* ---------------------SEQUENCE PROTOCOLS------------------------ */
-/* ----------------------------len(object)------------------------ */
-/* sequence length */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Sequence & Mapping Protocols Implementation
+ * \{ */
+
+/** Sequence length: `len(object)`. */
static int Color_len(ColorObject *UNUSED(self))
{
return COLOR_SIZE;
}
-/* ----------------------------object[]--------------------------- */
-/* sequence accessor (get) */
+
+/** Sequence accessor (get): `x = object[i]`. */
static PyObject *Color_item(ColorObject *self, int i)
{
if (i < 0) {
@@ -220,8 +371,8 @@ static PyObject *Color_item(ColorObject *self, int i)
return PyFloat_FromDouble(self->col[i]);
}
-/* ----------------------------object[]------------------------- */
-/* sequence accessor (set) */
+
+/** Sequence accessor (set): `object[i] = x`. */
static int Color_ass_item(ColorObject *self, int i, PyObject *value)
{
float f;
@@ -257,8 +408,8 @@ static int Color_ass_item(ColorObject *self, int i, PyObject *value)
return 0;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (get) */
+
+/** Sequence slice accessor (get): `x = object[i:j]`. */
static PyObject *Color_slice(ColorObject *self, int begin, int end)
{
PyObject *tuple;
@@ -282,8 +433,8 @@ static PyObject *Color_slice(ColorObject *self, int begin, int end)
return tuple;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (set) */
+
+/** Sequence slice accessor (set): `object[i:j] = x`. */
static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
{
int i, size;
@@ -320,6 +471,7 @@ static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
return 0;
}
+/** Sequence generic subscript (get): `x = object[...]`. */
static PyObject *Color_subscript(ColorObject *self, PyObject *item)
{
if (PyIndex_Check(item)) {
@@ -356,6 +508,7 @@ static PyObject *Color_subscript(ColorObject *self, PyObject *item)
return NULL;
}
+/** Sequence generic subscript (set): `object[...] = x`. */
static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *value)
{
if (PyIndex_Check(item)) {
@@ -388,29 +541,13 @@ static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *valu
return -1;
}
-/* -----------------PROTCOL DECLARATIONS-------------------------- */
-static PySequenceMethods Color_SeqMethods = {
- (lenfunc)Color_len, /* sq_length */
- (binaryfunc)NULL, /* sq_concat */
- (ssizeargfunc)NULL, /* sq_repeat */
- (ssizeargfunc)Color_item, /* sq_item */
- NULL, /* sq_slice, deprecated */
- (ssizeobjargproc)Color_ass_item, /* sq_ass_item */
- NULL, /* sq_ass_slice, deprecated */
- (objobjproc)NULL, /* sq_contains */
- (binaryfunc)NULL, /* sq_inplace_concat */
- (ssizeargfunc)NULL, /* sq_inplace_repeat */
-};
-
-static PyMappingMethods Color_AsMapping = {
- (lenfunc)Color_len,
- (binaryfunc)Color_subscript,
- (objobjargproc)Color_ass_subscript,
-};
+/** \} */
-/* numeric */
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Numeric Protocol Implementation
+ * \{ */
-/* addition: obj + obj */
+/** Addition: `object + object`. */
static PyObject *Color_add(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL, *color2 = NULL;
@@ -436,7 +573,7 @@ static PyObject *Color_add(PyObject *v1, PyObject *v2)
return Color_CreatePyObject(col, Py_TYPE(v1));
}
-/* addition in-place: obj += obj */
+/** Addition in-place: `object += object`. */
static PyObject *Color_iadd(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL, *color2 = NULL;
@@ -463,7 +600,7 @@ static PyObject *Color_iadd(PyObject *v1, PyObject *v2)
return v1;
}
-/* subtraction: obj - obj */
+/** Subtraction: `object - object`. */
static PyObject *Color_sub(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL, *color2 = NULL;
@@ -489,7 +626,7 @@ static PyObject *Color_sub(PyObject *v1, PyObject *v2)
return Color_CreatePyObject(col, Py_TYPE(v1));
}
-/* subtraction in-place: obj -= obj */
+/** Subtraction in-place: `object -= object`. */
static PyObject *Color_isub(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL, *color2 = NULL;
@@ -523,6 +660,7 @@ static PyObject *color_mul_float(ColorObject *color, const float scalar)
return Color_CreatePyObject(tcol, Py_TYPE(color));
}
+/** Multiplication: `object * object`. */
static PyObject *Color_mul(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL, *color2 = NULL;
@@ -567,6 +705,7 @@ static PyObject *Color_mul(PyObject *v1, PyObject *v2)
return NULL;
}
+/** Division: `object / object`. */
static PyObject *Color_div(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL;
@@ -600,7 +739,7 @@ static PyObject *Color_div(PyObject *v1, PyObject *v2)
return NULL;
}
-/* multiplication in-place: obj *= obj */
+/** Multiplication in-place: `object *= object`. */
static PyObject *Color_imul(PyObject *v1, PyObject *v2)
{
ColorObject *color = (ColorObject *)v1;
@@ -628,7 +767,7 @@ static PyObject *Color_imul(PyObject *v1, PyObject *v2)
return v1;
}
-/* multiplication in-place: obj *= obj */
+/** Division in-place: `object *= object`. */
static PyObject *Color_idiv(PyObject *v1, PyObject *v2)
{
ColorObject *color = (ColorObject *)v1;
@@ -661,8 +800,7 @@ static PyObject *Color_idiv(PyObject *v1, PyObject *v2)
return v1;
}
-/* -obj
- * returns the negative of this object */
+/** Negative (returns the negative of this object): `-object`. */
static PyObject *Color_neg(ColorObject *self)
{
float tcol[COLOR_SIZE];
@@ -675,6 +813,31 @@ static PyObject *Color_neg(ColorObject *self)
return Color_CreatePyObject(tcol, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Protocol Declarations
+ * \{ */
+
+static PySequenceMethods Color_SeqMethods = {
+ (lenfunc)Color_len, /*sq_length*/
+ (binaryfunc)NULL, /*sq_concat*/
+ (ssizeargfunc)NULL, /*sq_repeat*/
+ (ssizeargfunc)Color_item, /*sq_item*/
+ NULL, /*sq_slice(DEPRECATED)*/
+ (ssizeobjargproc)Color_ass_item, /*sq_ass_item*/
+ NULL, /*sq_ass_slice(DEPRECATED)*/
+ (objobjproc)NULL, /*sq_contains*/
+ (binaryfunc)NULL, /*sq_inplace_concat*/
+ (ssizeargfunc)NULL, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods Color_AsMapping = {
+ (lenfunc)Color_len,
+ (binaryfunc)Color_subscript,
+ (objobjargproc)Color_ass_subscript,
+};
+
static PyNumberMethods Color_NumMethods = {
(binaryfunc)Color_add, /*nb_add*/
(binaryfunc)Color_sub, /*nb_subtract*/
@@ -695,24 +858,31 @@ static PyNumberMethods Color_NumMethods = {
NULL, /*nb_int*/
NULL, /*nb_reserved*/
NULL, /*nb_float*/
- Color_iadd, /* nb_inplace_add */
- Color_isub, /* nb_inplace_subtract */
- Color_imul, /* nb_inplace_multiply */
- NULL, /* nb_inplace_remainder */
- NULL, /* nb_inplace_power */
- NULL, /* nb_inplace_lshift */
- NULL, /* nb_inplace_rshift */
- NULL, /* nb_inplace_and */
- NULL, /* nb_inplace_xor */
- NULL, /* nb_inplace_or */
- NULL, /* nb_floor_divide */
- Color_div, /* nb_true_divide */
- NULL, /* nb_inplace_floor_divide */
- Color_idiv, /* nb_inplace_true_divide */
- NULL, /* nb_index */
+ Color_iadd, /*nb_inplace_add*/
+ Color_isub, /*nb_inplace_subtract*/
+ Color_imul, /*nb_inplace_multiply*/
+ NULL, /*nb_inplace_remainder*/
+ NULL, /*nb_inplace_power*/
+ NULL, /*nb_inplace_lshift*/
+ NULL, /*nb_inplace_rshift*/
+ NULL, /*nb_inplace_and*/
+ NULL, /*nb_inplace_xor*/
+ NULL, /*nb_inplace_or*/
+ NULL, /*nb_floor_divide*/
+ Color_div, /*nb_true_divide*/
+ NULL, /*nb_inplace_floor_divide*/
+ Color_idiv, /*nb_inplace_true_divide*/
+ NULL, /*nb_index*/
};
-/* color channel, vector.r/g/b */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Get/Set Item Implementation
+ * \{ */
+
+/* Color channel (RGB): `color.r/g/b`. */
+
PyDoc_STRVAR(Color_channel_r_doc, "Red color channel.\n\n:type: float");
PyDoc_STRVAR(Color_channel_g_doc, "Green color channel.\n\n:type: float");
PyDoc_STRVAR(Color_channel_b_doc, "Blue color channel.\n\n:type: float");
@@ -727,7 +897,8 @@ static int Color_channel_set(ColorObject *self, PyObject *value, void *type)
return Color_ass_item(self, POINTER_AS_INT(type), value);
}
-/* color channel (HSV), color.h/s/v */
+/* Color channel (HSV): `color.h/s/v`. */
+
PyDoc_STRVAR(Color_channel_hsv_h_doc, "HSV Hue component in [0, 1].\n\n:type: float");
PyDoc_STRVAR(Color_channel_hsv_s_doc, "HSV Saturation component in [0, 1].\n\n:type: float");
PyDoc_STRVAR(Color_channel_hsv_v_doc, "HSV Value component in [0, 1].\n\n:type: float");
@@ -775,8 +946,8 @@ static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type)
return 0;
}
-/* color channel (HSV), color.h/s/v */
PyDoc_STRVAR(Color_hsv_doc, "HSV Values in [0, 1].\n\n:type: float triplet");
+/** Color channel HSV (get): `x = color.hsv`. */
static PyObject *Color_hsv_get(ColorObject *self, void *UNUSED(closure))
{
float hsv[3];
@@ -794,6 +965,7 @@ static PyObject *Color_hsv_get(ColorObject *self, void *UNUSED(closure))
return ret;
}
+/** Color channel HSV (set): `color.hsv = x`. */
static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closure))
{
float hsv[3];
@@ -816,9 +988,12 @@ static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closur
return 0;
}
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Get/Set Item Definitions
+ * \{ */
+
static PyGetSetDef Color_getseters[] = {
{"r", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_r_doc, (void *)0},
{"g", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_g_doc, (void *)1},
@@ -861,7 +1036,12 @@ static PyGetSetDef Color_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-/* -----------------------METHOD DEFINITIONS ---------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Method Definitions
+ * \{ */
+
static struct PyMethodDef Color_methods[] = {
{"copy", (PyCFunction)Color_copy, METH_NOARGS, Color_copy_doc},
{"__copy__", (PyCFunction)Color_copy, METH_NOARGS, Color_copy_doc},
@@ -869,17 +1049,61 @@ static struct PyMethodDef Color_methods[] = {
/* base-math methods */
{"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
+
+ /* Color-space methods. */
+ {"from_scene_linear_to_srgb",
+ (PyCFunction)Color_from_scene_linear_to_srgb,
+ METH_NOARGS,
+ Color_from_scene_linear_to_srgb_doc},
+ {"from_srgb_to_scene_linear",
+ (PyCFunction)Color_from_srgb_to_scene_linear,
+ METH_NOARGS,
+ Color_from_srgb_to_scene_linear_doc},
+ {"from_scene_linear_to_xyz_d65",
+ (PyCFunction)Color_from_scene_linear_to_xyz_d65,
+ METH_NOARGS,
+ Color_from_scene_linear_to_xyz_d65_doc},
+ {"from_xyz_d65_to_scene_linear",
+ (PyCFunction)Color_from_xyz_d65_to_scene_linear,
+ METH_NOARGS,
+ Color_from_xyz_d65_to_scene_linear_doc},
+ {"from_scene_linear_to_aces",
+ (PyCFunction)Color_from_scene_linear_to_aces,
+ METH_NOARGS,
+ Color_from_scene_linear_to_aces_doc},
+ {"from_aces_to_scene_linear",
+ (PyCFunction)Color_from_aces_to_scene_linear,
+ METH_NOARGS,
+ Color_from_aces_to_scene_linear_doc},
+ {"from_scene_linear_to_rec709_linear",
+ (PyCFunction)Color_from_scene_linear_to_rec709_linear,
+ METH_NOARGS,
+ Color_from_scene_linear_to_rec709_linear_doc},
+ {"from_rec709_linear_to_scene_linear",
+ (PyCFunction)Color_from_rec709_linear_to_scene_linear,
+ METH_NOARGS,
+ Color_from_rec709_linear_to_scene_linear_doc},
{NULL, NULL, 0, NULL},
};
-/* ------------------PY_OBECT DEFINITION-------------------------- */
-PyDoc_STRVAR(color_doc,
- ".. class:: Color(rgb)\n"
- "\n"
- " This object gives access to Colors in Blender.\n"
- "\n"
- " :param rgb: (r, g, b) color values\n"
- " :type rgb: 3d vector\n");
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Python Object Definition
+ * \{ */
+
+PyDoc_STRVAR(
+ color_doc,
+ ".. class:: Color(rgb)\n"
+ "\n"
+ " This object gives access to Colors in Blender.\n"
+ "\n"
+ " Most colors returned by Blender APIs are in scene linear color space, as defined by "
+ " the OpenColorIO configuration. The notable exception is user interface theming colors, "
+ " which are in sRGB color space.\n"
+ "\n"
+ " :param rgb: (r, g, b) color values\n"
+ " :type rgb: 3d vector\n");
PyTypeObject color_Type = {
PyVarObject_HEAD_INIT(NULL, 0) "Color", /* tp_name */
sizeof(ColorObject), /* tp_basicsize */
@@ -932,6 +1156,12 @@ PyTypeObject color_Type = {
NULL, /* tp_del */
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: C/API Constructors
+ * \{ */
+
PyObject *Color_CreatePyObject(const float col[3], PyTypeObject *base_type)
{
ColorObject *self;
@@ -1001,3 +1231,5 @@ PyObject *Color_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar cb_sub
return (PyObject *)self;
}
+
+/** \} */
diff --git a/source/blender/python/mathutils/mathutils_Color.h b/source/blender/python/mathutils/mathutils_Color.h
index 11a936b7bc8..b4fd2eeaa81 100644
--- a/source/blender/python/mathutils/mathutils_Color.h
+++ b/source/blender/python/mathutils/mathutils_Color.h
@@ -19,7 +19,8 @@ typedef struct {
* be stored in py_data) or be a wrapper for data allocated through
* Blender (stored in blend_data). This is an either/or struct not both. */
-/* prototypes */
+/* Prototypes. */
+
PyObject *Color_CreatePyObject(const float col[3],
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
PyObject *Color_CreatePyObject_wrap(float col[3], PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c
index 909c19e8cd2..f49868dfba7 100644
--- a/source/blender/python/mathutils/mathutils_Euler.c
+++ b/source/blender/python/mathutils/mathutils_Euler.c
@@ -19,45 +19,11 @@
#define EULER_SIZE 3
-/* ----------------------------------mathutils.Euler() ------------------- */
-/* makes a new euler for you to play with */
-static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyObject *seq = NULL;
- const char *order_str = NULL;
-
- float eul[EULER_SIZE] = {0.0f, 0.0f, 0.0f};
- short order = EULER_ORDER_XYZ;
-
- if (kwds && PyDict_Size(kwds)) {
- PyErr_SetString(PyExc_TypeError,
- "mathutils.Euler(): "
- "takes no keyword args");
- return NULL;
- }
-
- if (!PyArg_ParseTuple(args, "|Os:mathutils.Euler", &seq, &order_str)) {
- return NULL;
- }
-
- switch (PyTuple_GET_SIZE(args)) {
- case 0:
- break;
- case 2:
- if ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1) {
- return NULL;
- }
- ATTR_FALLTHROUGH;
- case 1:
- if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1) {
- return NULL;
- }
- break;
- }
- return Euler_CreatePyObject(eul, order, type);
-}
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
-/* internal use, assume read callback is done */
+/** Internal use, assume read callback is done. */
static const char *euler_order_str(EulerObject *self)
{
static const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
@@ -96,8 +62,10 @@ short euler_order_from_string(const char *str, const char *error_prefix)
return -1;
}
-/* NOTE: BaseMath_ReadCallback must be called beforehand. */
-static PyObject *Euler_ToTupleExt(EulerObject *self, int ndigits)
+/**
+ * \note #BaseMath_ReadCallback must be called beforehand.
+ */
+static PyObject *Euler_to_tuple_ex(EulerObject *self, int ndigits)
{
PyObject *ret;
int i;
@@ -118,8 +86,53 @@ static PyObject *Euler_ToTupleExt(EulerObject *self, int ndigits)
return ret;
}
-/* -----------------------------METHODS----------------------------
- * return a quaternion representation of the euler */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: `__new__` / `mathutils.Euler()`
+ * \{ */
+
+static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *seq = NULL;
+ const char *order_str = NULL;
+
+ float eul[EULER_SIZE] = {0.0f, 0.0f, 0.0f};
+ short order = EULER_ORDER_XYZ;
+
+ if (kwds && PyDict_Size(kwds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "mathutils.Euler(): "
+ "takes no keyword args");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "|Os:mathutils.Euler", &seq, &order_str)) {
+ return NULL;
+ }
+
+ switch (PyTuple_GET_SIZE(args)) {
+ case 0:
+ break;
+ case 2:
+ if ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1) {
+ return NULL;
+ }
+ ATTR_FALLTHROUGH;
+ case 1:
+ if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1) {
+ return NULL;
+ }
+ break;
+ }
+ return Euler_CreatePyObject(eul, order, type);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Methods
+ * \{ */
PyDoc_STRVAR(Euler_to_quaternion_doc,
".. method:: to_quaternion()\n"
@@ -141,7 +154,6 @@ static PyObject *Euler_to_quaternion(EulerObject *self)
return Quaternion_CreatePyObject(quat, NULL);
}
-/* return a matrix representation of the euler */
PyDoc_STRVAR(Euler_to_matrix_doc,
".. method:: to_matrix()\n"
"\n"
@@ -279,9 +291,6 @@ static PyObject *Euler_make_compatible(EulerObject *self, PyObject *value)
Py_RETURN_NONE;
}
-/* ----------------------------Euler.rotate()-----------------------
- * return a copy of the euler */
-
PyDoc_STRVAR(Euler_copy_doc,
".. function:: copy()\n"
"\n"
@@ -308,8 +317,11 @@ static PyObject *Euler_deepcopy(EulerObject *self, PyObject *args)
return Euler_copy(self);
}
-/* ----------------------------print object (internal)--------------
- * print the object to screen */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: `__repr__` & `__str__`
+ * \{ */
static PyObject *Euler_repr(EulerObject *self)
{
@@ -319,7 +331,7 @@ static PyObject *Euler_repr(EulerObject *self)
return NULL;
}
- tuple = Euler_ToTupleExt(self, -1);
+ tuple = Euler_to_tuple_ex(self, -1);
ret = PyUnicode_FromFormat("Euler(%R, '%s')", tuple, euler_order_str(self));
@@ -349,6 +361,12 @@ static PyObject *Euler_str(EulerObject *self)
}
#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Rich Compare
+ * \{ */
+
static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
{
PyObject *res;
@@ -390,6 +408,12 @@ static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
return Py_INCREF_RET(res);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Hash (`__hash__`)
+ * \{ */
+
static Py_hash_t Euler_hash(EulerObject *self)
{
if (BaseMath_ReadCallback(self) == -1) {
@@ -403,15 +427,19 @@ static Py_hash_t Euler_hash(EulerObject *self)
return mathutils_array_hash(self->eul, EULER_SIZE);
}
-/* ---------------------SEQUENCE PROTOCOLS------------------------ */
-/* ----------------------------len(object)------------------------ */
-/* sequence length */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Sequence Protocol
+ * \{ */
+
+/** Sequence length: `len(object)`. */
static int Euler_len(EulerObject *UNUSED(self))
{
return EULER_SIZE;
}
-/* ----------------------------object[]--------------------------- */
-/* sequence accessor (get) */
+
+/** Sequence accessor (get): `x = object[i]`. */
static PyObject *Euler_item(EulerObject *self, int i)
{
if (i < 0) {
@@ -431,8 +459,8 @@ static PyObject *Euler_item(EulerObject *self, int i)
return PyFloat_FromDouble(self->eul[i]);
}
-/* ----------------------------object[]------------------------- */
-/* sequence accessor (set) */
+
+/** Sequence accessor (set): `object[i] = x`. */
static int Euler_ass_item(EulerObject *self, int i, PyObject *value)
{
float f;
@@ -468,8 +496,8 @@ static int Euler_ass_item(EulerObject *self, int i, PyObject *value)
return 0;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (get) */
+
+/** Sequence slice accessor (get): `x = object[i:j]`. */
static PyObject *Euler_slice(EulerObject *self, int begin, int end)
{
PyObject *tuple;
@@ -493,8 +521,8 @@ static PyObject *Euler_slice(EulerObject *self, int begin, int end)
return tuple;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (set) */
+
+/** Sequence slice accessor (set): `object[i:j] = x`. */
static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
{
int i, size;
@@ -531,6 +559,7 @@ static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
return 0;
}
+/** Sequence generic subscript (get): `x = object[...]`. */
static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
{
if (PyIndex_Check(item)) {
@@ -567,6 +596,7 @@ static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
return NULL;
}
+/** Sequence generic subscript (set): `object[...] = x`. */
static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *value)
{
if (PyIndex_Check(item)) {
@@ -599,18 +629,23 @@ static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *valu
return -1;
}
-/* -----------------PROTCOL DECLARATIONS-------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Sequence & Mapping Protocol Declarations
+ * \{ */
+
static PySequenceMethods Euler_SeqMethods = {
- (lenfunc)Euler_len, /* sq_length */
- (binaryfunc)NULL, /* sq_concat */
- (ssizeargfunc)NULL, /* sq_repeat */
- (ssizeargfunc)Euler_item, /* sq_item */
- (ssizessizeargfunc)NULL, /* sq_slice (deprecated) */
- (ssizeobjargproc)Euler_ass_item, /* sq_ass_item */
- (ssizessizeobjargproc)NULL, /* sq_ass_slice (deprecated) */
- (objobjproc)NULL, /* sq_contains */
- (binaryfunc)NULL, /* sq_inplace_concat */
- (ssizeargfunc)NULL, /* sq_inplace_repeat */
+ (lenfunc)Euler_len, /*sq_length*/
+ (binaryfunc)NULL, /*sq_concat*/
+ (ssizeargfunc)NULL, /*sq_repeat*/
+ (ssizeargfunc)Euler_item, /*sq_item*/
+ (ssizessizeargfunc)NULL, /*sq_slice(DEPRECATED)*/
+ (ssizeobjargproc)Euler_ass_item, /*sq_ass_item*/
+ (ssizessizeobjargproc)NULL, /*sq_ass_slice(DEPRECATED)*/
+ (objobjproc)NULL, /*sq_contains*/
+ (binaryfunc)NULL, /*sq_inplace_concat*/
+ (ssizeargfunc)NULL, /*sq_inplace_repeat*/
};
static PyMappingMethods Euler_AsMapping = {
@@ -619,7 +654,13 @@ static PyMappingMethods Euler_AsMapping = {
(objobjargproc)Euler_ass_subscript,
};
-/* euler axis, euler.x/y/z */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Get/Set Item Implementation
+ * \{ */
+
+/* Euler axis: `euler.x/y/z`. */
PyDoc_STRVAR(Euler_axis_doc, "Euler axis angle in radians.\n\n:type: float");
static PyObject *Euler_axis_get(EulerObject *self, void *type)
@@ -632,7 +673,7 @@ static int Euler_axis_set(EulerObject *self, PyObject *value, void *type)
return Euler_ass_item(self, POINTER_AS_INT(type), value);
}
-/* rotation order */
+/* Euler rotation order: `euler.order`. */
PyDoc_STRVAR(
Euler_order_doc,
@@ -666,9 +707,12 @@ static int Euler_order_set(EulerObject *self, PyObject *value, void *UNUSED(clos
return 0;
}
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Get/Set Item Definitions
+ * \{ */
+
static PyGetSetDef Euler_getseters[] = {
{"x", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)0},
{"y", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)1},
@@ -694,7 +738,12 @@ static PyGetSetDef Euler_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-/* -----------------------METHOD DEFINITIONS ---------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Method Definitions
+ * \{ */
+
static struct PyMethodDef Euler_methods[] = {
{"zero", (PyCFunction)Euler_zero, METH_NOARGS, Euler_zero_doc},
{"to_matrix", (PyCFunction)Euler_to_matrix, METH_NOARGS, Euler_to_matrix_doc},
@@ -711,7 +760,12 @@ static struct PyMethodDef Euler_methods[] = {
{NULL, NULL, 0, NULL},
};
-/* ------------------PY_OBECT DEFINITION-------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Python Object Definition
+ * \{ */
+
PyDoc_STRVAR(
euler_doc,
".. class:: Euler(angles, order='XYZ')\n"
@@ -776,6 +830,12 @@ PyTypeObject euler_Type = {
NULL, /* tp_del */
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: C/API Constructors
+ * \{ */
+
PyObject *Euler_CreatePyObject(const float eul[3], const short order, PyTypeObject *base_type)
{
EulerObject *self;
@@ -849,3 +909,5 @@ PyObject *Euler_CreatePyObject_cb(PyObject *cb_user,
return (PyObject *)self;
}
+
+/** \} */
diff --git a/source/blender/python/mathutils/mathutils_Euler.h b/source/blender/python/mathutils/mathutils_Euler.h
index 4438ee380af..ca2ca26c90a 100644
--- a/source/blender/python/mathutils/mathutils_Euler.h
+++ b/source/blender/python/mathutils/mathutils_Euler.h
@@ -22,6 +22,7 @@ typedef struct {
* blender (stored in blend_data). This is an either/or struct not both */
/* prototypes */
+
PyObject *Euler_CreatePyObject(const float eul[3],
short order,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 76b5424711f..8cd7a5c7d87 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -32,6 +32,10 @@ static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
MatrixObject *self);
static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type);
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row)
{
if ((vec->vec_num != mat->col_num) || (row >= mat->row_num)) {
@@ -56,9 +60,242 @@ static int matrix_col_vector_check(MatrixObject *mat, VectorObject *vec, int col
return 1;
}
-/* ----------------------------------------------------------------------------
- * matrix row callbacks
- * this is so you can do matrix[i][j] = val OR matrix.row[i][j] = val */
+/** When a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4. */
+static void matrix_3x3_as_4x4(float mat[16])
+{
+ mat[10] = mat[8];
+ mat[9] = mat[7];
+ mat[8] = mat[6];
+ mat[7] = 0.0f;
+ mat[6] = mat[5];
+ mat[5] = mat[4];
+ mat[4] = mat[3];
+ mat[3] = 0.0f;
+}
+
+void matrix_as_3x3(float mat[3][3], MatrixObject *self)
+{
+ copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
+ copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1));
+ copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2));
+}
+
+static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src)
+{
+ BLI_assert((mat_dst->col_num == mat_src->col_num) && (mat_dst->row_num == mat_src->row_num));
+ BLI_assert(mat_dst != mat_src);
+
+ memcpy(mat_dst->matrix, mat_src->matrix, sizeof(float) * (mat_dst->col_num * mat_dst->row_num));
+}
+
+static void matrix_unit_internal(MatrixObject *self)
+{
+ const int mat_size = sizeof(float) * (self->col_num * self->row_num);
+ memset(self->matrix, 0x0, mat_size);
+ const int col_row_max = min_ii(self->col_num, self->row_num);
+ const int row_num = self->row_num;
+ for (int col = 0; col < col_row_max; col++) {
+ self->matrix[(col * row_num) + col] = 1.0f;
+ }
+}
+
+/** Transposes memory layout, row/columns don't have to match. */
+static void matrix_transpose_internal(float mat_dst_fl[], const MatrixObject *mat_src)
+{
+ ushort col, row;
+ uint i = 0;
+
+ for (row = 0; row < mat_src->row_num; row++) {
+ for (col = 0; col < mat_src->col_num; col++) {
+ mat_dst_fl[i++] = MATRIX_ITEM(mat_src, row, col);
+ }
+ }
+}
+
+/** Assumes `rowsize == colsize` is checked and the read callback has run. */
+static float matrix_determinant_internal(const MatrixObject *self)
+{
+ if (self->col_num == 2) {
+ return determinant_m2(MATRIX_ITEM(self, 0, 0),
+ MATRIX_ITEM(self, 0, 1),
+ MATRIX_ITEM(self, 1, 0),
+ MATRIX_ITEM(self, 1, 1));
+ }
+ if (self->col_num == 3) {
+ return determinant_m3(MATRIX_ITEM(self, 0, 0),
+ MATRIX_ITEM(self, 0, 1),
+ MATRIX_ITEM(self, 0, 2),
+ MATRIX_ITEM(self, 1, 0),
+ MATRIX_ITEM(self, 1, 1),
+ MATRIX_ITEM(self, 1, 2),
+ MATRIX_ITEM(self, 2, 0),
+ MATRIX_ITEM(self, 2, 1),
+ MATRIX_ITEM(self, 2, 2));
+ }
+
+ return determinant_m4((const float(*)[4])self->matrix);
+}
+
+static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const ushort dim)
+{
+ /* calculate the classical adjoint */
+ switch (dim) {
+ case 2: {
+ adjoint_m2_m2((float(*)[2])mat_dst, (const float(*)[2])mat_src);
+ break;
+ }
+ case 3: {
+ adjoint_m3_m3((float(*)[3])mat_dst, (const float(*)[3])mat_src);
+ break;
+ }
+ case 4: {
+ adjoint_m4_m4((float(*)[4])mat_dst, (const float(*)[4])mat_src);
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+}
+
+static void matrix_invert_with_det_n_internal(float *mat_dst,
+ const float *mat_src,
+ const float det,
+ const ushort dim)
+{
+ float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
+ ushort i, j, k;
+
+ BLI_assert(det != 0.0f);
+
+ adjoint_matrix_n(mat, mat_src, dim);
+
+ /* divide by determinant & set values */
+ k = 0;
+ for (i = 0; i < dim; i++) { /* col_num */
+ for (j = 0; j < dim; j++) { /* row_num */
+ mat_dst[MATRIX_ITEM_INDEX_NUMROW(dim, j, i)] = mat[k++] / det;
+ }
+ }
+}
+
+/**
+ * \param r_mat: can be from `self->matrix` or not.
+ */
+static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
+{
+ float det;
+ BLI_assert(self->col_num == self->row_num);
+ det = matrix_determinant_internal(self);
+
+ if (det != 0.0f) {
+ matrix_invert_with_det_n_internal(r_mat, self->matrix, det, self->col_num);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * 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)
+{
+ float det;
+ float *in_mat = self->matrix;
+ BLI_assert(self->col_num == self->row_num);
+ det = matrix_determinant_internal(self);
+
+ if (det == 0.0f) {
+ const float eps = PSEUDOINVERSE_EPSILON;
+
+ /* We will copy self->matrix into r_mat (if needed),
+ * and modify it in place to add diagonal epsilon. */
+ in_mat = r_mat;
+
+ switch (self->col_num) {
+ case 2: {
+ float(*mat)[2] = (float(*)[2])in_mat;
+
+ if (in_mat != self->matrix) {
+ copy_m2_m2(mat, (const float(*)[2])self->matrix);
+ }
+ mat[0][0] += eps;
+ mat[1][1] += eps;
+
+ if (UNLIKELY((det = determinant_m2(mat[0][0], mat[0][1], mat[1][0], mat[1][1])) == 0.0f)) {
+ unit_m2(mat);
+ det = 1.0f;
+ }
+ break;
+ }
+ case 3: {
+ float(*mat)[3] = (float(*)[3])in_mat;
+
+ if (in_mat != self->matrix) {
+ copy_m3_m3(mat, (const float(*)[3])self->matrix);
+ }
+ mat[0][0] += eps;
+ mat[1][1] += eps;
+ mat[2][2] += eps;
+
+ if (UNLIKELY((det = determinant_m3_array(mat)) == 0.0f)) {
+ unit_m3(mat);
+ det = 1.0f;
+ }
+ break;
+ }
+ case 4: {
+ float(*mat)[4] = (float(*)[4])in_mat;
+
+ if (in_mat != self->matrix) {
+ copy_m4_m4(mat, (const float(*)[4])self->matrix);
+ }
+ mat[0][0] += eps;
+ mat[1][1] += eps;
+ mat[2][2] += eps;
+ mat[3][3] += eps;
+
+ if (UNLIKELY(det = determinant_m4(mat)) == 0.0f) {
+ unit_m4(mat);
+ det = 1.0f;
+ }
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+ }
+
+ matrix_invert_with_det_n_internal(r_mat, in_mat, det, self->col_num);
+}
+
+static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
+ MatrixObject *self)
+{
+ PyObject *ret = Matrix_copy(self);
+ if (ret) {
+ PyObject *ret_dummy = matrix_func((MatrixObject *)ret);
+ if (ret_dummy) {
+ Py_DECREF(ret_dummy);
+ return ret;
+ }
+ /* error */
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ /* copy may fail if the read callback errors out */
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Row Callbacks
+ * This is so you can do `matrix[i][j] = val` or `matrix.row[i][j] = val`.
+ * \{ */
uchar mathutils_matrix_row_cb_index = -1;
@@ -147,9 +384,12 @@ Mathutils_Callback mathutils_matrix_row_cb = {
mathutils_matrix_row_set_index,
};
-/* ----------------------------------------------------------------------------
- * matrix row callbacks
- * this is so you can do matrix.col[i][j] = val */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Column Callbacks
+ * This is so you can do `matrix.col[i][j] = val`.
+ * \{ */
uchar mathutils_matrix_col_cb_index = -1;
@@ -246,10 +486,14 @@ Mathutils_Callback mathutils_matrix_col_cb = {
mathutils_matrix_col_set_index,
};
-/* ----------------------------------------------------------------------------
- * matrix row callbacks
- * this is so you can do matrix.translation = val
- * NOTE: this is _exactly like matrix.col except the 4th component is always omitted. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Translation Callbacks
+ * This is so you can do `matrix.translation = val`.
+ *
+ * \note this is _exactly like matrix.col except the 4th component is always omitted.
+ * \{ */
uchar mathutils_matrix_translation_cb_index = -1;
@@ -326,11 +570,12 @@ Mathutils_Callback mathutils_matrix_translation_cb = {
mathutils_matrix_translation_set_index,
};
-/* matrix column callbacks, this is so you can do `matrix.translation = Vector()`. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: `__new__` / `mathutils.Matrix()`
+ * \{ */
-/* ----------------------------------mathutils.Matrix() ----------------- */
-/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
-/* create a new matrix type */
static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
if (kwds && PyDict_Size(kwds)) {
@@ -379,41 +624,13 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
-static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
- MatrixObject *self)
-{
- PyObject *ret = Matrix_copy(self);
- if (ret) {
- PyObject *ret_dummy = matrix_func((MatrixObject *)ret);
- if (ret_dummy) {
- Py_DECREF(ret_dummy);
- return ret;
- }
- /* error */
- Py_DECREF(ret);
- return NULL;
- }
-
- /* copy may fail if the read callback errors out */
- return NULL;
-}
-
-/* when a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4 */
-static void matrix_3x3_as_4x4(float mat[16])
-{
- mat[10] = mat[8];
- mat[9] = mat[7];
- mat[8] = mat[6];
- mat[7] = 0.0f;
- mat[6] = mat[5];
- mat[5] = mat[4];
- mat[4] = mat[3];
- mat[3] = 0.0f;
-}
+/** \} */
-/*-----------------------CLASS-METHODS----------------------------*/
+/* -------------------------------------------------------------------- */
+/** \name Matrix Class Methods
+ * \{ */
-/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
+/** Identity constructor: `mathutils.Matrix.Identity()`. */
PyDoc_STRVAR(C_Matrix_Identity_doc,
".. classmethod:: Identity(size)\n"
"\n"
@@ -441,6 +658,7 @@ static PyObject *C_Matrix_Identity(PyObject *cls, PyObject *args)
return Matrix_CreatePyObject(NULL, matSize, matSize, (PyTypeObject *)cls);
}
+/** Rotation constructor: `mathutils.Matrix.Rotation()`. */
PyDoc_STRVAR(C_Matrix_Rotation_doc,
".. classmethod:: Rotation(angle, size, axis)\n"
"\n"
@@ -460,25 +678,8 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
PyObject *vec = NULL;
const char *axis = NULL;
int matSize;
- double angle; /* use double because of precision problems at high values */
- float mat[16] = {
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- };
+ double angle; /* Use double because of precision problems at high values. */
+ float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
if (!PyArg_ParseTuple(args, "di|O:Matrix.Rotation", &angle, &matSize, &vec)) {
return NULL;
@@ -545,6 +746,7 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
}
+/** Translation constructor: `mathutils.Matrix.Translation()`. */
PyDoc_STRVAR(C_Matrix_Translation_doc,
".. classmethod:: Translation(vector)\n"
"\n"
@@ -567,7 +769,7 @@ static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
}
-/* ----------------------------------mathutils.Matrix.Diagonal() ------------- */
+
PyDoc_STRVAR(C_Matrix_Diagonal_doc,
".. classmethod:: Diagonal(vector)\n"
"\n"
@@ -577,6 +779,7 @@ PyDoc_STRVAR(C_Matrix_Diagonal_doc,
" :type vector: :class:`Vector`\n"
" :return: A diagonal matrix.\n"
" :rtype: :class:`Matrix`\n");
+/** Diagonal constructor: `mathutils.Matrix.Diagonal()`. */
static PyObject *C_Matrix_Diagonal(PyObject *cls, PyObject *value)
{
float mat[16] = {0.0f};
@@ -595,8 +798,8 @@ static PyObject *C_Matrix_Diagonal(PyObject *cls, PyObject *value)
return Matrix_CreatePyObject(mat, size, size, (PyTypeObject *)cls);
}
-/* ----------------------------------mathutils.Matrix.Scale() ------------- */
-/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
+
+/** Scale constructor: `mathutils.Matrix.Scale()`. */
PyDoc_STRVAR(C_Matrix_Scale_doc,
".. classmethod:: Scale(factor, size, axis)\n"
"\n"
@@ -617,24 +820,7 @@ static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
float tvec[3];
float factor;
int matSize;
- float mat[16] = {
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- };
+ float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
if (!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
return NULL;
@@ -700,8 +886,7 @@ static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
/* pass to matrix creation */
return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
}
-/* ----------------------------------mathutils.Matrix.OrthoProjection() --- */
-/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
+/** Orthographic projection constructor: `mathutils.Matrix.OrthoProjection()`. */
PyDoc_STRVAR(C_Matrix_OrthoProjection_doc,
".. classmethod:: OrthoProjection(axis, size)\n"
"\n"
@@ -721,24 +906,7 @@ static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
int matSize, x;
float norm = 0.0f;
- float mat[16] = {
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- };
+ float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
if (!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
return NULL;
@@ -837,6 +1005,7 @@ static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
}
+/** Shear constructor: `mathutils.Matrix.Shear()`. */
PyDoc_STRVAR(C_Matrix_Shear_doc,
".. classmethod:: Shear(plane, size, factor)\n"
"\n"
@@ -857,24 +1026,7 @@ static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
int matSize;
const char *plane;
PyObject *fac;
- float mat[16] = {
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- };
+ float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
if (!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
return NULL;
@@ -1051,205 +1203,12 @@ static PyObject *C_Matrix_LocRotScale(PyObject *cls, PyObject *args)
return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
}
-void matrix_as_3x3(float mat[3][3], MatrixObject *self)
-{
- copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
- copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1));
- copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2));
-}
-
-static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src)
-{
- BLI_assert((mat_dst->col_num == mat_src->col_num) && (mat_dst->row_num == mat_src->row_num));
- BLI_assert(mat_dst != mat_src);
+/** \} */
- memcpy(mat_dst->matrix, mat_src->matrix, sizeof(float) * (mat_dst->col_num * mat_dst->row_num));
-}
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: To Quaternion
+ * \{ */
-static void matrix_unit_internal(MatrixObject *self)
-{
- const int mat_size = sizeof(float) * (self->col_num * self->row_num);
- memset(self->matrix, 0x0, mat_size);
- const int col_row_max = min_ii(self->col_num, self->row_num);
- const int row_num = self->row_num;
- for (int col = 0; col < col_row_max; col++) {
- self->matrix[(col * row_num) + col] = 1.0f;
- }
-}
-
-/* transposes memory layout, rol/col's don't have to match */
-static void matrix_transpose_internal(float mat_dst_fl[], const MatrixObject *mat_src)
-{
- ushort col, row;
- uint i = 0;
-
- for (row = 0; row < mat_src->row_num; row++) {
- for (col = 0; col < mat_src->col_num; col++) {
- mat_dst_fl[i++] = MATRIX_ITEM(mat_src, row, col);
- }
- }
-}
-
-/* assumes rowsize == colsize is checked and the read callback has run */
-static float matrix_determinant_internal(const MatrixObject *self)
-{
- if (self->col_num == 2) {
- return determinant_m2(MATRIX_ITEM(self, 0, 0),
- MATRIX_ITEM(self, 0, 1),
- MATRIX_ITEM(self, 1, 0),
- MATRIX_ITEM(self, 1, 1));
- }
- if (self->col_num == 3) {
- return determinant_m3(MATRIX_ITEM(self, 0, 0),
- MATRIX_ITEM(self, 0, 1),
- MATRIX_ITEM(self, 0, 2),
- MATRIX_ITEM(self, 1, 0),
- MATRIX_ITEM(self, 1, 1),
- MATRIX_ITEM(self, 1, 2),
- MATRIX_ITEM(self, 2, 0),
- MATRIX_ITEM(self, 2, 1),
- MATRIX_ITEM(self, 2, 2));
- }
-
- return determinant_m4((const float(*)[4])self->matrix);
-}
-
-static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const ushort dim)
-{
- /* calculate the classical adjoint */
- switch (dim) {
- case 2: {
- adjoint_m2_m2((float(*)[2])mat_dst, (const float(*)[2])mat_src);
- break;
- }
- case 3: {
- adjoint_m3_m3((float(*)[3])mat_dst, (const float(*)[3])mat_src);
- break;
- }
- case 4: {
- adjoint_m4_m4((float(*)[4])mat_dst, (const float(*)[4])mat_src);
- break;
- }
- default:
- BLI_assert_unreachable();
- break;
- }
-}
-
-static void matrix_invert_with_det_n_internal(float *mat_dst,
- const float *mat_src,
- const float det,
- const ushort dim)
-{
- float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
- ushort i, j, k;
-
- BLI_assert(det != 0.0f);
-
- adjoint_matrix_n(mat, mat_src, dim);
-
- /* divide by determinant & set values */
- k = 0;
- for (i = 0; i < dim; i++) { /* col_num */
- for (j = 0; j < dim; j++) { /* row_num */
- mat_dst[MATRIX_ITEM_INDEX_NUMROW(dim, j, i)] = mat[k++] / det;
- }
- }
-}
-
-/**
- * \param r_mat: can be from `self->matrix` or not.
- */
-static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
-{
- float det;
- BLI_assert(self->col_num == self->row_num);
- det = matrix_determinant_internal(self);
-
- if (det != 0.0f) {
- matrix_invert_with_det_n_internal(r_mat, self->matrix, det, self->col_num);
- return true;
- }
-
- return false;
-}
-
-/**
- * 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)
-{
- float det;
- float *in_mat = self->matrix;
- BLI_assert(self->col_num == self->row_num);
- det = matrix_determinant_internal(self);
-
- if (det == 0.0f) {
- const float eps = PSEUDOINVERSE_EPSILON;
-
- /* We will copy self->matrix into r_mat (if needed),
- * and modify it in place to add diagonal epsilon. */
- in_mat = r_mat;
-
- switch (self->col_num) {
- case 2: {
- float(*mat)[2] = (float(*)[2])in_mat;
-
- if (in_mat != self->matrix) {
- copy_m2_m2(mat, (const float(*)[2])self->matrix);
- }
- mat[0][0] += eps;
- mat[1][1] += eps;
-
- if (UNLIKELY((det = determinant_m2(mat[0][0], mat[0][1], mat[1][0], mat[1][1])) == 0.0f)) {
- unit_m2(mat);
- det = 1.0f;
- }
- break;
- }
- case 3: {
- float(*mat)[3] = (float(*)[3])in_mat;
-
- if (in_mat != self->matrix) {
- copy_m3_m3(mat, (const float(*)[3])self->matrix);
- }
- mat[0][0] += eps;
- mat[1][1] += eps;
- mat[2][2] += eps;
-
- if (UNLIKELY((det = determinant_m3_array(mat)) == 0.0f)) {
- unit_m3(mat);
- det = 1.0f;
- }
- break;
- }
- case 4: {
- float(*mat)[4] = (float(*)[4])in_mat;
-
- if (in_mat != self->matrix) {
- copy_m4_m4(mat, (const float(*)[4])self->matrix);
- }
- mat[0][0] += eps;
- mat[1][1] += eps;
- mat[2][2] += eps;
- mat[3][3] += eps;
-
- if (UNLIKELY(det = determinant_m4(mat)) == 0.0f) {
- unit_m4(mat);
- det = 1.0f;
- }
- break;
- }
- default:
- BLI_assert_unreachable();
- }
- }
-
- matrix_invert_with_det_n_internal(r_mat, in_mat, det, self->col_num);
-}
-
-/*-----------------------------METHODS----------------------------*/
PyDoc_STRVAR(Matrix_to_quaternion_doc,
".. method:: to_quaternion()\n"
"\n"
@@ -1282,7 +1241,12 @@ static PyObject *Matrix_to_quaternion(MatrixObject *self)
return Quaternion_CreatePyObject(quat, NULL);
}
-/*---------------------------matrix.toEuler() --------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: To Euler
+ * \{ */
+
PyDoc_STRVAR(Matrix_to_euler_doc,
".. method:: to_euler(order, euler_compat)\n"
"\n"
@@ -1367,6 +1331,12 @@ static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
return Euler_CreatePyObject(eul, order, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Resize
+ * \{ */
+
PyDoc_STRVAR(Matrix_resize_4x4_doc,
".. method:: resize_4x4()\n"
"\n"
@@ -1411,6 +1381,12 @@ static PyObject *Matrix_resize_4x4(MatrixObject *self)
Py_RETURN_NONE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: To NxN
+ * \{ */
+
static PyObject *Matrix_to_NxN(MatrixObject *self, const int col_num, const int row_num)
{
const int mat_size = sizeof(float) * (col_num * row_num);
@@ -1480,6 +1456,12 @@ static PyObject *Matrix_to_4x4(MatrixObject *self)
return Matrix_to_NxN(self, 4, 4);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: To Translation/Scale
+ * \{ */
+
PyDoc_STRVAR(Matrix_to_translation_doc,
".. method:: to_translation()\n"
"\n"
@@ -1539,9 +1521,13 @@ static PyObject *Matrix_to_scale(MatrixObject *self)
return Vector_CreatePyObject(size, 3, NULL);
}
-/*---------------------------matrix.invert() ---------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Invert
+ * \{ */
-/* re-usable checks for invert */
+/** Re-usable checks for invert. */
static bool matrix_invert_is_compat(const MatrixObject *self)
{
if (self->col_num != self->row_num) {
@@ -1763,7 +1749,12 @@ static PyObject *Matrix_inverted_safe(MatrixObject *self)
return Matrix_copy_notest(self, mat);
}
-/*---------------------------matrix.adjugate() ---------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Adjugate
+ * \{ */
+
PyDoc_STRVAR(
Matrix_adjugate_doc,
".. method:: adjugate()\n"
@@ -1852,7 +1843,12 @@ static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
Py_RETURN_NONE;
}
-/*---------------------------matrix.decompose() ---------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Decompose
+ * \{ */
+
PyDoc_STRVAR(Matrix_decompose_doc,
".. method:: decompose()\n"
"\n"
@@ -1890,6 +1886,12 @@ static PyObject *Matrix_decompose(MatrixObject *self)
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Linear Interpolate (lerp)
+ * \{ */
+
PyDoc_STRVAR(Matrix_lerp_doc,
".. function:: lerp(other, factor)\n"
"\n"
@@ -1947,7 +1949,6 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
return Matrix_CreatePyObject(mat, self->col_num, self->row_num, Py_TYPE(self));
}
-/*---------------------------matrix.determinant() ----------------*/
PyDoc_STRVAR(
Matrix_determinant_doc,
".. method:: determinant()\n"
@@ -1973,7 +1974,13 @@ static PyObject *Matrix_determinant(MatrixObject *self)
return PyFloat_FromDouble((double)matrix_determinant_internal(self));
}
-/*---------------------------matrix.transpose() ------------------*/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Transpose
+ * \{ */
+
PyDoc_STRVAR(
Matrix_transpose_doc,
".. method:: transpose()\n"
@@ -2022,7 +2029,12 @@ static PyObject *Matrix_transposed(MatrixObject *self)
return matrix__apply_to_copy(Matrix_transpose, self);
}
-/*---------------------------matrix.normalize() ------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Normalize
+ * \{ */
+
PyDoc_STRVAR(Matrix_normalize_doc,
".. method:: normalize()\n"
"\n"
@@ -2068,7 +2080,12 @@ static PyObject *Matrix_normalized(MatrixObject *self)
return matrix__apply_to_copy(Matrix_normalize, self);
}
-/*---------------------------matrix.zero() -----------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Zero
+ * \{ */
+
PyDoc_STRVAR(Matrix_zero_doc,
".. method:: zero()\n"
"\n"
@@ -2089,7 +2106,13 @@ static PyObject *Matrix_zero(MatrixObject *self)
Py_RETURN_NONE;
}
-/*---------------------------matrix.identity(() ------------------*/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Set Identity
+ * \{ */
+
static void matrix_identity_internal(MatrixObject *self)
{
BLI_assert((self->col_num == self->row_num) && (self->row_num <= 4));
@@ -2137,8 +2160,13 @@ static PyObject *Matrix_identity(MatrixObject *self)
Py_RETURN_NONE;
}
-/*---------------------------Matrix.copy() ------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Copy
+ * \{ */
+/** Copy `Matrix.copy()` */
static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix)
{
return Matrix_CreatePyObject((const float *)matrix, self->col_num, self->row_num, Py_TYPE(self));
@@ -2159,6 +2187,8 @@ static PyObject *Matrix_copy(MatrixObject *self)
return Matrix_copy_notest(self, self->matrix);
}
+
+/** Deep-copy `Matrix.deepcopy()` */
static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args)
{
if (!PyC_CheckArgs_DeepCopy(args)) {
@@ -2167,8 +2197,12 @@ static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args)
return Matrix_copy(self);
}
-/*----------------------------print object (internal)-------------*/
-/* print the object to screen */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: `__repr__` & `__str__`
+ * \{ */
+
static PyObject *Matrix_repr(MatrixObject *self)
{
int col, row;
@@ -2257,6 +2291,12 @@ static PyObject *Matrix_str(MatrixObject *self)
}
#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Rich Compare
+ * \{ */
+
static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
{
PyObject *res;
@@ -2298,6 +2338,12 @@ static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
return Py_INCREF_RET(res);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Hash (`__hash__`)
+ * \{ */
+
static Py_hash_t Matrix_hash(MatrixObject *self)
{
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
@@ -2315,16 +2361,22 @@ static Py_hash_t Matrix_hash(MatrixObject *self)
return mathutils_array_hash(mat, self->row_num * self->col_num);
}
-/*---------------------SEQUENCE PROTOCOLS------------------------
- * ----------------------------len(object)------------------------
- * sequence length */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Sequence & Mapping Protocol Implementation
+ * \{ */
+
+/** Sequence length: `len(object)`. */
static int Matrix_len(MatrixObject *self)
{
return self->row_num;
}
-/*----------------------------object[]---------------------------
- * sequence accessor (get)
- * the wrapped vector gives direct access to the matrix data */
+
+/**
+ * Sequence accessor (get): `x = object[i]`.
+ * \note the wrapped vector gives direct access to the matrix data.
+ */
static PyObject *Matrix_item_row(MatrixObject *self, int row)
{
if (BaseMath_ReadCallback_ForWrite(self) == -1) {
@@ -2340,7 +2392,10 @@ static PyObject *Matrix_item_row(MatrixObject *self, int row)
return Vector_CreatePyObject_cb(
(PyObject *)self, self->col_num, mathutils_matrix_row_cb_index, row);
}
-/* same but column access */
+/**
+ * Sequence accessor (get): `x = object.col[i]`.
+ * \note the wrapped vector gives direct access to the matrix data.
+ */
static PyObject *Matrix_item_col(MatrixObject *self, int col)
{
if (BaseMath_ReadCallback_ForWrite(self) == -1) {
@@ -2357,9 +2412,7 @@ static PyObject *Matrix_item_col(MatrixObject *self, int col)
(PyObject *)self, self->row_num, mathutils_matrix_col_cb_index, col);
}
-/*----------------------------object[]-------------------------
- * sequence accessor (set) */
-
+/** Sequence accessor (set): `object[i] = x`. */
static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
{
int col;
@@ -2386,6 +2439,8 @@ static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
(void)BaseMath_WriteCallback(self);
return 0;
}
+
+/** Sequence accessor (set): `object.col[i] = x`. */
static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
{
int row;
@@ -2413,8 +2468,7 @@ static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
return 0;
}
-/*----------------------------object[z:y]------------------------
- * Sequence slice (get). */
+/** Sequence slice accessor (get): `x = object[i:j]`. */
static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
{
@@ -2439,8 +2493,8 @@ static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
return tuple;
}
-/*----------------------------object[z:y]------------------------
- * Sequence slice (set). */
+
+/** Sequence slice accessor (set): `object[i:j] = x`. */
static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
{
PyObject *value_fast;
@@ -2500,8 +2554,84 @@ static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *va
(void)BaseMath_WriteCallback(self);
return 0;
}
-/*------------------------NUMERIC PROTOCOLS----------------------
- *------------------------obj + obj------------------------------*/
+
+/** Sequence generic subscript (get): `x = object[...]`. */
+static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
+{
+ if (PyIndex_Check(item)) {
+ Py_ssize_t i;
+ i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ if (i < 0) {
+ i += self->row_num;
+ }
+ return Matrix_item_row(self, i);
+ }
+ if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
+ return NULL;
+ }
+
+ if (slicelength <= 0) {
+ return PyTuple_New(0);
+ }
+ if (step == 1) {
+ return Matrix_slice(self, start, stop);
+ }
+
+ PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
+ return NULL;
+ }
+
+ PyErr_Format(
+ PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+ return NULL;
+}
+
+/** Sequence generic subscript (set): `object[...] = x`. */
+static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
+{
+ if (PyIndex_Check(item)) {
+ Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ if (i < 0) {
+ i += self->row_num;
+ }
+ return Matrix_ass_item_row(self, i, value);
+ }
+ if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
+ return -1;
+ }
+
+ if (step == 1) {
+ return Matrix_ass_slice(self, start, stop, value);
+ }
+
+ PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
+ return -1;
+ }
+
+ PyErr_Format(
+ PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+ return -1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Numeric Protocol Implementation
+ * \{ */
+
+/** Addition: `object + object`. */
static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
{
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
@@ -2534,8 +2664,8 @@ static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
return Matrix_CreatePyObject(mat, mat1->col_num, mat1->row_num, Py_TYPE(mat1));
}
-/*------------------------obj - obj------------------------------
- * subtraction */
+
+/** Subtraction: `object - object`. */
static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
{
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
@@ -2568,8 +2698,8 @@ static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
return Matrix_CreatePyObject(mat, mat1->col_num, mat1->row_num, Py_TYPE(mat1));
}
-/*------------------------obj * obj------------------------------
- * element-wise multiplication */
+
+/** Multiplication (element-wise): `object * object`. */
static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
{
float tmat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
@@ -2631,8 +2761,8 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
Py_TYPE(m2)->tp_name);
return NULL;
}
-/*------------------------obj *= obj------------------------------
- * In place element-wise multiplication */
+
+/** Multiplication in-place (element-wise): `object *= object`. */
static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
{
float scalar;
@@ -2680,8 +2810,8 @@ static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
Py_INCREF(m1);
return m1;
}
-/*------------------------obj @ obj------------------------------
- * matrix multiplication */
+
+/** Multiplication (matrix multiply): `object @ object`. */
static PyObject *Matrix_matmul(PyObject *m1, PyObject *m2)
{
int vec_num;
@@ -2756,8 +2886,8 @@ static PyObject *Matrix_matmul(PyObject *m1, PyObject *m2)
Py_TYPE(m2)->tp_name);
return NULL;
}
-/*------------------------obj @= obj------------------------------
- * In place matrix multiplication */
+
+/** Multiplication in-place (matrix multiply): `object @= object`. */
static PyObject *Matrix_imatmul(PyObject *m1, PyObject *m2)
{
MatrixObject *mat1 = NULL, *mat2 = NULL;
@@ -2816,87 +2946,24 @@ static PyObject *Matrix_imatmul(PyObject *m1, PyObject *m2)
return m1;
}
-/*-----------------PROTOCOL DECLARATIONS--------------------------*/
-static PySequenceMethods Matrix_SeqMethods = {
- (lenfunc)Matrix_len, /* sq_length */
- (binaryfunc)NULL, /* sq_concat */
- (ssizeargfunc)NULL, /* sq_repeat */
- (ssizeargfunc)Matrix_item_row, /* sq_item */
- (ssizessizeargfunc)NULL, /* sq_slice, deprecated */
- (ssizeobjargproc)Matrix_ass_item_row, /* sq_ass_item */
- (ssizessizeobjargproc)NULL, /* sq_ass_slice, deprecated */
- (objobjproc)NULL, /* sq_contains */
- (binaryfunc)NULL, /* sq_inplace_concat */
- (ssizeargfunc)NULL, /* sq_inplace_repeat */
-};
-
-static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i;
- i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred()) {
- return NULL;
- }
- if (i < 0) {
- i += self->row_num;
- }
- return Matrix_item_row(self, i);
- }
- if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
- return NULL;
- }
-
- if (slicelength <= 0) {
- return PyTuple_New(0);
- }
- if (step == 1) {
- return Matrix_slice(self, start, stop);
- }
-
- PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
- return NULL;
- }
-
- PyErr_Format(
- PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
- return NULL;
-}
-
-static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred()) {
- return -1;
- }
- if (i < 0) {
- i += self->row_num;
- }
- return Matrix_ass_item_row(self, i, value);
- }
- if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
+/** \} */
- if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
- return -1;
- }
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Protocol Declarations
+ * \{ */
- if (step == 1) {
- return Matrix_ass_slice(self, start, stop, value);
- }
-
- PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
- return -1;
- }
-
- PyErr_Format(
- PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
- return -1;
-}
+static PySequenceMethods Matrix_SeqMethods = {
+ (lenfunc)Matrix_len, /*sq_length*/
+ (binaryfunc)NULL, /*sq_concat*/
+ (ssizeargfunc)NULL, /*sq_repeat*/
+ (ssizeargfunc)Matrix_item_row, /*sq_item*/
+ (ssizessizeargfunc)NULL, /*sq_slice(DEPRECATED)*/
+ (ssizeobjargproc)Matrix_ass_item_row, /*sq_ass_item*/
+ (ssizessizeobjargproc)NULL, /*sq_ass_slice(DEPRECATED)*/
+ (objobjproc)NULL, /*sq_contains*/
+ (binaryfunc)NULL, /*sq_inplace_concat*/
+ (ssizeargfunc)NULL, /*sq_inplace_repeat*/
+};
static PyMappingMethods Matrix_AsMapping = {
(lenfunc)Matrix_len,
@@ -2924,25 +2991,31 @@ static PyNumberMethods Matrix_NumMethods = {
NULL, /*nb_int*/
NULL, /*nb_reserved*/
NULL, /*nb_float*/
- NULL, /* nb_inplace_add */
- NULL, /* nb_inplace_subtract */
- (binaryfunc)Matrix_imul, /* nb_inplace_multiply */
- NULL, /* nb_inplace_remainder */
- NULL, /* nb_inplace_power */
- NULL, /* nb_inplace_lshift */
- NULL, /* nb_inplace_rshift */
- NULL, /* nb_inplace_and */
- NULL, /* nb_inplace_xor */
- NULL, /* nb_inplace_or */
- NULL, /* nb_floor_divide */
- NULL, /* nb_true_divide */
- NULL, /* nb_inplace_floor_divide */
- NULL, /* nb_inplace_true_divide */
- NULL, /* nb_index */
- (binaryfunc)Matrix_matmul, /* nb_matrix_multiply */
- (binaryfunc)Matrix_imatmul, /* nb_inplace_matrix_multiply */
+ NULL, /*nb_inplace_add*/
+ NULL, /*nb_inplace_subtract*/
+ (binaryfunc)Matrix_imul, /*nb_inplace_multiply*/
+ NULL, /*nb_inplace_remainder*/
+ NULL, /*nb_inplace_power*/
+ NULL, /*nb_inplace_lshift*/
+ NULL, /*nb_inplace_rshift*/
+ NULL, /*nb_inplace_and*/
+ NULL, /*nb_inplace_xor*/
+ NULL, /*nb_inplace_or*/
+ NULL, /*nb_floor_divide*/
+ NULL, /*nb_true_divide*/
+ NULL, /*nb_inplace_floor_divide*/
+ NULL, /*nb_inplace_true_divide*/
+ NULL, /*nb_index*/
+ (binaryfunc)Matrix_matmul, /*nb_matrix_multiply*/
+ (binaryfunc)Matrix_imatmul, /*nb_inplace_matrix_multiply*/
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Get/Set Item Implementation
+ * \{ */
+
PyDoc_STRVAR(Matrix_translation_doc, "The translation component of the matrix.\n\n:type: Vector");
static PyObject *Matrix_translation_get(MatrixObject *self, void *UNUSED(closure))
{
@@ -3099,9 +3172,12 @@ static PyObject *Matrix_is_orthogonal_axis_vectors_get(MatrixObject *self, void
return NULL;
}
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Get/Set Item Definitions
+ * \{ */
+
static PyGetSetDef Matrix_getseters[] = {
{"median_scale", (getter)Matrix_median_scale_get, (setter)NULL, Matrix_median_scale_doc, NULL},
{"translation",
@@ -3141,7 +3217,12 @@ static PyGetSetDef Matrix_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-/*-----------------------METHOD DEFINITIONS ----------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Method Definitions
+ * \{ */
+
static struct PyMethodDef Matrix_methods[] = {
/* Derived values. */
{"determinant", (PyCFunction)Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
@@ -3205,7 +3286,12 @@ static struct PyMethodDef Matrix_methods[] = {
{NULL, NULL, 0, NULL},
};
-/*------------------PY_OBECT DEFINITION--------------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Python Object Definition
+ * \{ */
+
PyDoc_STRVAR(
matrix_doc,
".. class:: Matrix([rows])\n"
@@ -3268,6 +3354,12 @@ PyTypeObject matrix_Type = {
NULL, /*tp_del*/
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: C/API Constructors
+ * \{ */
+
PyObject *Matrix_CreatePyObject(const float *mat,
const ushort col_num,
const ushort row_num,
@@ -3380,6 +3472,12 @@ PyObject *Matrix_CreatePyObject_alloc(float *mat,
return (PyObject *)self;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: C/API Parse Utilities
+ * \{ */
+
/**
* Use with PyArg_ParseTuple's "O&" formatting.
*/
@@ -3460,8 +3558,11 @@ int Matrix_Parse4x4(PyObject *o, void *p)
return 1;
}
-/* ----------------------------------------------------------------------------
- * special type for alternate access */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix-Access Type: Struct & Internal Functions
+ * \{ */
typedef struct {
PyObject_HEAD /* Required Python macro. */
@@ -3491,7 +3592,11 @@ static void MatrixAccess_dealloc(MatrixAccessObject *self)
Py_TYPE(self)->tp_free(self);
}
-/* sequence access */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix-Access Type: Sequence Protocol
+ * \{ */
static int MatrixAccess_len(MatrixAccessObject *self)
{
@@ -3609,13 +3714,13 @@ static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item,
static PyObject *MatrixAccess_iter(MatrixAccessObject *self)
{
- /* Try get values from a collection */
+ /* Try get values from a collection. */
PyObject *ret;
PyObject *iter = NULL;
ret = MatrixAccess_slice(self, 0, MATRIX_MAX_DIM);
- /* we know this is a tuple so no need to PyIter_Check
- * otherwise it could be NULL (unlikely) if conversion failed */
+ /* We know this is a tuple so no need to #PyIter_Check
+ * otherwise it could be NULL (unlikely) if conversion failed. */
if (ret) {
iter = PyObject_GetIter(ret);
Py_DECREF(ret);
@@ -3630,6 +3735,12 @@ static PyMappingMethods MatrixAccess_AsMapping = {
(objobjargproc)MatrixAccess_ass_subscript,
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix-Access Type: Python Object Definition
+ * \{ */
+
PyTypeObject matrix_access_Type = {
PyVarObject_HEAD_INIT(NULL, 0) "MatrixAccess", /*tp_name*/
sizeof(MatrixAccessObject), /*tp_basicsize*/
@@ -3658,6 +3769,12 @@ PyTypeObject matrix_access_Type = {
(getiterfunc)MatrixAccess_iter, /* getiterfunc tp_iter; */
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix-Access Type: C/API Constructor
+ * \{ */
+
static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
{
MatrixAccessObject *matrix_access = (MatrixAccessObject *)PyObject_GC_New(MatrixObject,
@@ -3671,5 +3788,4 @@ static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrix
return (PyObject *)matrix_access;
}
-/* end special access
- * -------------------------------------------------------------------------- */
+/** \} */
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index bc596ce6ac8..c8c207c13f3 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -45,7 +45,8 @@ typedef struct {
* be stored in py_data) or be a wrapper for data allocated through
* blender (stored in blend_data). This is an either/or struct not both */
-/* prototypes */
+/* Prototypes. */
+
PyObject *Matrix_CreatePyObject(const float *mat,
ushort col_num,
ushort row_num,
@@ -70,6 +71,7 @@ PyObject *Matrix_CreatePyObject_alloc(float *mat,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
/* PyArg_ParseTuple's "O&" formatting helpers. */
+
int Matrix_ParseAny(PyObject *o, void *p);
int Matrix_Parse2x2(PyObject *o, void *p);
int Matrix_Parse3x3(PyObject *o, void *p);
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 7b51154f0d0..6994a313237 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -26,9 +26,49 @@ static void quat__axis_angle_sanitize(float axis[3], float *angle);
static PyObject *Quaternion_copy(QuaternionObject *self);
static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args);
-/* -----------------------------METHODS------------------------------ */
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
-/* NOTE: BaseMath_ReadCallback must be called beforehand. */
+static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
+ QuaternionObject *self)
+{
+ PyObject *ret = Quaternion_copy(self);
+ PyObject *ret_dummy = quat_func((QuaternionObject *)ret);
+ if (ret_dummy) {
+ Py_DECREF(ret_dummy);
+ return ret;
+ }
+ /* error */
+ Py_DECREF(ret);
+ return NULL;
+}
+
+/** Axis vector suffers from precision errors, use this function to ensure. */
+static void quat__axis_angle_sanitize(float axis[3], float *angle)
+{
+ if (axis) {
+ if (is_zero_v3(axis) || !isfinite(axis[0]) || !isfinite(axis[1]) || !isfinite(axis[2])) {
+ axis[0] = 1.0f;
+ axis[1] = 0.0f;
+ axis[2] = 0.0f;
+ }
+ else if (EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && EXPP_FloatsAreEqual(axis[1], 0.0f, 10) &&
+ EXPP_FloatsAreEqual(axis[2], 0.0f, 10)) {
+ axis[0] = 1.0f;
+ }
+ }
+
+ if (angle) {
+ if (!isfinite(*angle)) {
+ *angle = 0.0f;
+ }
+ }
+}
+
+/**
+ * \note #BaseMath_ReadCallback must be called beforehand.
+ */
static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits)
{
PyObject *ret;
@@ -50,6 +90,72 @@ static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits)
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: `__new__` / `mathutils.Quaternion()`
+ * \{ */
+
+static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *seq = NULL;
+ double angle = 0.0f;
+ float quat[QUAT_SIZE];
+ unit_qt(quat);
+
+ if (kwds && PyDict_Size(kwds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "mathutils.Quaternion(): "
+ "takes no keyword args");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle)) {
+ return NULL;
+ }
+
+ switch (PyTuple_GET_SIZE(args)) {
+ case 0:
+ break;
+ case 1: {
+ int size;
+
+ if ((size = mathutils_array_parse(quat, 3, QUAT_SIZE, seq, "mathutils.Quaternion()")) ==
+ -1) {
+ return NULL;
+ }
+
+ if (size == 4) {
+ /* 4d: Quaternion (common case) */
+ }
+ else {
+ /* 3d: Interpret as exponential map */
+ BLI_assert(size == 3);
+ expmap_to_quat(quat, quat);
+ }
+
+ break;
+ }
+ case 2: {
+ float axis[3];
+ if (mathutils_array_parse(axis, 3, 3, seq, "mathutils.Quaternion()") == -1) {
+ return NULL;
+ }
+ angle = angle_wrap_rad(angle); /* clamp because of precision issues */
+ axis_angle_to_quat(quat, axis, angle);
+ break;
+ /* PyArg_ParseTuple assures no more than 2 */
+ }
+ }
+ return Quaternion_CreatePyObject(quat, type);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: To Euler
+ * \{ */
+
PyDoc_STRVAR(Quaternion_to_euler_doc,
".. method:: to_euler(order, euler_compat)\n"
"\n"
@@ -114,6 +220,12 @@ static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args)
return Euler_CreatePyObject(eul, order, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: To Matrix
+ * \{ */
+
PyDoc_STRVAR(Quaternion_to_matrix_doc,
".. method:: to_matrix()\n"
"\n"
@@ -133,6 +245,12 @@ static PyObject *Quaternion_to_matrix(QuaternionObject *self)
return Matrix_CreatePyObject(mat, 3, 3, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: To Axis/Angle
+ * \{ */
+
PyDoc_STRVAR(Quaternion_to_axis_angle_doc,
".. method:: to_axis_angle()\n"
"\n"
@@ -163,6 +281,12 @@ static PyObject *Quaternion_to_axis_angle(QuaternionObject *self)
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: To Swing/Twist
+ * \{ */
+
PyDoc_STRVAR(Quaternion_to_swing_twist_doc,
".. method:: to_swing_twist(axis)\n"
"\n"
@@ -207,6 +331,12 @@ static PyObject *Quaternion_to_swing_twist(QuaternionObject *self, PyObject *axi
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: To Exponential Map
+ * \{ */
+
PyDoc_STRVAR(
Quaternion_to_exponential_map_doc,
".. method:: to_exponential_map()\n"
@@ -232,6 +362,12 @@ static PyObject *Quaternion_to_exponential_map(QuaternionObject *self)
return Vector_CreatePyObject(expmap, 3, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Cross Product
+ * \{ */
+
PyDoc_STRVAR(Quaternion_cross_doc,
".. method:: cross(other)\n"
"\n"
@@ -259,6 +395,12 @@ static PyObject *Quaternion_cross(QuaternionObject *self, PyObject *value)
return Quaternion_CreatePyObject(quat, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Dot Product
+ * \{ */
+
PyDoc_STRVAR(Quaternion_dot_doc,
".. method:: dot(other)\n"
"\n"
@@ -285,6 +427,12 @@ static PyObject *Quaternion_dot(QuaternionObject *self, PyObject *value)
return PyFloat_FromDouble(dot_qtqt(self->quat, tquat));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Rotation Difference
+ * \{ */
+
PyDoc_STRVAR(Quaternion_rotation_difference_doc,
".. function:: rotation_difference(other)\n"
"\n"
@@ -315,6 +463,12 @@ static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject
return Quaternion_CreatePyObject(quat, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Spherical Interpolation (slerp)
+ * \{ */
+
PyDoc_STRVAR(Quaternion_slerp_doc,
".. function:: slerp(other, factor)\n"
"\n"
@@ -360,6 +514,12 @@ static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args)
return Quaternion_CreatePyObject(quat, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Rotate
+ * \{ */
+
PyDoc_STRVAR(Quaternion_rotate_doc,
".. method:: rotate(other)\n"
"\n"
@@ -423,9 +583,15 @@ static PyObject *Quaternion_make_compatible(QuaternionObject *self, PyObject *va
Py_RETURN_NONE;
}
-/* ----------------------------Quaternion.normalize()---------------- */
-/* Normalize the quaternion. This may change the angle as well as the
- * rotation axis, as all of (w, x, y, z) are scaled. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Normalize
+ *
+ * Normalize the quaternion. This may change the angle as well as the
+ * rotation axis, as all of (w, x, y, z) are scaled.
+ * \{ */
+
PyDoc_STRVAR(Quaternion_normalize_doc,
".. function:: normalize()\n"
"\n"
@@ -453,6 +619,15 @@ static PyObject *Quaternion_normalized(QuaternionObject *self)
return quat__apply_to_copy(Quaternion_normalize, self);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Invert
+ *
+ * Normalize the quaternion. This may change the angle as well as the
+ * rotation axis, as all of (w, x, y, z) are scaled.
+ * \{ */
+
PyDoc_STRVAR(Quaternion_invert_doc,
".. function:: invert()\n"
"\n"
@@ -480,6 +655,12 @@ static PyObject *Quaternion_inverted(QuaternionObject *self)
return quat__apply_to_copy(Quaternion_invert, self);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Set Identity
+ * \{ */
+
PyDoc_STRVAR(Quaternion_identity_doc,
".. function:: identity()\n"
"\n"
@@ -498,6 +679,12 @@ static PyObject *Quaternion_identity(QuaternionObject *self)
Py_RETURN_NONE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Negate
+ * \{ */
+
PyDoc_STRVAR(Quaternion_negate_doc,
".. function:: negate()\n"
"\n"
@@ -516,6 +703,12 @@ static PyObject *Quaternion_negate(QuaternionObject *self)
Py_RETURN_NONE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Conjugate
+ * \{ */
+
PyDoc_STRVAR(Quaternion_conjugate_doc,
".. function:: conjugate()\n"
"\n"
@@ -543,6 +736,12 @@ static PyObject *Quaternion_conjugated(QuaternionObject *self)
return quat__apply_to_copy(Quaternion_conjugate, self);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Copy/Deep-Copy
+ * \{ */
+
PyDoc_STRVAR(Quaternion_copy_doc,
".. function:: copy()\n"
"\n"
@@ -569,7 +768,12 @@ static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args)
return Quaternion_copy(self);
}
-/* print the object to screen */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: `__repr__` & `__str__`
+ * \{ */
+
static PyObject *Quaternion_repr(QuaternionObject *self)
{
PyObject *ret, *tuple;
@@ -608,6 +812,12 @@ static PyObject *Quaternion_str(QuaternionObject *self)
}
#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Rich Compare
+ * \{ */
+
static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
{
PyObject *res;
@@ -646,6 +856,12 @@ static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
return Py_INCREF_RET(res);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Hash (`__hash__`)
+ * \{ */
+
static Py_hash_t Quaternion_hash(QuaternionObject *self)
{
if (BaseMath_ReadCallback(self) == -1) {
@@ -659,15 +875,19 @@ static Py_hash_t Quaternion_hash(QuaternionObject *self)
return mathutils_array_hash(self->quat, QUAT_SIZE);
}
-/* ---------------------SEQUENCE PROTOCOLS------------------------ */
-/* ----------------------------len(object)------------------------ */
-/* sequence length */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Sequence & Mapping Protocols Implementation
+ * \{ */
+
+/** Sequence length: `len(object)`. */
static int Quaternion_len(QuaternionObject *UNUSED(self))
{
return QUAT_SIZE;
}
-/* ----------------------------object[]--------------------------- */
-/* sequence accessor (get) */
+
+/** Sequence accessor (get): `x = object[i]`. */
static PyObject *Quaternion_item(QuaternionObject *self, int i)
{
if (i < 0) {
@@ -687,8 +907,8 @@ static PyObject *Quaternion_item(QuaternionObject *self, int i)
return PyFloat_FromDouble(self->quat[i]);
}
-/* ----------------------------object[]------------------------- */
-/* sequence accessor (set) */
+
+/** Sequence accessor (set): `object[i] = x`. */
static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
{
float f;
@@ -724,8 +944,8 @@ static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
return 0;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (get) */
+
+/** Sequence slice accessor (get): `x = object[i:j]`. */
static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end)
{
PyObject *tuple;
@@ -749,8 +969,8 @@ static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end)
return tuple;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (set) */
+
+/** Sequence slice accessor (set): `object[i:j] = x`. */
static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq)
{
int i, size;
@@ -779,7 +999,7 @@ static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyOb
return -1;
}
- /* parsed well - now set in vector */
+ /* Parsed well, now set in vector. */
for (i = 0; i < size; i++) {
self->quat[begin + i] = quat[i];
}
@@ -788,6 +1008,7 @@ static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyOb
return 0;
}
+/** Sequence generic subscript (get): `x = object[...]`. */
static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item)
{
if (PyIndex_Check(item)) {
@@ -824,6 +1045,7 @@ static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item)
return NULL;
}
+/** Sequence generic subscript (set): `object[...] = x`. */
static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyObject *value)
{
if (PyIndex_Check(item)) {
@@ -856,9 +1078,13 @@ static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyOb
return -1;
}
-/* ------------------------NUMERIC PROTOCOLS---------------------- */
-/* ------------------------obj + obj------------------------------ */
-/* addition */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Numeric Protocol Implementation
+ * \{ */
+
+/** Addition: `object + object`. */
static PyObject *Quaternion_add(PyObject *q1, PyObject *q2)
{
float quat[QUAT_SIZE];
@@ -882,8 +1108,8 @@ static PyObject *Quaternion_add(PyObject *q1, PyObject *q2)
add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f);
return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
}
-/* ------------------------obj - obj------------------------------ */
-/* subtraction */
+
+/** Subtraction: `object - object`. */
static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2)
{
int x;
@@ -921,8 +1147,7 @@ static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar)
return Quaternion_CreatePyObject(tquat, Py_TYPE(quat));
}
-/*------------------------obj * obj------------------------------
- * multiplication */
+/** Multiplication (element-wise or scalar): `object * object`. */
static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
{
float scalar;
@@ -965,8 +1190,8 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
Py_TYPE(q2)->tp_name);
return NULL;
}
-/*------------------------obj *= obj------------------------------
- * in-place multiplication */
+
+/** Multiplication in-place (element-wise or scalar): `object *= object`. */
static PyObject *Quaternion_imul(PyObject *q1, PyObject *q2)
{
float scalar;
@@ -1005,8 +1230,8 @@ static PyObject *Quaternion_imul(PyObject *q1, PyObject *q2)
Py_INCREF(q1);
return q1;
}
-/*------------------------obj @ obj------------------------------
- * quaternion multiplication */
+
+/** Multiplication (quaternion multiply): `object @ object`. */
static PyObject *Quaternion_matmul(PyObject *q1, PyObject *q2)
{
float quat[QUAT_SIZE];
@@ -1060,8 +1285,8 @@ static PyObject *Quaternion_matmul(PyObject *q1, PyObject *q2)
Py_TYPE(q2)->tp_name);
return NULL;
}
-/*------------------------obj @= obj------------------------------
- * in-place quaternion multiplication */
+
+/** Multiplication in-place (quaternion multiply): `object @= object`. */
static PyObject *Quaternion_imatmul(PyObject *q1, PyObject *q2)
{
float quat[QUAT_SIZE];
@@ -1098,8 +1323,7 @@ static PyObject *Quaternion_imatmul(PyObject *q1, PyObject *q2)
return q1;
}
-/* -obj
- * Returns the negative of this object. */
+/** Negative (returns the negative of this object): `-object`. */
static PyObject *Quaternion_neg(QuaternionObject *self)
{
float tquat[QUAT_SIZE];
@@ -1112,18 +1336,23 @@ static PyObject *Quaternion_neg(QuaternionObject *self)
return Quaternion_CreatePyObject(tquat, Py_TYPE(self));
}
-/* -----------------PROTOCOL DECLARATIONS-------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Protocol Declarations
+ * \{ */
+
static PySequenceMethods Quaternion_SeqMethods = {
- (lenfunc)Quaternion_len, /* sq_length */
- (binaryfunc)NULL, /* sq_concat */
- (ssizeargfunc)NULL, /* sq_repeat */
- (ssizeargfunc)Quaternion_item, /* sq_item */
- (ssizessizeargfunc)NULL, /* sq_slice, deprecated */
- (ssizeobjargproc)Quaternion_ass_item, /* sq_ass_item */
- (ssizessizeobjargproc)NULL, /* sq_ass_slice, deprecated */
- (objobjproc)NULL, /* sq_contains */
- (binaryfunc)NULL, /* sq_inplace_concat */
- (ssizeargfunc)NULL, /* sq_inplace_repeat */
+ (lenfunc)Quaternion_len, /*sq_length*/
+ (binaryfunc)NULL, /*sq_concat*/
+ (ssizeargfunc)NULL, /*sq_repeat*/
+ (ssizeargfunc)Quaternion_item, /*sq_item*/
+ (ssizessizeargfunc)NULL, /*sq_slice(deprecated)*/
+ (ssizeobjargproc)Quaternion_ass_item, /*sq_ass_item*/
+ (ssizessizeobjargproc)NULL, /*sq_ass_slice(deprecated)*/
+ (objobjproc)NULL, /*sq_contains*/
+ (binaryfunc)NULL, /*sq_inplace_concat*/
+ (ssizeargfunc)NULL, /*sq_inplace_repeat*/
};
static PyMappingMethods Quaternion_AsMapping = {
@@ -1152,25 +1381,31 @@ static PyNumberMethods Quaternion_NumMethods = {
NULL, /*nb_int*/
NULL, /*nb_reserved*/
NULL, /*nb_float*/
- NULL, /* nb_inplace_add */
- NULL, /* nb_inplace_subtract */
- (binaryfunc)Quaternion_imul, /* nb_inplace_multiply */
- NULL, /* nb_inplace_remainder */
- NULL, /* nb_inplace_power */
- NULL, /* nb_inplace_lshift */
- NULL, /* nb_inplace_rshift */
- NULL, /* nb_inplace_and */
- NULL, /* nb_inplace_xor */
- NULL, /* nb_inplace_or */
- NULL, /* nb_floor_divide */
- NULL, /* nb_true_divide */
- NULL, /* nb_inplace_floor_divide */
- NULL, /* nb_inplace_true_divide */
- NULL, /* nb_index */
- (binaryfunc)Quaternion_matmul, /* nb_matrix_multiply */
- (binaryfunc)Quaternion_imatmul, /* nb_inplace_matrix_multiply */
+ NULL, /*nb_inplace_add*/
+ NULL, /*nb_inplace_subtract*/
+ (binaryfunc)Quaternion_imul, /*nb_inplace_multiply*/
+ NULL, /*nb_inplace_remainder*/
+ NULL, /*nb_inplace_power*/
+ NULL, /*nb_inplace_lshift*/
+ NULL, /*nb_inplace_rshift*/
+ NULL, /*nb_inplace_and*/
+ NULL, /*nb_inplace_xor*/
+ NULL, /*nb_inplace_or*/
+ NULL, /*nb_floor_divide*/
+ NULL, /*nb_true_divide*/
+ NULL, /*nb_inplace_floor_divide*/
+ NULL, /*nb_inplace_true_divide*/
+ NULL, /*nb_index*/
+ (binaryfunc)Quaternion_matmul, /*nb_matrix_multiply*/
+ (binaryfunc)Quaternion_imatmul, /*nb_inplace_matrix_multiply*/
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Get/Set Item Implementation
+ * \{ */
+
PyDoc_STRVAR(Quaternion_axis_doc, "Quaternion axis value.\n\n:type: float");
static PyObject *Quaternion_axis_get(QuaternionObject *self, void *type)
{
@@ -1300,98 +1535,69 @@ static int Quaternion_axis_vector_set(QuaternionObject *self,
return 0;
}
-/* ----------------------------------mathutils.Quaternion() -------------- */
-static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyObject *seq = NULL;
- double angle = 0.0f;
- float quat[QUAT_SIZE];
- unit_qt(quat);
-
- if (kwds && PyDict_Size(kwds)) {
- PyErr_SetString(PyExc_TypeError,
- "mathutils.Quaternion(): "
- "takes no keyword args");
- return NULL;
- }
-
- if (!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle)) {
- return NULL;
- }
-
- switch (PyTuple_GET_SIZE(args)) {
- case 0:
- break;
- case 1: {
- int size;
-
- if ((size = mathutils_array_parse(quat, 3, QUAT_SIZE, seq, "mathutils.Quaternion()")) ==
- -1) {
- return NULL;
- }
+/** \} */
- if (size == 4) {
- /* 4d: Quaternion (common case) */
- }
- else {
- /* 3d: Interpret as exponential map */
- BLI_assert(size == 3);
- expmap_to_quat(quat, quat);
- }
-
- break;
- }
- case 2: {
- float axis[3];
- if (mathutils_array_parse(axis, 3, 3, seq, "mathutils.Quaternion()") == -1) {
- return NULL;
- }
- angle = angle_wrap_rad(angle); /* clamp because of precision issues */
- axis_angle_to_quat(quat, axis, angle);
- break;
- /* PyArg_ParseTuple assures no more than 2 */
- }
- }
- return Quaternion_CreatePyObject(quat, type);
-}
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Get/Set Item Definitions
+ * \{ */
-static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
- QuaternionObject *self)
-{
- PyObject *ret = Quaternion_copy(self);
- PyObject *ret_dummy = quat_func((QuaternionObject *)ret);
- if (ret_dummy) {
- Py_DECREF(ret_dummy);
- return ret;
- }
- /* error */
- Py_DECREF(ret);
- return NULL;
-}
+static PyGetSetDef Quaternion_getseters[] = {
+ {"w",
+ (getter)Quaternion_axis_get,
+ (setter)Quaternion_axis_set,
+ Quaternion_axis_doc,
+ (void *)0},
+ {"x",
+ (getter)Quaternion_axis_get,
+ (setter)Quaternion_axis_set,
+ Quaternion_axis_doc,
+ (void *)1},
+ {"y",
+ (getter)Quaternion_axis_get,
+ (setter)Quaternion_axis_set,
+ Quaternion_axis_doc,
+ (void *)2},
+ {"z",
+ (getter)Quaternion_axis_get,
+ (setter)Quaternion_axis_set,
+ Quaternion_axis_doc,
+ (void *)3},
+ {"magnitude", (getter)Quaternion_magnitude_get, (setter)NULL, Quaternion_magnitude_doc, NULL},
+ {"angle",
+ (getter)Quaternion_angle_get,
+ (setter)Quaternion_angle_set,
+ Quaternion_angle_doc,
+ NULL},
+ {"axis",
+ (getter)Quaternion_axis_vector_get,
+ (setter)Quaternion_axis_vector_set,
+ Quaternion_axis_vector_doc,
+ NULL},
+ {"is_wrapped",
+ (getter)BaseMathObject_is_wrapped_get,
+ (setter)NULL,
+ BaseMathObject_is_wrapped_doc,
+ NULL},
+ {"is_frozen",
+ (getter)BaseMathObject_is_frozen_get,
+ (setter)NULL,
+ BaseMathObject_is_frozen_doc,
+ NULL},
+ {"is_valid",
+ (getter)BaseMathObject_is_valid_get,
+ (setter)NULL,
+ BaseMathObject_is_valid_doc,
+ NULL},
+ {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
+};
-/* axis vector suffers from precision errors, use this function to ensure */
-static void quat__axis_angle_sanitize(float axis[3], float *angle)
-{
- if (axis) {
- if (is_zero_v3(axis) || !isfinite(axis[0]) || !isfinite(axis[1]) || !isfinite(axis[2])) {
- axis[0] = 1.0f;
- axis[1] = 0.0f;
- axis[2] = 0.0f;
- }
- else if (EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && EXPP_FloatsAreEqual(axis[1], 0.0f, 10) &&
- EXPP_FloatsAreEqual(axis[2], 0.0f, 10)) {
- axis[0] = 1.0f;
- }
- }
+/** \} */
- if (angle) {
- if (!isfinite(*angle)) {
- *angle = 0.0f;
- }
- }
-}
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Method Definitions
+ * \{ */
-/* -----------------------METHOD DEFINITIONS ---------------------- */
static struct PyMethodDef Quaternion_methods[] = {
/* In place only. */
{"identity", (PyCFunction)Quaternion_identity, METH_NOARGS, Quaternion_identity_doc},
@@ -1446,61 +1652,12 @@ static struct PyMethodDef Quaternion_methods[] = {
{NULL, NULL, 0, NULL},
};
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
-static PyGetSetDef Quaternion_getseters[] = {
- {"w",
- (getter)Quaternion_axis_get,
- (setter)Quaternion_axis_set,
- Quaternion_axis_doc,
- (void *)0},
- {"x",
- (getter)Quaternion_axis_get,
- (setter)Quaternion_axis_set,
- Quaternion_axis_doc,
- (void *)1},
- {"y",
- (getter)Quaternion_axis_get,
- (setter)Quaternion_axis_set,
- Quaternion_axis_doc,
- (void *)2},
- {"z",
- (getter)Quaternion_axis_get,
- (setter)Quaternion_axis_set,
- Quaternion_axis_doc,
- (void *)3},
- {"magnitude", (getter)Quaternion_magnitude_get, (setter)NULL, Quaternion_magnitude_doc, NULL},
- {"angle",
- (getter)Quaternion_angle_get,
- (setter)Quaternion_angle_set,
- Quaternion_angle_doc,
- NULL},
- {"axis",
- (getter)Quaternion_axis_vector_get,
- (setter)Quaternion_axis_vector_set,
- Quaternion_axis_vector_doc,
- NULL},
- {"is_wrapped",
- (getter)BaseMathObject_is_wrapped_get,
- (setter)NULL,
- BaseMathObject_is_wrapped_doc,
- NULL},
- {"is_frozen",
- (getter)BaseMathObject_is_frozen_get,
- (setter)NULL,
- BaseMathObject_is_frozen_doc,
- NULL},
- {"is_valid",
- (getter)BaseMathObject_is_valid_get,
- (setter)NULL,
- BaseMathObject_is_valid_doc,
- NULL},
- {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
- {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
-};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Python Object Definition
+ * \{ */
-/* ------------------PY_OBECT DEFINITION-------------------------- */
PyDoc_STRVAR(quaternion_doc,
".. class:: Quaternion([seq, [angle]])\n"
"\n"
@@ -1577,6 +1734,12 @@ PyTypeObject quaternion_Type = {
NULL, /* tp_del */
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: C/API Constructors
+ * \{ */
+
PyObject *Quaternion_CreatePyObject(const float quat[4], PyTypeObject *base_type)
{
QuaternionObject *self;
@@ -1643,3 +1806,5 @@ PyObject *Quaternion_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar c
return (PyObject *)self;
}
+
+/** \} */
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.h b/source/blender/python/mathutils/mathutils_Quaternion.h
index 96e3d2e0055..c45b0a98a7b 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.h
+++ b/source/blender/python/mathutils/mathutils_Quaternion.h
@@ -20,7 +20,8 @@ typedef struct {
* be stored in py_data) or be a wrapper for data allocated through
* blender (stored in blend_data). This is an either/or struct not both */
-/* prototypes */
+/* Prototypes. */
+
PyObject *Quaternion_CreatePyObject(const float quat[4],
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
PyObject *Quaternion_CreatePyObject_wrap(float quat[4],
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index ffeb121b3d1..0c9cbd6ccfa 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -24,19 +24,108 @@
*/
#define MAX_DIMENSIONS 4
-/* Swizzle axes get packed into a single value that is used as a closure. Each
+/**
+ * Swizzle axes get packed into a single value that is used as a closure. Each
* axis uses SWIZZLE_BITS_PER_AXIS bits. The first bit (SWIZZLE_VALID_AXIS) is
- * used as a sentinel: if it is unset, the axis is not valid. */
+ * used as a sentinel: if it is unset, the axis is not valid.
+ */
#define SWIZZLE_BITS_PER_AXIS 3
#define SWIZZLE_VALID_AXIS 0x4
#define SWIZZLE_AXIS 0x3
static PyObject *Vector_copy(VectorObject *self);
static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args);
-static PyObject *Vector_to_tuple_ex(VectorObject *self, int ndigits);
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+/**
+ * Row vector multiplication - (Vector * Matrix)
+ * <pre>
+ * [x][y][z] * [1][4][7]
+ * [2][5][8]
+ * [3][6][9]
+ * </pre>
+ * \note vector/matrix multiplication is not commutative.
+ */
static int row_vector_multiplication(float r_vec[MAX_DIMENSIONS],
VectorObject *vec,
- MatrixObject *mat);
+ MatrixObject *mat)
+{
+ float vec_cpy[MAX_DIMENSIONS];
+ int row, col, z = 0, vec_num = vec->vec_num;
+
+ if (mat->row_num != vec_num) {
+ if (mat->row_num == 4 && vec_num == 3) {
+ vec_cpy[3] = 1.0f;
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "vector * matrix: matrix column size "
+ "and the vector size must be the same");
+ return -1;
+ }
+ }
+
+ if (BaseMath_ReadCallback(vec) == -1 || BaseMath_ReadCallback(mat) == -1) {
+ return -1;
+ }
+
+ memcpy(vec_cpy, vec->vec, vec_num * sizeof(float));
+
+ r_vec[3] = 1.0f;
+ /* Multiplication. */
+ for (col = 0; col < mat->col_num; col++) {
+ double dot = 0.0;
+ for (row = 0; row < mat->row_num; row++) {
+ dot += (double)(MATRIX_ITEM(mat, row, col) * vec_cpy[row]);
+ }
+ r_vec[z++] = (float)dot;
+ }
+ return 0;
+}
+
+static PyObject *vec__apply_to_copy(PyObject *(*vec_func)(VectorObject *), VectorObject *self)
+{
+ PyObject *ret = Vector_copy(self);
+ PyObject *ret_dummy = vec_func((VectorObject *)ret);
+ if (ret_dummy) {
+ Py_DECREF(ret_dummy);
+ return (PyObject *)ret;
+ }
+ /* error */
+ Py_DECREF(ret);
+ return NULL;
+}
+
+/** \note #BaseMath_ReadCallback must be called beforehand. */
+static PyObject *Vector_to_tuple_ex(VectorObject *self, int ndigits)
+{
+ PyObject *ret;
+ int i;
+
+ ret = PyTuple_New(self->vec_num);
+
+ if (ndigits >= 0) {
+ for (i = 0; i < self->vec_num; i++) {
+ PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->vec[i], ndigits)));
+ }
+ }
+ else {
+ for (i = 0; i < self->vec_num; i++) {
+ PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->vec[i]));
+ }
+ }
+
+ return ret;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: `__new__` / `mathutils.Vector()`
+ * \{ */
/**
* Supports 2D, 3D, and 4D vector objects both int and float values
@@ -82,20 +171,12 @@ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return Vector_CreatePyObject_alloc(vec, vec_num, type);
}
-static PyObject *vec__apply_to_copy(PyObject *(*vec_func)(VectorObject *), VectorObject *self)
-{
- PyObject *ret = Vector_copy(self);
- PyObject *ret_dummy = vec_func((VectorObject *)ret);
- if (ret_dummy) {
- Py_DECREF(ret_dummy);
- return (PyObject *)ret;
- }
- /* error */
- Py_DECREF(ret);
- return NULL;
-}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Class Methods
+ * \{ */
-/*-----------------------CLASS-METHODS----------------------------*/
PyDoc_STRVAR(C_Vector_Fill_doc,
".. classmethod:: Fill(size, fill=0.0)\n"
"\n"
@@ -311,7 +392,12 @@ static PyObject *C_Vector_Repeat(PyObject *cls, PyObject *args)
return Vector_CreatePyObject_alloc(vec, vec_num, (PyTypeObject *)cls);
}
-/*-----------------------------METHODS---------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Zero
+ * \{ */
+
PyDoc_STRVAR(Vector_zero_doc,
".. method:: zero()\n"
"\n"
@@ -331,6 +417,12 @@ static PyObject *Vector_zero(VectorObject *self)
Py_RETURN_NONE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Normalize
+ * \{ */
+
PyDoc_STRVAR(Vector_normalize_doc,
".. method:: normalize()\n"
"\n"
@@ -364,6 +456,12 @@ static PyObject *Vector_normalized(VectorObject *self)
return vec__apply_to_copy(Vector_normalize, self);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Resize
+ * \{ */
+
PyDoc_STRVAR(Vector_resize_doc,
".. method:: resize(size=3)\n"
"\n"
@@ -553,6 +651,13 @@ static PyObject *Vector_resize_4d(VectorObject *self)
self->vec_num = 4;
Py_RETURN_NONE;
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: To N-dimensions
+ * \{ */
+
PyDoc_STRVAR(Vector_to_2d_doc,
".. method:: to_2d()\n"
"\n"
@@ -605,6 +710,12 @@ static PyObject *Vector_to_4d(VectorObject *self)
return Vector_CreatePyObject(tvec, 4, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: To Tuple
+ * \{ */
+
PyDoc_STRVAR(Vector_to_tuple_doc,
".. method:: to_tuple(precision=-1)\n"
"\n"
@@ -614,28 +725,6 @@ PyDoc_STRVAR(Vector_to_tuple_doc,
" :type precision: int\n"
" :return: the values of the vector rounded by *precision*\n"
" :rtype: tuple\n");
-/* NOTE: BaseMath_ReadCallback must be called beforehand. */
-static PyObject *Vector_to_tuple_ex(VectorObject *self, int ndigits)
-{
- PyObject *ret;
- int i;
-
- ret = PyTuple_New(self->vec_num);
-
- if (ndigits >= 0) {
- for (i = 0; i < self->vec_num; i++) {
- PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->vec[i], ndigits)));
- }
- }
- else {
- for (i = 0; i < self->vec_num; i++) {
- PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->vec[i]));
- }
- }
-
- return ret;
-}
-
static PyObject *Vector_to_tuple(VectorObject *self, PyObject *args)
{
int ndigits = 0;
@@ -662,6 +751,12 @@ static PyObject *Vector_to_tuple(VectorObject *self, PyObject *args)
return Vector_to_tuple_ex(self, ndigits);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: To Track Quaternion
+ * \{ */
+
PyDoc_STRVAR(Vector_to_track_quat_doc,
".. method:: to_track_quat(track, up)\n"
"\n"
@@ -781,6 +876,12 @@ static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args)
return Quaternion_CreatePyObject(quat, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Orthogonal
+ * \{ */
+
PyDoc_STRVAR(
Vector_orthogonal_doc,
".. method:: orthogonal()\n"
@@ -816,12 +917,15 @@ static PyObject *Vector_orthogonal(VectorObject *self)
return Vector_CreatePyObject(vec, self->vec_num, Py_TYPE(self));
}
-/**
- * Vector.reflect(mirror): return a reflected vector on the mirror normal.
- * <pre>
- * vec - ((2 * dot(vec, mirror)) * mirror)
- * </pre>
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Reflect
+ *
+ * `Vector.reflect(mirror)`: return a reflected vector on the mirror normal:
+ * `vec - ((2 * dot(vec, mirror)) * mirror)`.
+ * \{ */
+
PyDoc_STRVAR(Vector_reflect_doc,
".. method:: reflect(mirror)\n"
"\n"
@@ -866,6 +970,12 @@ static PyObject *Vector_reflect(VectorObject *self, PyObject *value)
return Vector_CreatePyObject(reflect, self->vec_num, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Cross Product
+ * \{ */
+
PyDoc_STRVAR(Vector_cross_doc,
".. method:: cross(other)\n"
"\n"
@@ -908,6 +1018,12 @@ static PyObject *Vector_cross(VectorObject *self, PyObject *value)
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Dot Product
+ * \{ */
+
PyDoc_STRVAR(Vector_dot_doc,
".. method:: dot(other)\n"
"\n"
@@ -936,6 +1052,12 @@ static PyObject *Vector_dot(VectorObject *self, PyObject *value)
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Angle
+ * \{ */
+
PyDoc_STRVAR(
Vector_angle_doc,
".. function:: angle(other, fallback=None)\n"
@@ -1001,6 +1123,12 @@ static PyObject *Vector_angle(VectorObject *self, PyObject *args)
return PyFloat_FromDouble(saacos(dot / (sqrt(dot_self) * sqrt(dot_other))));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Angle Signed
+ * \{ */
+
PyDoc_STRVAR(
Vector_angle_signed_doc,
".. function:: angle_signed(other, fallback)\n"
@@ -1055,6 +1183,12 @@ static PyObject *Vector_angle_signed(VectorObject *self, PyObject *args)
return PyFloat_FromDouble(angle_signed_v2v2(self->vec, tvec));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Rotation Difference
+ * \{ */
+
PyDoc_STRVAR(Vector_rotation_difference_doc,
".. function:: rotation_difference(other)\n"
"\n"
@@ -1096,6 +1230,12 @@ static PyObject *Vector_rotation_difference(VectorObject *self, PyObject *value)
return Quaternion_CreatePyObject(quat, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Project
+ * \{ */
+
PyDoc_STRVAR(Vector_project_doc,
".. function:: project(other)\n"
"\n"
@@ -1134,6 +1274,12 @@ static PyObject *Vector_project(VectorObject *self, PyObject *value)
return Vector_CreatePyObject_alloc(tvec, vec_num, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Linear Interpolation
+ * \{ */
+
PyDoc_STRVAR(Vector_lerp_doc,
".. function:: lerp(other, factor)\n"
"\n"
@@ -1170,6 +1316,12 @@ static PyObject *Vector_lerp(VectorObject *self, PyObject *args)
return Vector_CreatePyObject_alloc(tvec, vec_num, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Spherical Interpolation
+ * \{ */
+
PyDoc_STRVAR(Vector_slerp_doc,
".. function:: slerp(other, factor, fallback=None)\n"
"\n"
@@ -1256,6 +1408,12 @@ static PyObject *Vector_slerp(VectorObject *self, PyObject *args)
return Vector_CreatePyObject(ret_vec, vec_num, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Rotate
+ * \{ */
+
PyDoc_STRVAR(
Vector_rotate_doc,
".. function:: rotate(other)\n"
@@ -1297,6 +1455,34 @@ static PyObject *Vector_rotate(VectorObject *self, PyObject *value)
Py_RETURN_NONE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Negate
+ * \{ */
+
+PyDoc_STRVAR(Vector_negate_doc,
+ ".. method:: negate()\n"
+ "\n"
+ " Set all values to their negative.\n");
+static PyObject *Vector_negate(VectorObject *self)
+{
+ if (BaseMath_ReadCallback(self) == -1) {
+ return NULL;
+ }
+
+ negate_vn(self->vec, self->vec_num);
+
+ (void)BaseMath_WriteCallback(self); /* already checked for error */
+ Py_RETURN_NONE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Copy/Deep-Copy
+ * \{ */
+
PyDoc_STRVAR(Vector_copy_doc,
".. function:: copy()\n"
"\n"
@@ -1323,6 +1509,12 @@ static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args)
return Vector_copy(self);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: `__repr__` & `__str__`
+ * \{ */
+
static PyObject *Vector_repr(VectorObject *self)
{
PyObject *ret, *tuple;
@@ -1362,13 +1554,124 @@ static PyObject *Vector_str(VectorObject *self)
}
#endif
-/* Sequence Protocol */
-/* sequence length len(vector) */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Rich Compare
+ * \{ */
+
+static PyObject *Vector_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+{
+ VectorObject *vecA = NULL, *vecB = NULL;
+ int result = 0;
+ const double epsilon = 0.000001f;
+ double lenA, lenB;
+
+ if (!VectorObject_Check(objectA) || !VectorObject_Check(objectB)) {
+ if (comparison_type == Py_NE) {
+ Py_RETURN_TRUE;
+ }
+
+ Py_RETURN_FALSE;
+ }
+ vecA = (VectorObject *)objectA;
+ vecB = (VectorObject *)objectB;
+
+ if (BaseMath_ReadCallback(vecA) == -1 || BaseMath_ReadCallback(vecB) == -1) {
+ return NULL;
+ }
+
+ if (vecA->vec_num != vecB->vec_num) {
+ if (comparison_type == Py_NE) {
+ Py_RETURN_TRUE;
+ }
+
+ Py_RETURN_FALSE;
+ }
+
+ switch (comparison_type) {
+ case Py_LT:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA < lenB) {
+ result = 1;
+ }
+ break;
+ case Py_LE:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA < lenB) {
+ result = 1;
+ }
+ else {
+ result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
+ }
+ break;
+ case Py_EQ:
+ result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
+ break;
+ case Py_NE:
+ result = !EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
+ break;
+ case Py_GT:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA > lenB) {
+ result = 1;
+ }
+ break;
+ case Py_GE:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA > lenB) {
+ result = 1;
+ }
+ else {
+ result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
+ }
+ break;
+ default:
+ printf("The result of the comparison could not be evaluated");
+ break;
+ }
+ if (result == 1) {
+ Py_RETURN_TRUE;
+ }
+
+ Py_RETURN_FALSE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Hash (`__hash__`)
+ * \{ */
+
+static Py_hash_t Vector_hash(VectorObject *self)
+{
+ if (BaseMath_ReadCallback(self) == -1) {
+ return -1;
+ }
+
+ if (BaseMathObject_Prepare_ForHash(self) == -1) {
+ return -1;
+ }
+
+ return mathutils_array_hash(self->vec, self->vec_num);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Sequence & Mapping Protocols Implementation
+ * \{ */
+
+/** Sequence length: `len(object)`. */
static int Vector_len(VectorObject *self)
{
return self->vec_num;
}
-/* sequence accessor (get): vector[index] */
+
static PyObject *vector_item_internal(VectorObject *self, int i, const bool is_attr)
{
if (i < 0) {
@@ -1395,11 +1698,12 @@ static PyObject *vector_item_internal(VectorObject *self, int i, const bool is_a
return PyFloat_FromDouble(self->vec[i]);
}
+/** Sequence accessor (get): `x = object[i]`. */
static PyObject *Vector_item(VectorObject *self, int i)
{
return vector_item_internal(self, i, false);
}
-/* sequence accessor (set): vector[index] = value */
+
static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value, const bool is_attr)
{
float scalar;
@@ -1442,12 +1746,13 @@ static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value,
return 0;
}
+/** Sequence accessor (set): `object[i] = x`. */
static int Vector_ass_item(VectorObject *self, int i, PyObject *value)
{
return vector_ass_item_internal(self, i, value, false);
}
-/* sequence slice (get): vector[a:b] */
+/** Sequence slice accessor (get): `x = object[i:j]`. */
static PyObject *Vector_slice(VectorObject *self, int begin, int end)
{
PyObject *tuple;
@@ -1471,7 +1776,8 @@ static PyObject *Vector_slice(VectorObject *self, int begin, int end)
return tuple;
}
-/* sequence slice (set): vector[a:b] = value */
+
+/** Sequence slice accessor (set): `object[i:j] = x`. */
static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *seq)
{
int vec_num = 0;
@@ -1509,8 +1815,83 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *se
return 0;
}
-/* Numeric Protocols */
-/* addition: obj + obj */
+/** Sequence generic subscript (get): `x = object[...]`. */
+static PyObject *Vector_subscript(VectorObject *self, PyObject *item)
+{
+ if (PyIndex_Check(item)) {
+ Py_ssize_t i;
+ i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ if (i < 0) {
+ i += self->vec_num;
+ }
+ return Vector_item(self, i);
+ }
+ if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
+ return NULL;
+ }
+
+ if (slicelength <= 0) {
+ return PyTuple_New(0);
+ }
+ if (step == 1) {
+ return Vector_slice(self, start, stop);
+ }
+
+ PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
+ return NULL;
+ }
+
+ PyErr_Format(
+ PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+ return NULL;
+}
+
+/** Sequence generic subscript (set): `object[...] = x`. */
+static int Vector_ass_subscript(VectorObject *self, PyObject *item, PyObject *value)
+{
+ if (PyIndex_Check(item)) {
+ Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ if (i < 0) {
+ i += self->vec_num;
+ }
+ return Vector_ass_item(self, i, value);
+ }
+ if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
+ return -1;
+ }
+
+ if (step == 1) {
+ return Vector_ass_slice(self, start, stop, value);
+ }
+
+ PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
+ return -1;
+ }
+
+ PyErr_Format(
+ PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+ return -1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Numeric Protocol Implementation
+ * \{ */
+
+/** Addition: `object + object`. */
static PyObject *Vector_add(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1552,7 +1933,7 @@ static PyObject *Vector_add(PyObject *v1, PyObject *v2)
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
}
-/* addition in-place: obj += obj */
+/** Addition in-place: `object += object`. */
static PyObject *Vector_iadd(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1586,7 +1967,7 @@ static PyObject *Vector_iadd(PyObject *v1, PyObject *v2)
return v1;
}
-/* subtraction: obj - obj */
+/** Subtraction: `object - object`. */
static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1627,7 +2008,7 @@ static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
}
-/* subtraction in-place: obj -= obj */
+/** Subtraction in-place: `object -= object`. */
static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1661,8 +2042,7 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
return v1;
}
-/*------------------------obj * obj------------------------------
- * multiplication */
+/* Multiply internal implementation `object * object`, `object *= object`. */
int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat)
{
@@ -1725,6 +2105,7 @@ static PyObject *vector_mul_vec(VectorObject *vec1, VectorObject *vec2)
return Vector_CreatePyObject_alloc(tvec, vec1->vec_num, Py_TYPE(vec1));
}
+/** Multiplication (element-wise or scalar): `object * object`. */
static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1776,7 +2157,7 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
return NULL;
}
-/* multiplication in-place: obj *= obj */
+/** Multiplication in-place (element-wise or scalar): `object *= object`. */
static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1830,6 +2211,7 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
return v1;
}
+/** Multiplication (matrix multiply): `object @ object`. */
static PyObject *Vector_matmul(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1893,6 +2275,7 @@ static PyObject *Vector_matmul(PyObject *v1, PyObject *v2)
return NULL;
}
+/** Multiplication in-place (matrix multiply): `object @= object`. */
static PyObject *Vector_imatmul(PyObject *v1, PyObject *v2)
{
PyErr_Format(PyExc_TypeError,
@@ -1903,7 +2286,7 @@ static PyObject *Vector_imatmul(PyObject *v1, PyObject *v2)
return NULL;
}
-/* divide: obj / obj */
+/** Division: `object / object`. */
static PyObject *Vector_div(PyObject *v1, PyObject *v2)
{
float *vec = NULL, scalar;
@@ -1950,7 +2333,7 @@ static PyObject *Vector_div(PyObject *v1, PyObject *v2)
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
}
-/* divide in-place: obj /= obj */
+/** Division in-place: `object /= object`. */
static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
{
float scalar;
@@ -1983,8 +2366,7 @@ static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
return v1;
}
-/* -obj
- * Returns the negative of this object. */
+/** Negative (returns the negative of this object): `-object`. */
static PyObject *Vector_neg(VectorObject *self)
{
float *tvec;
@@ -1998,184 +2380,25 @@ static PyObject *Vector_neg(VectorObject *self)
return Vector_CreatePyObject_alloc(tvec, self->vec_num, Py_TYPE(self));
}
-/*------------------------tp_richcmpr
- * returns -1 exception, 0 false, 1 true */
-static PyObject *Vector_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
-{
- VectorObject *vecA = NULL, *vecB = NULL;
- int result = 0;
- const double epsilon = 0.000001f;
- double lenA, lenB;
-
- if (!VectorObject_Check(objectA) || !VectorObject_Check(objectB)) {
- if (comparison_type == Py_NE) {
- Py_RETURN_TRUE;
- }
-
- Py_RETURN_FALSE;
- }
- vecA = (VectorObject *)objectA;
- vecB = (VectorObject *)objectB;
-
- if (BaseMath_ReadCallback(vecA) == -1 || BaseMath_ReadCallback(vecB) == -1) {
- return NULL;
- }
+/** \} */
- if (vecA->vec_num != vecB->vec_num) {
- if (comparison_type == Py_NE) {
- Py_RETURN_TRUE;
- }
-
- Py_RETURN_FALSE;
- }
-
- switch (comparison_type) {
- case Py_LT:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA < lenB) {
- result = 1;
- }
- break;
- case Py_LE:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA < lenB) {
- result = 1;
- }
- else {
- result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
- }
- break;
- case Py_EQ:
- result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
- break;
- case Py_NE:
- result = !EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
- break;
- case Py_GT:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA > lenB) {
- result = 1;
- }
- break;
- case Py_GE:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA > lenB) {
- result = 1;
- }
- else {
- result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
- }
- break;
- default:
- printf("The result of the comparison could not be evaluated");
- break;
- }
- if (result == 1) {
- Py_RETURN_TRUE;
- }
-
- Py_RETURN_FALSE;
-}
-
-static Py_hash_t Vector_hash(VectorObject *self)
-{
- if (BaseMath_ReadCallback(self) == -1) {
- return -1;
- }
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Protocol Declarations
+ * \{ */
- if (BaseMathObject_Prepare_ForHash(self) == -1) {
- return -1;
- }
-
- return mathutils_array_hash(self->vec, self->vec_num);
-}
-
-/*-----------------PROTCOL DECLARATIONS--------------------------*/
static PySequenceMethods Vector_SeqMethods = {
- (lenfunc)Vector_len, /* sq_length */
- (binaryfunc)NULL, /* sq_concat */
- (ssizeargfunc)NULL, /* sq_repeat */
- (ssizeargfunc)Vector_item, /* sq_item */
- NULL, /* py3 deprecated slice func */
- (ssizeobjargproc)Vector_ass_item, /* sq_ass_item */
- NULL, /* py3 deprecated slice assign func */
- (objobjproc)NULL, /* sq_contains */
- (binaryfunc)NULL, /* sq_inplace_concat */
- (ssizeargfunc)NULL, /* sq_inplace_repeat */
+ (lenfunc)Vector_len, /*sq_length*/
+ (binaryfunc)NULL, /*sq_concat*/
+ (ssizeargfunc)NULL, /*sq_repeat*/
+ (ssizeargfunc)Vector_item, /*sq_item*/
+ NULL, /*sq_slice(DEPRECATED)*/
+ (ssizeobjargproc)Vector_ass_item, /*sq_ass_item*/
+ NULL, /*sq_ass_slice(DEPRECATED)*/
+ (objobjproc)NULL, /*sq_contains*/
+ (binaryfunc)NULL, /*sq_inplace_concat */
+ (ssizeargfunc)NULL, /*sq_inplace_repeat */
};
-static PyObject *Vector_subscript(VectorObject *self, PyObject *item)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i;
- i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred()) {
- return NULL;
- }
- if (i < 0) {
- i += self->vec_num;
- }
- return Vector_item(self, i);
- }
- if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
- return NULL;
- }
-
- if (slicelength <= 0) {
- return PyTuple_New(0);
- }
- if (step == 1) {
- return Vector_slice(self, start, stop);
- }
-
- PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
- return NULL;
- }
-
- PyErr_Format(
- PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
- return NULL;
-}
-
-static int Vector_ass_subscript(VectorObject *self, PyObject *item, PyObject *value)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred()) {
- return -1;
- }
- if (i < 0) {
- i += self->vec_num;
- }
- return Vector_ass_item(self, i, value);
- }
- if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
- return -1;
- }
-
- if (step == 1) {
- return Vector_ass_slice(self, start, stop, value);
- }
-
- PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
- return -1;
- }
-
- PyErr_Format(
- PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
- return -1;
-}
-
static PyMappingMethods Vector_AsMapping = {
(lenfunc)Vector_len,
(binaryfunc)Vector_subscript,
@@ -2202,28 +2425,32 @@ static PyNumberMethods Vector_NumMethods = {
NULL, /*nb_int*/
NULL, /*nb_reserved*/
NULL, /*nb_float*/
- Vector_iadd, /* nb_inplace_add */
- Vector_isub, /* nb_inplace_subtract */
- Vector_imul, /* nb_inplace_multiply */
- NULL, /* nb_inplace_remainder */
- NULL, /* nb_inplace_power */
- NULL, /* nb_inplace_lshift */
- NULL, /* nb_inplace_rshift */
- NULL, /* nb_inplace_and */
- NULL, /* nb_inplace_xor */
- NULL, /* nb_inplace_or */
- NULL, /* nb_floor_divide */
- Vector_div, /* nb_true_divide */
- NULL, /* nb_inplace_floor_divide */
- Vector_idiv, /* nb_inplace_true_divide */
- NULL, /* nb_index */
- (binaryfunc)Vector_matmul, /* nb_matrix_multiply */
- (binaryfunc)Vector_imatmul, /* nb_inplace_matrix_multiply */
+ Vector_iadd, /*nb_inplace_add*/
+ Vector_isub, /*nb_inplace_subtract*/
+ Vector_imul, /*nb_inplace_multiply*/
+ NULL, /*nb_inplace_remainder*/
+ NULL, /*nb_inplace_power*/
+ NULL, /*nb_inplace_lshift*/
+ NULL, /*nb_inplace_rshift*/
+ NULL, /*nb_inplace_and*/
+ NULL, /*nb_inplace_xor*/
+ NULL, /*nb_inplace_or*/
+ NULL, /*nb_floor_divide*/
+ Vector_div, /*nb_true_divide*/
+ NULL, /*nb_inplace_floor_divide*/
+ Vector_idiv, /*nb_inplace_true_divide*/
+ NULL, /*nb_index*/
+ (binaryfunc)Vector_matmul, /*nb_matrix_multiply*/
+ (binaryfunc)Vector_imatmul, /*nb_inplace_matrix_multiply*/
};
-/*------------------PY_OBECT DEFINITION--------------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Get/Set Item Implementation
+ * \{ */
-/* vector axis, vector.x/y/z/w */
+/* Vector axis: `vector.x/y/z/w`. */
PyDoc_STRVAR(Vector_axis_x_doc, "Vector X axis.\n\n:type: float");
PyDoc_STRVAR(Vector_axis_y_doc, "Vector Y axis.\n\n:type: float");
@@ -2240,7 +2467,7 @@ static int Vector_axis_set(VectorObject *self, PyObject *value, void *type)
return vector_ass_item_internal(self, POINTER_AS_INT(type), value, true);
}
-/* vector.length */
+/* `Vector.length`. */
PyDoc_STRVAR(Vector_length_doc, "Vector Length.\n\n:type: float");
static PyObject *Vector_length_get(VectorObject *self, void *UNUSED(closure))
@@ -2296,7 +2523,7 @@ static int Vector_length_set(VectorObject *self, PyObject *value)
return 0;
}
-/* vector.length_squared */
+/* `Vector.length_squared`. */
PyDoc_STRVAR(Vector_length_squared_doc, "Vector length squared (v.dot(v)).\n\n:type: float");
static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(closure))
{
@@ -2503,9 +2730,12 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure
#define SWIZZLE3(a, b, c) POINTER_FROM_INT(_SWIZZLE3(a, b, c))
#define SWIZZLE4(a, b, c, d) POINTER_FROM_INT(_SWIZZLE4(a, b, c, d))
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Get/Set Item Definitions
+ * \{ */
+
static PyGetSetDef Vector_getseters[] = {
{"x", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_x_doc, (void *)0},
{"y", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_y_doc, (void *)1},
@@ -2886,68 +3116,11 @@ static PyGetSetDef Vector_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-/**
- * Row vector multiplication - (Vector * Matrix)
- * <pre>
- * [x][y][z] * [1][4][7]
- * [2][5][8]
- * [3][6][9]
- * </pre>
- * \note vector/matrix multiplication is not commutative.
- */
-static int row_vector_multiplication(float r_vec[MAX_DIMENSIONS],
- VectorObject *vec,
- MatrixObject *mat)
-{
- float vec_cpy[MAX_DIMENSIONS];
- int row, col, z = 0, vec_num = vec->vec_num;
-
- if (mat->row_num != vec_num) {
- if (mat->row_num == 4 && vec_num == 3) {
- vec_cpy[3] = 1.0f;
- }
- else {
- PyErr_SetString(PyExc_ValueError,
- "vector * matrix: matrix column size "
- "and the vector size must be the same");
- return -1;
- }
- }
-
- if (BaseMath_ReadCallback(vec) == -1 || BaseMath_ReadCallback(mat) == -1) {
- return -1;
- }
-
- memcpy(vec_cpy, vec->vec, vec_num * sizeof(float));
-
- r_vec[3] = 1.0f;
- /* Multiplication. */
- for (col = 0; col < mat->col_num; col++) {
- double dot = 0.0;
- for (row = 0; row < mat->row_num; row++) {
- dot += (double)(MATRIX_ITEM(mat, row, col) * vec_cpy[row]);
- }
- r_vec[z++] = (float)dot;
- }
- return 0;
-}
-
-/*----------------------------Vector.negate() -------------------- */
-PyDoc_STRVAR(Vector_negate_doc,
- ".. method:: negate()\n"
- "\n"
- " Set all values to their negative.\n");
-static PyObject *Vector_negate(VectorObject *self)
-{
- if (BaseMath_ReadCallback(self) == -1) {
- return NULL;
- }
-
- negate_vn(self->vec, self->vec_num);
+/** \} */
- (void)BaseMath_WriteCallback(self); /* already checked for error */
- Py_RETURN_NONE;
-}
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Method Definitions
+ * \{ */
static struct PyMethodDef Vector_methods[] = {
/* Class Methods */
@@ -3000,11 +3173,15 @@ static struct PyMethodDef Vector_methods[] = {
{NULL, NULL, 0, NULL},
};
-/**
- * NOTE: #Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Python Object Definition
+ *
+ * \note #Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing
* but this means for eg that (vec * mat) and (mat * vec)
* both get sent to Vector_mul and it needs to sort out the order
- */
+ * \{ */
PyDoc_STRVAR(vector_doc,
".. class:: Vector(seq)\n"
@@ -3098,6 +3275,12 @@ PyTypeObject vector_Type = {
NULL,
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: C/API Constructors
+ * \{ */
+
PyObject *Vector_CreatePyObject(const float *vec, const int vec_num, PyTypeObject *base_type)
{
VectorObject *self;
@@ -3190,3 +3373,5 @@ PyObject *Vector_CreatePyObject_alloc(float *vec, const int vec_num, PyTypeObjec
return (PyObject *)self;
}
+
+/** \} */
diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h
index 3bc4e9d6b6f..7006ece6bf0 100644
--- a/source/blender/python/mathutils/mathutils_Vector.h
+++ b/source/blender/python/mathutils/mathutils_Vector.h
@@ -18,7 +18,8 @@ typedef struct {
int vec_num;
} VectorObject;
-/*prototypes*/
+/* Prototypes. */
+
PyObject *Vector_CreatePyObject(const float *vec,
int vec_num,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index faa527786fd..ad57412034a 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -129,7 +129,13 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int
seq->pitch = 1.0f;
seq->scene_sound = NULL;
seq->type = type;
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+
+ if (seq->type == SEQ_TYPE_ADJUSTMENT) {
+ seq->blend_mode = SEQ_TYPE_CROSS;
+ }
+ else {
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ }
seq->strip = seq_strip_alloc(type);
seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 59d40ce840f..dda60975a96 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -770,6 +770,41 @@ void WM_operator_properties_filesel(struct wmOperatorType *ot,
eFileSel_Flag flag,
short display,
short sort);
+
+/**
+ * Tries to pass \a id to an operator via either a "session_uuid" or a "name" property defined in
+ * the properties of \a ptr. The former is preferred, since it works properly with linking and
+ * library overrides (which may both result in multiple IDs with the same name and type).
+ *
+ * Also see #WM_operator_properties_id_lookup() and
+ * #WM_operator_properties_id_lookup_from_name_or_session_uuid()
+ */
+void WM_operator_properties_id_lookup_set_from_id(PointerRNA *ptr, const ID *id);
+/**
+ * Tries to find an ID in \a bmain. There needs to be either a "session_uuid" int or "name" string
+ * property defined and set. The former has priority. See #WM_operator_properties_id_lookup() for a
+ * helper to add the properties.
+ */
+struct ID *WM_operator_properties_id_lookup_from_name_or_session_uuid(struct Main *bmain,
+ PointerRNA *ptr,
+ enum ID_Type type);
+/**
+ * Check if either the "session_uuid" or "name" property is set inside \a ptr. If this is the case
+ * the ID can be looked up by #WM_operator_properties_id_lookup_from_name_or_session_uuid().
+ */
+bool WM_operator_properties_id_lookup_is_set(PointerRNA *ptr);
+/**
+ * Adds "name" and "session_uuid" properties so the caller can tell the operator which ID to act
+ * on. See #WM_operator_properties_id_lookup_from_name_or_session_uuid(). Both properties will be
+ * hidden in the UI and not be saved over consecutive operator calls.
+ *
+ * \note New operators should probably use "session_uuid" only (set \a add_name_prop to #false),
+ * since this works properly with linked data and/or library overrides (in both cases, multiple IDs
+ * with the same name and type may be present). The "name" property is only kept to not break
+ * compatibility with old scripts using some previously existing operators.
+ */
+void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop);
+
/**
* Disable using cursor position,
* use when view operators are initialized from buttons.
@@ -939,6 +974,14 @@ bool WM_operatortype_remove(const char *idname);
* Remove memory of all previously executed tools.
*/
void WM_operatortype_last_properties_clear_all(void);
+
+void WM_operatortype_idname_visit_for_search(const struct bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
/**
* Tag all operator-properties of \a ot defined after calling this, until
* the next #WM_operatortype_props_advanced_end call (if available), with
@@ -1042,6 +1085,13 @@ void WM_menutype_freelink(struct MenuType *mt);
void WM_menutype_free(void);
bool WM_menutype_poll(struct bContext *C, struct MenuType *mt);
+void WM_menutype_idname_visit_for_search(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
/* wm_panel_type.c */
/**
@@ -1053,6 +1103,13 @@ struct PanelType *WM_paneltype_find(const char *idname, bool quiet);
bool WM_paneltype_add(struct PanelType *pt);
void WM_paneltype_remove(struct PanelType *pt);
+void WM_paneltype_idname_visit_for_search(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
/* wm_gesture_ops.c */
int WM_gesture_box_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index a98ded82a92..8f96080c810 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -683,15 +683,10 @@ void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox *
return;
}
- /* Get name from property, not asset data - it may have changed after importing to ensure
- * uniqueness (name is assumed to be set from the imported ID name). */
- char name[MAX_ID_NAME - 2];
- RNA_string_get(drop->ptr, "name", name);
- if (!name[0]) {
- return;
- }
-
- ID *id = BKE_libblock_find_name(bmain, asset_drag->id_type, name);
+ /* Try to find the imported ID. For this to work either a "session_uuid" or "name" property must
+ * have been defined (see #WM_operator_properties_id_lookup()). */
+ ID *id = WM_operator_properties_id_lookup_from_name_or_session_uuid(
+ bmain, drop->ptr, asset_drag->id_type);
if (id != NULL) {
/* Do not delete the dragged ID if it has any user, otherwise if it is a 're-used' ID it will
* cause T95636. Note that we need first to add the user that we want to remove in
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index 1fdc8bbe2c8..e3892933905 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -819,6 +819,7 @@ int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *ev
/* Toggle flipping on/off. */
gesture->use_flip = !gesture->use_flip;
gesture_straightline_apply(C, op);
+ wm_gesture_tag_redraw(win);
break;
}
case GESTURE_MODAL_SELECT: {
@@ -897,6 +898,7 @@ int WM_gesture_straightline_oneshot_modal(bContext *C, wmOperator *op, const wmE
case GESTURE_MODAL_FLIP: {
/* Toggle flip on/off. */
gesture->use_flip = !gesture->use_flip;
+ wm_gesture_tag_redraw(win);
break;
}
case GESTURE_MODAL_SELECT:
diff --git a/source/blender/windowmanager/intern/wm_menu_type.c b/source/blender/windowmanager/intern/wm_menu_type.c
index 9e50ebb1ce5..b4cf5a79cfa 100644
--- a/source/blender/windowmanager/intern/wm_menu_type.c
+++ b/source/blender/windowmanager/intern/wm_menu_type.c
@@ -99,3 +99,21 @@ bool WM_menutype_poll(bContext *C, MenuType *mt)
}
return true;
}
+
+void WM_menutype_idname_visit_for_search(const bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ const char *UNUSED(edit_text),
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, menutypes_hash) {
+ MenuType *mt = BLI_ghashIterator_getValue(&gh_iter);
+
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = mt->idname;
+ visit_params.info = mt->label;
+ visit_fn(visit_user_data, &visit_params);
+ }
+}
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 6e44246f3ef..71c948dfbb9 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -8,8 +8,12 @@
* (`WM_operator_properties_*` functions).
*/
+#include "DNA_ID_enums.h"
#include "DNA_space_types.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+
#include "BLI_math_base.h"
#include "BLI_rect.h"
@@ -222,6 +226,74 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+void WM_operator_properties_id_lookup_set_from_id(PointerRNA *ptr, const ID *id)
+{
+ PropertyRNA *prop_session_uuid = RNA_struct_find_property(ptr, "session_uuid");
+ PropertyRNA *prop_name = RNA_struct_find_property(ptr, "name");
+
+ if (prop_session_uuid) {
+ RNA_int_set(ptr, "session_uuid", (int)id->session_uuid);
+ }
+ else if (prop_name) {
+ RNA_string_set(ptr, "name", id->name + 2);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+}
+
+ID *WM_operator_properties_id_lookup_from_name_or_session_uuid(Main *bmain,
+ PointerRNA *ptr,
+ const ID_Type type)
+{
+ PropertyRNA *prop_session_uuid = RNA_struct_find_property(ptr, "session_uuid");
+ if (prop_session_uuid && RNA_property_is_set(ptr, prop_session_uuid)) {
+ const uint32_t session_uuid = (uint32_t)RNA_property_int_get(ptr, prop_session_uuid);
+ return BKE_libblock_find_session_uuid(bmain, type, session_uuid);
+ }
+
+ PropertyRNA *prop_name = RNA_struct_find_property(ptr, "name");
+ if (prop_name && RNA_property_is_set(ptr, prop_name)) {
+ char name[MAX_ID_NAME - 2];
+ RNA_property_string_get(ptr, prop_name, name);
+ return BKE_libblock_find_name(bmain, type, name);
+ }
+
+ return NULL;
+}
+
+bool WM_operator_properties_id_lookup_is_set(PointerRNA *ptr)
+{
+ return RNA_struct_property_is_set(ptr, "session_uuid") ||
+ RNA_struct_property_is_set(ptr, "name");
+}
+
+void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop)
+{
+ PropertyRNA *prop;
+
+ if (add_name_prop) {
+ prop = RNA_def_string(ot->srna,
+ "name",
+ NULL,
+ MAX_ID_NAME - 2,
+ "Name",
+ "Name of the data-block to use by the operator");
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
+ }
+
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to use by the operator",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
+}
+
static void wm_operator_properties_select_action_ex(wmOperatorType *ot,
int default_action,
const EnumPropertyItem *select_actions,
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index 8aa8469f0bc..d1c27504628 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -246,6 +246,27 @@ void WM_operatortype_last_properties_clear_all(void)
}
}
+void WM_operatortype_idname_visit_for_search(const bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ const char *UNUSED(edit_text),
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, global_ops_hash) {
+ wmOperatorType *ot = BLI_ghashIterator_getValue(&gh_iter);
+
+ char idname_py[OP_MAX_TYPENAME];
+ WM_operator_py_idname(idname_py, ot->idname);
+
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = idname_py;
+ visit_params.info = ot->name;
+ visit_fn(visit_user_data, &visit_params);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index f455f7f2719..307d3282659 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1266,6 +1266,7 @@ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short i
{
Main *bmain = CTX_data_main(C);
ID *id = NULL;
+
/* check input variables */
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
@@ -1303,19 +1304,29 @@ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short i
}
}
}
+
+ return id;
}
- else if (RNA_struct_property_is_set(op->ptr, "name")) {
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- id = BKE_libblock_find_name(bmain, idcode, name);
- if (!id) {
+
+ /* Lookup an already existing ID. */
+ id = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, idcode);
+
+ if (!id) {
+ /* Print error with the name if the name is available. */
+
+ if (RNA_struct_property_is_set(op->ptr, "name")) {
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "name", name);
BKE_reportf(
op->reports, RPT_ERROR, "%s '%s' not found", BKE_idtype_idcode_to_name(idcode), name);
return NULL;
}
- id_us_plus(id);
+
+ BKE_reportf(op->reports, RPT_ERROR, "%s not found", BKE_idtype_idcode_to_name(idcode));
+ return NULL;
}
+ id_us_plus(id);
return id;
}
@@ -1859,7 +1870,14 @@ static void WM_OT_call_menu(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
- RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
+ RNA_def_property_string_search_func_runtime(
+ prop,
+ WM_menutype_idname_visit_for_search,
+ /* Only a suggestion as menu items may be referenced from add-ons that have been disabled. */
+ (PROP_STRING_SEARCH_SORT | PROP_STRING_SEARCH_SUGGESTION));
}
static int wm_call_pie_menu_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -1891,7 +1909,14 @@ static void WM_OT_call_menu_pie(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
- RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the pie menu");
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the pie menu");
+ RNA_def_property_string_search_func_runtime(
+ prop,
+ WM_menutype_idname_visit_for_search,
+ /* Only a suggestion as menu items may be referenced from add-ons that have been disabled. */
+ (PROP_STRING_SEARCH_SORT | PROP_STRING_SEARCH_SUGGESTION));
}
static int wm_call_panel_exec(bContext *C, wmOperator *op)
@@ -1927,6 +1952,11 @@ static void WM_OT_call_panel(wmOperatorType *ot)
PropertyRNA *prop;
prop = RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
+ RNA_def_property_string_search_func_runtime(
+ prop,
+ WM_paneltype_idname_visit_for_search,
+ /* Only a suggestion as menu items may be referenced from add-ons that have been disabled. */
+ (PROP_STRING_SEARCH_SORT | PROP_STRING_SEARCH_SUGGESTION));
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "keep_open", true, "Keep Open", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/windowmanager/intern/wm_panel_type.c b/source/blender/windowmanager/intern/wm_panel_type.c
index bfcc86c38e7..860b53c1071 100644
--- a/source/blender/windowmanager/intern/wm_panel_type.c
+++ b/source/blender/windowmanager/intern/wm_panel_type.c
@@ -65,3 +65,21 @@ void WM_paneltype_clear(void)
{
BLI_ghash_free(g_paneltypes_hash, NULL, NULL);
}
+
+void WM_paneltype_idname_visit_for_search(const bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ const char *UNUSED(edit_text),
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, g_paneltypes_hash) {
+ PanelType *pt = BLI_ghashIterator_getValue(&gh_iter);
+
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = pt->idname;
+ visit_params.info = pt->label;
+ visit_fn(visit_user_data, &visit_params);
+ }
+}
diff --git a/source/tools b/source/tools
-Subproject 53b7c02a062c3d6ec6b38ce670836321b4e78fa
+Subproject ccc8fceb6bd83ffbf6e5207247fb8f76fc47a5b