Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs77
-rw-r--r--CMakeLists.txt5
-rw-r--r--GNUmakefile13
-rw-r--r--build_files/build_environment/CMakeLists.txt1
-rw-r--r--build_files/build_environment/cmake/haru.cmake46
-rw-r--r--build_files/build_environment/cmake/harvest.cmake2
-rw-r--r--build_files/build_environment/cmake/versions.cmake4
-rw-r--r--build_files/build_environment/patches/haru.diff12
-rw-r--r--build_files/cmake/Modules/FindClangTidy.cmake2
-rw-r--r--build_files/cmake/Modules/FindHaru.cmake64
-rw-r--r--build_files/cmake/Modules/GTestTesting.cmake4
-rw-r--r--build_files/cmake/config/blender_full.cmake1
-rw-r--r--build_files/cmake/config/blender_lite.cmake1
-rw-r--r--build_files/cmake/config/blender_release.cmake1
-rw-r--r--build_files/cmake/platform/platform_apple.cmake14
-rw-r--r--build_files/cmake/platform/platform_win32.cmake12
-rwxr-xr-xbuild_files/utils/make_update.py8
-rw-r--r--doc/doxygen/Doxyfile2
-rwxr-xr-xdoc/manpage/blender.1.py5
-rwxr-xr-xdoc/python_api/sphinx_doc_gen.sh2
-rw-r--r--intern/cycles/blender/addon/__init__.py1
-rw-r--r--intern/cycles/blender/blender_curves.cpp49
-rw-r--r--intern/cycles/blender/blender_device.cpp8
-rw-r--r--intern/cycles/blender/blender_geometry.cpp39
-rw-r--r--intern/cycles/blender/blender_mesh.cpp133
-rw-r--r--intern/cycles/blender/blender_object.cpp10
-rw-r--r--intern/cycles/blender/blender_particles.cpp4
-rw-r--r--intern/cycles/blender/blender_python.cpp15
-rw-r--r--intern/cycles/blender/blender_session.cpp16
-rw-r--r--intern/cycles/blender/blender_shader.cpp159
-rw-r--r--intern/cycles/blender/blender_sync.cpp46
-rw-r--r--intern/cycles/blender/blender_sync.h1
-rw-r--r--intern/cycles/blender/blender_util.h16
-rw-r--r--intern/cycles/blender/blender_volume.cpp8
-rw-r--r--intern/cycles/device/device_memory.h69
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h2
-rw-r--r--intern/cycles/kernel/osl/osl_globals.h2
-rw-r--r--intern/cycles/render/CMakeLists.txt14
-rw-r--r--intern/cycles/render/alembic.cpp1869
-rw-r--r--intern/cycles/render/alembic.h404
-rw-r--r--intern/cycles/render/attribute.cpp68
-rw-r--r--intern/cycles/render/attribute.h10
-rw-r--r--intern/cycles/render/background.cpp5
-rw-r--r--intern/cycles/render/bake.cpp20
-rw-r--r--intern/cycles/render/bake.h5
-rw-r--r--intern/cycles/render/film.cpp8
-rw-r--r--intern/cycles/render/geometry.cpp537
-rw-r--r--intern/cycles/render/geometry.h38
-rw-r--r--intern/cycles/render/hair.cpp33
-rw-r--r--intern/cycles/render/hair.h2
-rw-r--r--intern/cycles/render/image.cpp22
-rw-r--r--intern/cycles/render/image.h5
-rw-r--r--intern/cycles/render/integrator.cpp88
-rw-r--r--intern/cycles/render/integrator.h15
-rw-r--r--intern/cycles/render/light.cpp31
-rw-r--r--intern/cycles/render/light.h23
-rw-r--r--intern/cycles/render/mesh.cpp44
-rw-r--r--intern/cycles/render/mesh.h2
-rw-r--r--intern/cycles/render/object.cpp136
-rw-r--r--intern/cycles/render/object.h28
-rw-r--r--intern/cycles/render/osl.cpp6
-rw-r--r--intern/cycles/render/particles.cpp15
-rw-r--r--intern/cycles/render/particles.h6
-rw-r--r--intern/cycles/render/procedural.cpp89
-rw-r--r--intern/cycles/render/procedural.h73
-rw-r--r--intern/cycles/render/scene.cpp114
-rw-r--r--intern/cycles/render/scene.h13
-rw-r--r--intern/cycles/render/session.cpp8
-rw-r--r--intern/cycles/render/shader.cpp62
-rw-r--r--intern/cycles/render/shader.h23
-rw-r--r--intern/cycles/render/stats.cpp2
-rw-r--r--intern/cycles/render/stats.h1
-rw-r--r--intern/cycles/render/svm.cpp6
-rw-r--r--intern/cycles/render/tables.cpp15
-rw-r--r--intern/cycles/render/tables.h5
-rw-r--r--intern/cycles/util/util_array.h8
-rw-r--r--intern/ghost/intern/GHOST_DropTargetX11.h2
-rw-r--r--intern/guardedalloc/CMakeLists.txt6
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h6
-rw-r--r--intern/guardedalloc/intern/mmap_win.c294
-rw-r--r--intern/guardedalloc/mmap_win.h50
-rw-r--r--release/datafiles/splash.pngbin887863 -> 737984 bytes
-rw-r--r--release/datafiles/userdef/userdef_default.c1
-rw-r--r--release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py13
-rw-r--r--release/scripts/presets/keyconfig/blender_27x.py25
-rw-r--r--release/scripts/startup/bl_operators/wm.py24
-rw-r--r--release/scripts/startup/bl_ui/properties_data_gpencil.py13
-rw-r--r--release/scripts/startup/bl_ui/properties_data_volume.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py40
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py6
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py8
-rw-r--r--release/scripts/startup/bl_ui/space_node.py10
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py3
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py165
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py40
-rw-r--r--release/scripts/startup/nodeitems_builtins.py4
-rw-r--r--release/windows/batch/blender_debug_gpu.cmd2
-rw-r--r--source/blender/blenkernel/BKE_animsys.h3
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh3
-rw-r--r--source/blender/blenkernel/BKE_attribute_math.hh94
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh27
-rw-r--r--source/blender/blenkernel/BKE_global.h19
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h17
-rw-r--r--source/blender/blenkernel/BKE_idtype.h9
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h9
-rw-r--r--source/blender/blenkernel/BKE_main.h47
-rw-r--r--source/blender/blenkernel/BKE_node.h34
-rw-r--r--source/blender/blenkernel/BKE_screen.h44
-rw-r--r--source/blender/blenkernel/BKE_tracking.h33
-rw-r--r--source/blender/blenkernel/BKE_volume.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/intern/action.c2
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c528
-rw-r--r--source/blender/blenkernel/intern/armature.c2
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc17
-rw-r--r--source/blender/blenkernel/intern/blendfile.c4
-rw-r--r--source/blender/blenkernel/intern/bpath.c2
-rw-r--r--source/blender/blenkernel/intern/brush.c4
-rw-r--r--source/blender/blenkernel/intern/cachefile.c2
-rw-r--r--source/blender/blenkernel/intern/camera.c2
-rw-r--r--source/blender/blenkernel/intern/collection.c10
-rw-r--r--source/blender/blenkernel/intern/context.c2
-rw-r--r--source/blender/blenkernel/intern/curve.c4
-rw-r--r--source/blender/blenkernel/intern/curve_deform.c2
-rw-r--r--source/blender/blenkernel/intern/customdata.c140
-rw-r--r--source/blender/blenkernel/intern/displist.c5
-rw-r--r--source/blender/blenkernel/intern/font.c2
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc103
-rw-r--r--source/blender/blenkernel/intern/gpencil.c157
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c9
-rw-r--r--source/blender/blenkernel/intern/hair.c2
-rw-r--r--source/blender/blenkernel/intern/idprop.c104
-rw-r--r--source/blender/blenkernel/intern/image.c2
-rw-r--r--source/blender/blenkernel/intern/ipo.c2
-rw-r--r--source/blender/blenkernel/intern/key.c2
-rw-r--r--source/blender/blenkernel/intern/lattice.c2
-rw-r--r--source/blender/blenkernel/intern/lib_id.c29
-rw-r--r--source/blender/blenkernel/intern/lib_override.c324
-rw-r--r--source/blender/blenkernel/intern/lib_query.c9
-rw-r--r--source/blender/blenkernel/intern/library.c2
-rw-r--r--source/blender/blenkernel/intern/light.c2
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c2
-rw-r--r--source/blender/blenkernel/intern/linestyle.c2
-rw-r--r--source/blender/blenkernel/intern/main.c115
-rw-r--r--source/blender/blenkernel/intern/mask.c2
-rw-r--r--source/blender/blenkernel/intern/material.c2
-rw-r--r--source/blender/blenkernel/intern/mball.c2
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c2
-rw-r--r--source/blender/blenkernel/intern/movieclip.c2
-rw-r--r--source/blender/blenkernel/intern/multires.c2
-rw-r--r--source/blender/blenkernel/intern/node.c52
-rw-r--r--source/blender/blenkernel/intern/object.c25
-rw-r--r--source/blender/blenkernel/intern/object_update.c2
-rw-r--r--source/blender/blenkernel/intern/ocean.c2
-rw-r--r--source/blender/blenkernel/intern/paint.c4
-rw-r--r--source/blender/blenkernel/intern/particle.c2
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc2
-rw-r--r--source/blender/blenkernel/intern/scene.c15
-rw-r--r--source/blender/blenkernel/intern/screen.c5
-rw-r--r--source/blender/blenkernel/intern/simulation.cc2
-rw-r--r--source/blender/blenkernel/intern/sound.c2
-rw-r--r--source/blender/blenkernel/intern/speaker.c2
-rw-r--r--source/blender/blenkernel/intern/text.c2
-rw-r--r--source/blender/blenkernel/intern/texture.c2
-rw-r--r--source/blender/blenkernel/intern/tracking.c345
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c6
-rw-r--r--source/blender/blenkernel/intern/tracking_test.cc170
-rw-r--r--source/blender/blenkernel/intern/undo_system.c2
-rw-r--r--source/blender/blenkernel/intern/unit.c3
-rw-r--r--source/blender/blenkernel/intern/volume.cc32
-rw-r--r--source/blender/blenkernel/intern/workspace.c2
-rw-r--r--source/blender/blenkernel/intern/world.c2
-rw-r--r--source/blender/blenkernel/nla_private.h4
-rw-r--r--source/blender/blenlib/BLI_fileops.h2
-rw-r--r--source/blender/blenlib/BLI_float2.hh13
-rw-r--r--source/blender/blenlib/BLI_fnmatch.h2
-rw-r--r--source/blender/blenlib/BLI_math.h3
-rw-r--r--source/blender/blenlib/BLI_math_base.h3
-rw-r--r--source/blender/blenlib/BLI_math_bits.h3
-rw-r--r--source/blender/blenlib/BLI_math_color.h3
-rw-r--r--source/blender/blenlib/BLI_math_color_blend.h3
-rw-r--r--source/blender/blenlib/BLI_math_geom.h8
-rw-r--r--source/blender/blenlib/BLI_math_inline.h3
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h2
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h3
-rw-r--r--source/blender/blenlib/BLI_math_solvers.h2
-rw-r--r--source/blender/blenlib/BLI_math_statistics.h2
-rw-r--r--source/blender/blenlib/BLI_math_vector.h3
-rw-r--r--source/blender/blenlib/BLI_mmap.h56
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/BLI_mmap.c237
-rw-r--r--source/blender/blenlib/intern/bitmap_draw_2d.c3
-rw-r--r--source/blender/blenlib/intern/boxpack_2d.c3
-rw-r--r--source/blender/blenlib/intern/list_sort_impl.h2
-rw-r--r--source/blender/blenlib/intern/math_base.c3
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c3
-rw-r--r--source/blender/blenlib/intern/math_bits_inline.c3
-rw-r--r--source/blender/blenlib/intern/math_boolean.cc2
-rw-r--r--source/blender/blenlib/intern/math_color.c3
-rw-r--r--source/blender/blenlib/intern/math_color_blend_inline.c3
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c3
-rw-r--r--source/blender/blenlib/intern/math_geom.c62
-rw-r--r--source/blender/blenlib/intern/math_geom_inline.c3
-rw-r--r--source/blender/blenlib/intern/math_rotation.c2
-rw-r--r--source/blender/blenlib/intern/math_solvers.c2
-rw-r--r--source/blender/blenlib/intern/math_statistics.c2
-rw-r--r--source/blender/blenlib/intern/math_vector.c3
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c3
-rw-r--r--source/blender/blenlib/intern/path_util.c2
-rw-r--r--source/blender/blenlib/intern/system_win32.c1
-rw-r--r--source/blender/blenlib/intern/threads.cc5
-rw-r--r--source/blender/blenlib/intern/voxel.c8
-rw-r--r--source/blender/blenloader/intern/readfile.c68
-rw-r--r--source/blender/blenloader/intern/readfile.h4
-rw-r--r--source/blender/blenloader/intern/versioning_290.c80
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c10
-rw-r--r--source/blender/bmesh/bmesh_class.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c173
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c3
-rw-r--r--source/blender/compositor/operations/COM_BokehImageOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_DotproductOperation.cpp2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc26
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.h4
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c11
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_fx.c8
-rw-r--r--source/blender/draw/engines/overlay/overlay_gpencil.c15
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c8
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c2
-rw-r--r--source/blender/draw/intern/shaders/common_fxaa_lib.glsl2
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c65
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c8
-rw-r--r--source/blender/editors/animation/keyframing.c2
-rw-r--r--source/blender/editors/animation/time_scrub_ui.c33
-rw-r--r--source/blender/editors/armature/armature_add.c3
-rw-r--r--source/blender/editors/armature/pose_slide.c18
-rw-r--r--source/blender/editors/curve/editcurve_select.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c11
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c29
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c24
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c22
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h16
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c16
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c19
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c22
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_trace_ops.c15
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c22
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c67
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c25
-rw-r--r--source/blender/editors/include/ED_clip.h24
-rw-r--r--source/blender/editors/include/ED_gpencil.h10
-rw-r--r--source/blender/editors/include/ED_mask.h5
-rw-r--r--source/blender/editors/include/ED_node.h4
-rw-r--r--source/blender/editors/include/ED_object.h2
-rw-r--r--source/blender/editors/include/ED_screen.h44
-rw-r--r--source/blender/editors/include/ED_transform.h3
-rw-r--r--source/blender/editors/include/UI_interface.h76
-rw-r--r--source/blender/editors/include/UI_view2d.h2
-rw-r--r--source/blender/editors/interface/interface.c6
-rw-r--r--source/blender/editors/interface/interface_draw.c726
-rw-r--r--source/blender/editors/interface/interface_handlers.c15
-rw-r--r--source/blender/editors/interface/interface_icons_event.c10
-rw-r--r--source/blender/editors/interface/interface_panel.c68
-rw-r--r--source/blender/editors/interface/interface_region_popup.c9
-rw-r--r--source/blender/editors/interface/interface_region_search.c22
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c80
-rw-r--r--source/blender/editors/interface/interface_style.c17
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.c1
-rw-r--r--source/blender/editors/interface/interface_templates.c29
-rw-r--r--source/blender/editors/interface/interface_widgets.c30
-rw-r--r--source/blender/editors/interface/view2d.c2
-rw-r--r--source/blender/editors/interface/view2d_ops.c112
-rw-r--r--source/blender/editors/lattice/editlattice_select.c2
-rw-r--r--source/blender/editors/mask/mask_add.c10
-rw-r--r--source/blender/editors/mask/mask_edit.c36
-rw-r--r--source/blender/editors/mask/mask_intern.h15
-rw-r--r--source/blender/editors/mask/mask_ops.c47
-rw-r--r--source/blender/editors/mask/mask_query.c23
-rw-r--r--source/blender/editors/mask/mask_select.c13
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c5
-rw-r--r--source/blender/editors/mesh/editmesh_select.c2
-rw-r--r--source/blender/editors/metaball/mball_edit.c2
-rw-r--r--source/blender/editors/object/object_add.c4
-rw-r--r--source/blender/editors/object/object_relations.c33
-rw-r--r--source/blender/editors/object/object_select.c2
-rw-r--r--source/blender/editors/object/object_transform.c2
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c5
-rw-r--r--source/blender/editors/render/render_preview.c21
-rw-r--r--source/blender/editors/screen/area.c93
-rw-r--r--source/blender/editors/screen/area_utils.c13
-rw-r--r--source/blender/editors/screen/glutil.c20
-rw-r--r--source/blender/editors/screen/screen_context.c2
-rw-r--r--source/blender/editors/screen/screen_edit.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c5
-rw-r--r--source/blender/editors/space_action/space_action.c72
-rw-r--r--source/blender/editors/space_api/spacetypes.c70
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c40
-rw-r--r--source/blender/editors/space_clip/clip_editor.c160
-rw-r--r--source/blender/editors/space_clip/clip_intern.h8
-rw-r--r--source/blender/editors/space_clip/clip_ops.c14
-rw-r--r--source/blender/editors/space_clip/clip_utils.c226
-rw-r--r--source/blender/editors/space_clip/space_clip.c64
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c114
-rw-r--r--source/blender/editors/space_clip/tracking_select.c18
-rw-r--r--source/blender/editors/space_console/space_console.c10
-rw-r--r--source/blender/editors/space_file/file_draw.c10
-rw-r--r--source/blender/editors/space_file/filelist.c17
-rw-r--r--source/blender/editors/space_file/space_file.c93
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c18
-rw-r--r--source/blender/editors/space_graph/space_graph.c30
-rw-r--r--source/blender/editors/space_image/image_ops.c2
-rw-r--r--source/blender/editors/space_image/space_image.c42
-rw-r--r--source/blender/editors/space_info/space_info.c29
-rw-r--r--source/blender/editors/space_info/textview.c17
-rw-r--r--source/blender/editors/space_nla/nla_draw.c26
-rw-r--r--source/blender/editors/space_nla/space_nla.c62
-rw-r--r--source/blender/editors/space_node/drawnode.c133
-rw-r--r--source/blender/editors/space_node/node_add.c30
-rw-r--r--source/blender/editors/space_node/node_draw.c128
-rw-r--r--source/blender/editors/space_node/node_edit.c4
-rw-r--r--source/blender/editors/space_node/node_intern.h45
-rw-r--r--source/blender/editors/space_node/node_relationships.c16
-rw-r--r--source/blender/editors/space_node/node_select.c5
-rw-r--r--source/blender/editors/space_node/space_node.c69
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c47
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c237
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c30
-rw-r--r--source/blender/editors/space_script/space_script.c7
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c21
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c47
-rw-r--r--source/blender/editors/space_statusbar/space_statusbar.c20
-rw-r--r--source/blender/editors/space_text/space_text.c7
-rw-r--r--source/blender/editors/space_text/text_draw.c26
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c30
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c34
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c101
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c31
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate.c26
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c620
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c42
-rw-r--r--source/blender/editors/transform/transform_constraints.c130
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c12
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c221
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_skin.c4
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c246
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.c394
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c2
-rw-r--r--source/blender/editors/transform/transform_orientations.c24
-rw-r--r--source/blender/editors/transform/transform_snap.c118
-rw-r--r--source/blender/editors/undo/ed_undo.c234
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp13
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h4
-rw-r--r--source/blender/freestyle/intern/geometry/GeomUtils.cpp4
-rw-r--r--source/blender/freestyle/intern/geometry/matrix_util.cpp2
-rw-r--r--source/blender/freestyle/intern/geometry/matrix_util.h2
-rw-r--r--source/blender/freestyle/intern/geometry/normal_cycle.cpp2
-rw-r--r--source/blender/freestyle/intern/geometry/normal_cycle.h2
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.cpp2
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.h2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c36
-rw-r--r--source/blender/gpu/GPU_platform.h1
-rw-r--r--source/blender/gpu/intern/gpu_state.cc5
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.cc2
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc20
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp2
-rw-r--r--source/blender/imbuf/intern/IMB_allocimbuf.h2
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c2
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.h2
-rw-r--r--source/blender/imbuf/intern/filter.c2
-rw-r--r--source/blender/imbuf/intern/readimage.c24
-rw-r--r--source/blender/io/alembic/exporter/abc_archive.cc2
-rw-r--r--source/blender/io/common/IO_dupli_persistent_id.hh2
-rw-r--r--source/blender/makesdna/DNA_ID.h12
-rw-r--r--source/blender/makesdna/DNA_brush_types.h9
-rw-r--r--source/blender/makesdna/DNA_dynamicpaint_types.h6
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h2
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h11
-rw-r--r--source/blender/makesdna/DNA_modifier_defaults.h4
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h6
-rw-r--r--source/blender/makesdna/DNA_node_types.h36
-rw-r--r--source/blender/makesdna/DNA_space_types.h38
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h12
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h8
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt6
-rw-r--r--source/blender/makesdna/intern/makesdna.c17
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt1
-rw-r--r--source/blender/makesrna/intern/makesrna.c11
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c12
-rw-r--r--source/blender/makesrna/intern/rna_brush.c10
-rw-r--r--source/blender/makesrna/intern/rna_define.c10
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c51
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c9
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c56
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c81
-rw-r--r--source/blender/makesrna/intern/rna_object.c10
-rw-r--r--source/blender/makesrna/intern/rna_render.c8
-rw-r--r--source/blender/makesrna/intern/rna_rna.c50
-rw-r--r--source/blender/makesrna/intern/rna_space.c30
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c16
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c5
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc12
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c4
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c157
-rw-r--r--source/blender/nodes/CMakeLists.txt9
-rw-r--r--source/blender/nodes/NOD_geometry.h2
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh16
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc172
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc107
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_object_info.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc190
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_instance.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc259
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc50
-rw-r--r--source/blender/nodes/intern/node_tree_multi_function.cc58
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c52
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c3
-rw-r--r--source/blender/python/intern/bpy_app.c5
-rw-r--r--source/blender/python/intern/bpy_interface.c20
-rw-r--r--source/blender/python/intern/bpy_rna.c10
-rw-r--r--source/blender/render/RE_engine.h1
-rw-r--r--source/blender/render/RE_pipeline.h2
-rw-r--r--source/blender/render/intern/initrender.c35
-rw-r--r--source/blender/render/intern/multires_bake.c2
-rw-r--r--source/blender/render/intern/pipeline.c72
-rw-r--r--source/blender/sequencer/intern/image_cache.c180
-rw-r--r--source/blender/sequencer/intern/image_cache.h9
-rw-r--r--source/blender/sequencer/intern/prefetch.c8
-rw-r--r--source/blender/sequencer/intern/render.c26
-rw-r--r--source/blender/windowmanager/WM_api.h1
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h2
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_types.h8
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c2
-rw-r--r--source/blender/windowmanager/gizmo/wm_gizmo_fn.h3
-rw-r--r--source/blender/windowmanager/intern/wm.c2
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c3
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c11
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c32
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c18
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c5
-rw-r--r--source/creator/creator_args.c16
462 files changed, 11841 insertions, 5862 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index d864e08c953..0cad9be4693 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -10,8 +10,9 @@
# Changes that belong here:
# - Massive comment, doxy-sections, or spelling corrections.
# - Clang-format, PEP8 or other automated changes which are *strictly* "no functional change".
-# - Several smaller commits should be added to this list at once, because adding
-# one extra commit (to edit this file) after every small cleanup is noisy.
+# - Several commits should be added to this list at once, because adding
+# one extra commit (to edit this file) after every cleanup is noisy.
+# - No clang-tidy changes.
#
# Note:
# - The comment above the SHA should be the first line of the commit.
@@ -92,78 +93,12 @@ c42a6b77b52560d257279de2cb624b4ef2c0d24c
# Cleanup: use doxy sections for imbuf
c207f7c22e1439e0b285fba5d2c072bdae23f981
-# Cleanup: Clang-Tidy, modernize-use-bool-literals
-af35ada2f3fa8da4d46b3a71de724d353d716820
-
-# Cleanup: Use nullptr everywhere in fluid code
-311031ecd03dbfbf43e1df672a395f24b2e7d4d3
-
-# Cleanup: Clang-Tidy, modernize-redundant-void-arg
-a331d5c99299c4514ca33c843b1c79b872f2728d
-
-# Cleanup: Clang-Tidy modernize-use-nullptr
-16732def37c5a66f3ea28dbe247b09cc6bca6677
-
-# Cleanup: Clang-tidy, modernize-concat-nested-namespaces
-4525049aa0cf818f6483dce589ac9791eb562338
-
-# Cleanup: Clang-tidy else-after-return
-ae342ed4511cf2e144dcd27ce2c635d3d536f9ad
-
-# Cleanup: Clang-Tidy, readability-redundant-member-init
-190170d4cc92ff34abe1744a10474ac4f1074086
-
-# Cleanup: use 'filepath' instead of 'name' for ImBuf utilities
-99f56b4c16323f96c0cbf54e392fb509fcac5bda
-
# Cleanup: clang-format
c4d8f6a4a8ddc29ed27311ed7578b3c8c31399d2
b5d310b569e07a937798a2d38539cfd290149f1c
8c846cccd6bdfd3e90a695fabbf05f53e5466a57
-40d4a4cb1a6b4c3c2a486e8f2868f547530e0811
4eac03d821fa17546f562485f7d073813a5e5943
+1166110a9d66af9c5a47cee2be591f50fdc445e8
-# Cleanup: use preprocessor version check for PyTypeObject declaration
-cd9acfed4f7674b84be965d469a367aef96f8af3
-
-# Cycles: fix compilation of OSL shaders following API change
-b980cd163a9d5d77eeffc2e353333e739fa9e719
-
-# Cleanup: clang-tidy suppress warnings for PyTypeObject.tp_print
-efd71aad4f22ec0073d80b8dd296015d3f395aa8
-
-# Cleanup: fix wrong merge, remove extra unique_ptr.
-6507449e54a167c63a72229e4d0119dd2af68ae5
-
-# Cleanup: fix some clang tidy issues
-525a042c5c7513c41240b118acca002f6c60cc12
-
-# Fix T82520: error building freestyle with Python3.8
-e118426e4695a97d67e65d69677f3c4e2db50a56
-
-# Cleanup: Clang-tidy, readability-else-after-return
-7be47dadea5066ae095c644e0b4f1f10d75f5ab3
-
-# Cleanup: Add `r_` to return parameter
-45dca05b1cd2a5ead59144c93d790fdfe7c35ee6
-
-# Cleanup: Typo in `print_default_info` function name.
-41a73909dec716642f044e60b40a28335c9fdb10
-
-# Cleanup: Reduce indentation
-1cc3a0e2cf73a5ff4f9e0a7f5338eda77266b300
-
-# Build-system: Force C linkage for all DNA type headers
-ad4b7741dba45a2be210942c18af6b6e4438f129
-
-# Cleanup: Move function to proper section
-c126e27cdc8b28365a9d5f9fafc4d521d1eb83df
-
-# Cleanup: remove break after return statements
-bbdfeb751e16d939482d2e4b95c4d470f53f18a5
-
-# Cleanup: clang-tidy
-af013ff76feef7e8b8ba642279c62a5dc275d59f
-
-# Cleanup: Make panel type flag names more clear
-9d28353b525ecfbcca1501be72e4276dfb2bbc2a
+# Cleanup: clang-format.
+40d4a4cb1a6b4c3c2a486e8f2868f547530e0811
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 035cf81e1b3..bc19ca4393f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -205,6 +205,7 @@ option(WITH_OPENVDB_BLOSC "Enable blosc compression for OpenVDB, only enable if
option(WITH_OPENVDB_3_ABI_COMPATIBLE "Assume OpenVDB library has been compiled with version 3 ABI compatibility" OFF)
mark_as_advanced(WITH_OPENVDB_3_ABI_COMPATIBLE)
option(WITH_NANOVDB "Enable usage of NanoVDB data structure for rendering on the GPU" ON)
+option(WITH_HARU "Enable features relying on Libharu (Grease pencil PDF export)" ON)
# GHOST Windowing Library Options
option(WITH_GHOST_DEBUG "Enable debugging output for the GHOST library" OFF)
@@ -730,6 +731,9 @@ set_and_warn_dependency(WITH_OPENVDB WITH_NANOVDB OFF)
# OpenVDB uses 'half' type from OpenEXR & fails to link without OpenEXR enabled.
set_and_warn_dependency(WITH_IMAGE_OPENEXR WITH_OPENVDB OFF)
+# Haru needs `TIFFFaxBlackCodes` & `TIFFFaxWhiteCodes` symbols from TIFF.
+set_and_warn_dependency(WITH_IMAGE_TIFF WITH_HARU OFF)
+
# auto enable openimageio for cycles
if(WITH_CYCLES)
set(WITH_OPENIMAGEIO ON)
@@ -1849,6 +1853,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_FFTW3)
info_cfg_option(WITH_FREESTYLE)
info_cfg_option(WITH_GMP)
+ info_cfg_option(WITH_HARU)
info_cfg_option(WITH_IK_ITASC)
info_cfg_option(WITH_IK_SOLVER)
info_cfg_option(WITH_INPUT_NDOF)
diff --git a/GNUmakefile b/GNUmakefile
index 3b5b9d65521..98463891407 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -183,8 +183,13 @@ endif
ifndef DEPS_INSTALL_DIR
DEPS_INSTALL_DIR:=$(shell dirname "$(BLENDER_DIR)")/lib/$(OS_NCASE)
- ifneq ($(OS_NCASE),darwin)
- # Add processor type to directory name
+ # Add processor type to directory name, except for darwin x86_64
+ # which by convention does not have it.
+ ifeq ($(OS_NCASE),darwin)
+ ifneq ($(CPU),x86_64)
+ DEPS_INSTALL_DIR:=$(DEPS_INSTALL_DIR)_$(CPU)
+ endif
+ else
DEPS_INSTALL_DIR:=$(DEPS_INSTALL_DIR)_$(CPU)
endif
endif
@@ -198,7 +203,7 @@ endif
# in libraries, or python 2 for running make update to get it.
ifeq ($(OS_NCASE),darwin)
ifeq (, $(shell command -v $(PYTHON)))
- PYTHON:=../lib/darwin/python/bin/python3.7m
+ PYTHON:=$(DEPS_INSTALL_DIR)/python/bin/python3.7m
ifeq (, $(shell command -v $(PYTHON)))
PYTHON:=python
endif
@@ -520,7 +525,7 @@ format: .FORCE
# Simple version of ./doc/python_api/sphinx_doc_gen.sh with no PDF generation.
doc_py: .FORCE
- ASAN_OPTIONS=halt_on_error=0 \
+ ASAN_OPTIONS=halt_on_error=0:${ASAN_OPTIONS} \
$(BLENDER_BIN) --background -noaudio --factory-startup \
--python doc/python_api/sphinx_doc_gen.py
sphinx-build -b html -j $(NPROCS) doc/python_api/sphinx-in doc/python_api/sphinx-out
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index dfbb0e824a0..672f5820a16 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -92,6 +92,7 @@ include(cmake/package_python.cmake)
include(cmake/numpy.cmake)
include(cmake/usd.cmake)
include(cmake/potrace.cmake)
+include(cmake/haru.cmake)
# Boost needs to be included after python.cmake due to the PYTHON_BINARY variable being needed.
include(cmake/boost.cmake)
include(cmake/pugixml.cmake)
diff --git a/build_files/build_environment/cmake/haru.cmake b/build_files/build_environment/cmake/haru.cmake
new file mode 100644
index 00000000000..7382095f459
--- /dev/null
+++ b/build_files/build_environment/cmake/haru.cmake
@@ -0,0 +1,46 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(HARU_EXTRA_ARGS
+ -DLIBHPDF_SHARED=OFF
+ -DLIBHPDF_STATIC=ON
+ -DLIBHPDF_EXAMPLES=OFF
+ -DLIBHPDF_ENABLE_EXCEPTIONS=ON
+)
+
+ExternalProject_Add(external_haru
+ URL ${HARU_URI}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH MD5=${HARU_HASH}
+ PREFIX ${BUILD_DIR}/haru
+ PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/haru/src/external_haru < ${PATCH_DIR}/haru.diff
+ CMAKE_ARGS
+ -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${LIBDIR}/haru
+ ${DEFAULT_CMAKE_FLAGS} ${HARU_EXTRA_ARGS}
+ INSTALL_DIR ${LIBDIR}/haru
+)
+
+if(WIN32)
+ if(BUILD_MODE STREQUAL Release)
+ ExternalProject_Add_Step(external_haru after_install
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/haru/include ${HARVEST_TARGET}/haru/include
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/haru/lib/libhpdfs.lib ${HARVEST_TARGET}/haru/lib/libhpdfs.lib
+ DEPENDEES install
+ )
+ endif()
+endif()
diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake
index 536907f563d..6785b727a69 100644
--- a/build_files/build_environment/cmake/harvest.cmake
+++ b/build_files/build_environment/cmake/harvest.cmake
@@ -187,6 +187,8 @@ harvest(usd/lib/usd usd/lib/usd "*")
harvest(usd/plugin usd/plugin "*")
harvest(potrace/include potrace/include "*.h")
harvest(potrace/lib potrace/lib "*.a")
+harvest(haru/include haru/include "*.h")
+harvest(haru/lib haru/lib "*.a")
if(UNIX AND NOT APPLE)
harvest(libglu/lib mesa/lib "*.so*")
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index d4a2c715ecc..8d3793ef242 100644
--- a/build_files/build_environment/cmake/versions.cmake
+++ b/build_files/build_environment/cmake/versions.cmake
@@ -331,3 +331,7 @@ set(GMP_HASH a325e3f09e6d91e62101e59f9bda3ec1)
set(POTRACE_VERSION 1.16)
set(POTRACE_URI http://potrace.sourceforge.net/download/${POTRACE_VERSION}/potrace-${POTRACE_VERSION}.tar.gz)
set(POTRACE_HASH 5f0bd87ddd9a620b0c4e65652ef93d69)
+
+set(HARU_VERSION 2_3_0)
+set(HARU_URI https://github.com/libharu/libharu/archive/RELEASE_${HARU_VERSION}.tar.gz)
+set(HARU_HASH 4f916aa49c3069b3a10850013c507460)
diff --git a/build_files/build_environment/patches/haru.diff b/build_files/build_environment/patches/haru.diff
new file mode 100644
index 00000000000..fed551b4bf0
--- /dev/null
+++ b/build_files/build_environment/patches/haru.diff
@@ -0,0 +1,12 @@
+diff --git a/src/hpdf_image_ccitt.c b/src/hpdf_image_ccitt.c
+index 8672763..9be531a 100644
+--- a/src/hpdf_image_ccitt.c
++++ b/src/hpdf_image_ccitt.c
+@@ -21,7 +21,6 @@
+ #include <memory.h>
+ #include <assert.h>
+
+-#define G3CODES
+ #include "t4.h"
+
+ typedef unsigned int uint32;
diff --git a/build_files/cmake/Modules/FindClangTidy.cmake b/build_files/cmake/Modules/FindClangTidy.cmake
index 04c5dfda448..4cf416e67d7 100644
--- a/build_files/cmake/Modules/FindClangTidy.cmake
+++ b/build_files/cmake/Modules/FindClangTidy.cmake
@@ -34,6 +34,8 @@ set(_clang_tidy_SEARCH_DIRS
# TODO(sergey): Find more reliable way of finding the latest clang-tidy.
find_program(CLANG_TIDY_EXECUTABLE
NAMES
+ clang-tidy-12
+ clang-tidy-11
clang-tidy-10
clang-tidy-9
clang-tidy-8
diff --git a/build_files/cmake/Modules/FindHaru.cmake b/build_files/cmake/Modules/FindHaru.cmake
new file mode 100644
index 00000000000..5774f83b8c5
--- /dev/null
+++ b/build_files/cmake/Modules/FindHaru.cmake
@@ -0,0 +1,64 @@
+# - Find HARU library
+# Find the native Haru includes and library
+# This module defines
+# HARU_INCLUDE_DIRS, where to find hpdf.h, set when
+# HARU_INCLUDE_DIR is found.
+# HARU_LIBRARIES, libraries to link against to use Haru.
+# HARU_ROOT_DIR, The base directory to search for Haru.
+# This can also be an environment variable.
+# HARU_FOUND, If false, do not try to use Haru.
+#
+# also defined, but not for general use are
+# HARU_LIBRARY, where to find the Haru library.
+
+#=============================================================================
+# Copyright 2021 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD 3-Clause License,
+# see accompanying file BSD-3-Clause-license.txt for details.
+#=============================================================================
+
+# If HARU_ROOT_DIR was defined in the environment, use it.
+if(NOT HARU_ROOT_DIR AND NOT $ENV{HARU_ROOT_DIR} STREQUAL "")
+ set(HARU_ROOT_DIR $ENV{HARU_ROOT_DIR})
+endif()
+
+set(_haru_SEARCH_DIRS
+ ${HARU_ROOT_DIR}
+ /opt/lib/haru
+)
+
+find_path(HARU_INCLUDE_DIR
+ NAMES
+ hpdf.h
+ HINTS
+ ${_haru_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include/haru
+)
+
+find_library(HARU_LIBRARY
+ NAMES
+ hpdfs
+ HINTS
+ ${_haru_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib64 lib
+)
+
+# Handle the QUIETLY and REQUIRED arguments and set HARU_FOUND to TRUE if
+# all listed variables are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Haru DEFAULT_MSG HARU_LIBRARY HARU_INCLUDE_DIR)
+
+if(HARU_FOUND)
+ set(HARU_LIBRARIES ${HARU_LIBRARY})
+ set(HARU_INCLUDE_DIRS ${HARU_INCLUDE_DIR})
+endif()
+
+mark_as_advanced(
+ HARU_INCLUDE_DIR
+ HARU_LIBRARY
+)
+
+unset(_haru_SEARCH_DIRS)
diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake
index 70f48fc33ea..0c78111eaaf 100644
--- a/build_files/cmake/Modules/GTestTesting.cmake
+++ b/build_files/cmake/Modules/GTestTesting.cmake
@@ -99,7 +99,9 @@ macro(BLENDER_SRC_GTEST_EX)
# Don't fail tests on leaks since these often happen in external libraries
# that we can't fix.
- set_tests_properties(${TARGET_NAME} PROPERTIES ENVIRONMENT LSAN_OPTIONS=exitcode=0)
+ set_tests_properties(${TARGET_NAME} PROPERTIES
+ ENVIRONMENT LSAN_OPTIONS=exitcode=0:$ENV{LSAN_OPTIONS}
+ )
endif()
if(WIN32)
set_target_properties(${TARGET_NAME} PROPERTIES VS_GLOBAL_VcpkgEnabled "false")
diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake
index aab997ab453..75f78befb60 100644
--- a/build_files/cmake/config/blender_full.cmake
+++ b/build_files/cmake/config/blender_full.cmake
@@ -19,6 +19,7 @@ set(WITH_DRACO ON CACHE BOOL "" FORCE)
set(WITH_FFTW3 ON CACHE BOOL "" FORCE)
set(WITH_FREESTYLE ON CACHE BOOL "" FORCE)
set(WITH_GMP ON CACHE BOOL "" FORCE)
+set(WITH_HARU ON CACHE BOOL "" FORCE)
set(WITH_IK_ITASC ON CACHE BOOL "" FORCE)
set(WITH_IK_SOLVER ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_CINEON ON CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 480548abca7..680734aba6e 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -24,6 +24,7 @@ set(WITH_DRACO OFF CACHE BOOL "" FORCE)
set(WITH_FFTW3 OFF CACHE BOOL "" FORCE)
set(WITH_FREESTYLE OFF CACHE BOOL "" FORCE)
set(WITH_GMP OFF CACHE BOOL "" FORCE)
+set(WITH_HARU OFF CACHE BOOL "" FORCE)
set(WITH_IK_ITASC OFF CACHE BOOL "" FORCE)
set(WITH_IK_SOLVER OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_CINEON OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake
index 96101ee7bcc..973d6cdb34e 100644
--- a/build_files/cmake/config/blender_release.cmake
+++ b/build_files/cmake/config/blender_release.cmake
@@ -20,6 +20,7 @@ set(WITH_DRACO ON CACHE BOOL "" FORCE)
set(WITH_FFTW3 ON CACHE BOOL "" FORCE)
set(WITH_FREESTYLE ON CACHE BOOL "" FORCE)
set(WITH_GMP ON CACHE BOOL "" FORCE)
+set(WITH_HARU ON CACHE BOOL "" FORCE)
set(WITH_IK_SOLVER ON CACHE BOOL "" FORCE)
set(WITH_IK_ITASC ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_CINEON ON CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index 31da5292eaf..8a7792bd886 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -72,7 +72,11 @@ if(WITH_JACK)
endif()
if(NOT DEFINED LIBDIR)
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin)
+ if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64")
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin)
+ else()
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin_${CMAKE_OSX_ARCHITECTURES})
+ endif()
else()
message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
endif()
@@ -428,6 +432,14 @@ if(WITH_GMP)
endif()
endif()
+if(WITH_HARU)
+ find_package(Haru)
+ if(NOT HARU_FOUND)
+ message(WARNING "Haru not found, disabling WITH_HARU")
+ set(WITH_HARU OFF)
+ endif()
+endif()
+
if(EXISTS ${LIBDIR})
without_system_libs_end()
endif()
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index 016ae58fde4..69a78ba7ca6 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -800,3 +800,15 @@ if(WITH_POTRACE)
set(POTRACE_LIBRARIES ${LIBDIR}/potrace/lib/potrace.lib)
set(POTRACE_FOUND On)
endif()
+
+if(WITH_HARU)
+ if(EXISTS ${LIBDIR}/haru)
+ set(HARU_FOUND On)
+ set(HARU_ROOT_DIR ${LIBDIR}/haru)
+ set(HARU_INCLUDE_DIRS ${HARU_ROOT_DIR}/include)
+ set(HARU_LIBRARIES ${HARU_ROOT_DIR}/lib/libhpdfs.lib)
+ else()
+ message(WARNING "Haru was not found, disabling WITH_HARU")
+ set(WITH_HARU OFF)
+ endif()
+endif()
diff --git a/build_files/utils/make_update.py b/build_files/utils/make_update.py
index 53f6b3d447f..2b8c7af98fb 100755
--- a/build_files/utils/make_update.py
+++ b/build_files/utils/make_update.py
@@ -8,6 +8,7 @@
import argparse
import os
+import platform
import shutil
import sys
@@ -49,7 +50,12 @@ def svn_update(args, release_version):
# Checkout precompiled libraries
if sys.platform == 'darwin':
- lib_platform = "darwin"
+ if platform.machine() == 'x86_64':
+ lib_platform = "darwin"
+ elif platform.machine() == 'arm64':
+ lib_platform = "darwin_arm64"
+ else:
+ lib_platform = None
elif sys.platform == 'win32':
# Windows checkout is usually handled by bat scripts since python3 to run
# this script is bundled as part of the precompiled libraries. However it
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index 772fac56f63..f9055f02bcf 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = "V2.92"
+PROJECT_NUMBER = "V2.93"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/doc/manpage/blender.1.py b/doc/manpage/blender.1.py
index da83abe8442..150548072d5 100755
--- a/doc/manpage/blender.1.py
+++ b/doc/manpage/blender.1.py
@@ -52,10 +52,11 @@ outfilename = sys.argv[2]
cmd = [blender_bin, "--help"]
print(" executing:", " ".join(cmd))
+ASAN_OPTIONS = "exitcode=0:" + os.environ.get("ASAN_OPTIONS", "")
blender_help = subprocess.run(
- cmd, env={"ASAN_OPTIONS": "exitcode=0"}, check=True, stdout=subprocess.PIPE).stdout.decode(encoding="utf-8")
+ cmd, env={"ASAN_OPTIONS": ASAN_OPTIONS}, check=True, stdout=subprocess.PIPE).stdout.decode(encoding="utf-8")
blender_version = subprocess.run(
- [blender_bin, "--version"], env={"ASAN_OPTIONS": "exitcode=0"}, check=True, stdout=subprocess.PIPE).stdout.decode(encoding="utf-8").strip()
+ [blender_bin, "--version"], env={"ASAN_OPTIONS": ASAN_OPTIONS}, check=True, stdout=subprocess.PIPE).stdout.decode(encoding="utf-8").strip()
blender_version, blender_date = (blender_version.split("build") + [None, None])[0:2]
blender_version = blender_version.rstrip().partition(" ")[2] # remove 'Blender' prefix.
if blender_date is None:
diff --git a/doc/python_api/sphinx_doc_gen.sh b/doc/python_api/sphinx_doc_gen.sh
index 590de594875..26c3701f3e0 100755
--- a/doc/python_api/sphinx_doc_gen.sh
+++ b/doc/python_api/sphinx_doc_gen.sh
@@ -55,7 +55,7 @@ if $DO_EXE_BLENDER ; then
# Don't delete existing docs, now partial updates are used for quick builds.
#
# Disable ASAN error halt since it results in nonzero exit code on any minor issue.
- ASAN_OPTIONS=halt_on_error=0 \
+ ASAN_OPTIONS=halt_on_error=0:${ASAN_OPTIONS} \
$BLENDER_BIN \
--background \
-noaudio \
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 3ab352e52a2..b1deb5cb64e 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -59,6 +59,7 @@ class CyclesRender(bpy.types.RenderEngine):
bl_use_exclude_layers = True
bl_use_save_buffers = True
bl_use_spherical_stereo = True
+ bl_use_custom_freestyle = True
def __init__(self):
self.session = None
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 964241e9904..4fb5c7f57d1 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -67,11 +67,10 @@ static bool ObtainCacheParticleData(
Transform tfm = get_transform(b_ob->matrix_world());
Transform itfm = transform_quick_inverse(tfm);
- BL::Object::modifiers_iterator b_mod;
- for (b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) &&
- (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
+ for (BL::Modifier &b_mod : b_ob->modifiers) {
+ if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
+ (background ? b_mod.show_render() : b_mod.show_viewport())) {
+ BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
@@ -163,11 +162,10 @@ static bool ObtainCacheParticleUV(Hair *hair,
CData->curve_uv.clear();
- BL::Object::modifiers_iterator b_mod;
- for (b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) &&
- (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
+ for (BL::Modifier &b_mod : b_ob->modifiers) {
+ if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
+ (background ? b_mod.show_render() : b_mod.show_viewport())) {
+ BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
@@ -226,11 +224,10 @@ static bool ObtainCacheParticleVcol(Hair *hair,
CData->curve_vcol.clear();
- BL::Object::modifiers_iterator b_mod;
- for (b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) &&
- (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
+ for (BL::Modifier &b_mod : b_ob->modifiers) {
+ if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
+ (background ? b_mod.show_render() : b_mod.show_viewport())) {
+ BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
@@ -510,11 +507,10 @@ static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int
bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
{
/* Test if the object has a particle modifier with hair. */
- BL::Object::modifiers_iterator b_mod;
- for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
- if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) &&
- (preview ? b_mod->show_viewport() : b_mod->show_render())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
+ for (BL::Modifier &b_mod : b_ob.modifiers) {
+ if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
+ (preview ? b_mod.show_viewport() : b_mod.show_render())) {
+ BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
@@ -678,9 +674,7 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
/* Export curves and points. */
vector<float> points_length;
- BL::Hair::curves_iterator b_curve_iter;
- for (b_hair.curves.begin(b_curve_iter); b_curve_iter != b_hair.curves.end(); ++b_curve_iter) {
- BL::HairCurve b_curve = *b_curve_iter;
+ for (BL::HairCurve &b_curve : b_hair.curves) {
const int first_point_index = b_curve.first_point_index();
const int num_points = b_curve.num_points();
@@ -748,9 +742,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
int num_motion_keys = 0;
int curve_index = 0;
- BL::Hair::curves_iterator b_curve_iter;
- for (b_hair.curves.begin(b_curve_iter); b_curve_iter != b_hair.curves.end(); ++b_curve_iter) {
- BL::HairCurve b_curve = *b_curve_iter;
+ for (BL::HairCurve &b_curve : b_hair.curves) {
const int first_point_index = b_curve.first_point_index();
const int num_points = b_curve.num_points();
@@ -855,10 +847,7 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *ha
hair->set_value(socket, new_hair, socket);
}
- hair->attributes.clear();
- foreach (Attribute &attr, new_hair.attributes.attributes) {
- hair->attributes.attributes.push_back(std::move(attr));
- }
+ hair->attributes.update(std::move(new_hair.attributes));
/* tag update */
diff --git a/intern/cycles/blender/blender_device.cpp b/intern/cycles/blender/blender_device.cpp
index 3ec77719bea..d51b31de638 100644
--- a/intern/cycles/blender/blender_device.cpp
+++ b/intern/cycles/blender/blender_device.cpp
@@ -47,11 +47,9 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
/* Find cycles preferences. */
PointerRNA cpreferences;
- BL::Preferences::addons_iterator b_addon_iter;
- for (b_preferences.addons.begin(b_addon_iter); b_addon_iter != b_preferences.addons.end();
- ++b_addon_iter) {
- if (b_addon_iter->module() == "cycles") {
- cpreferences = b_addon_iter->preferences().ptr;
+ for (BL::Addon &b_addon : b_preferences.addons) {
+ if (b_addon.module() == "cycles") {
+ cpreferences = b_addon.preferences().ptr;
break;
}
}
diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp
index bd2f0731030..a009018f357 100644
--- a/intern/cycles/blender/blender_geometry.cpp
+++ b/intern/cycles/blender/blender_geometry.cpp
@@ -42,32 +42,20 @@ static Geometry::Type determine_geom_type(BL::Object &b_ob, bool use_particle_ha
return Geometry::MESH;
}
-Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
- BL::Object &b_ob,
- BL::Object &b_ob_instance,
- bool object_updated,
- bool use_particle_hair,
- TaskPool *task_pool)
+array<Node *> BlenderSync::find_used_shaders(BL::Object &b_ob)
{
- /* Test if we can instance or if the object is modified. */
- BL::ID b_ob_data = b_ob.data();
- BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
BL::Material material_override = view_layer.material_override;
Shader *default_shader = (b_ob.type() == BL::Object::type_VOLUME) ? scene->default_volume :
scene->default_surface;
- Geometry::Type geom_type = determine_geom_type(b_ob, use_particle_hair);
- GeometryKey key(b_key_id.ptr.data, geom_type);
- /* Find shader indices. */
array<Node *> used_shaders;
- BL::Object::material_slots_iterator slot;
- for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
+ for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
if (material_override) {
find_shader(material_override, used_shaders, default_shader);
}
else {
- BL::ID b_material(slot->material());
+ BL::ID b_material(b_slot.material());
find_shader(b_material, used_shaders, default_shader);
}
}
@@ -79,6 +67,25 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
used_shaders.push_back_slow(default_shader);
}
+ return used_shaders;
+}
+
+Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
+ BL::Object &b_ob,
+ BL::Object &b_ob_instance,
+ bool object_updated,
+ bool use_particle_hair,
+ TaskPool *task_pool)
+{
+ /* Test if we can instance or if the object is modified. */
+ BL::ID b_ob_data = b_ob.data();
+ BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
+ Geometry::Type geom_type = determine_geom_type(b_ob, use_particle_hair);
+ GeometryKey key(b_key_id.ptr.data, geom_type);
+
+ /* Find shader indices. */
+ array<Node *> used_shaders = find_used_shaders(b_ob);
+
/* Ensure we only sync instanced geometry once. */
Geometry *geom = geometry_map.find(key);
if (geom) {
@@ -124,7 +131,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
- if (shader->need_update_geometry) {
+ if (shader->need_update_geometry()) {
attribute_recalc = true;
}
}
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index 3420025f472..7edf797e096 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -285,12 +285,10 @@ static void attr_create_sculpt_vertex_color(Scene *scene,
BL::Mesh &b_mesh,
bool subdivision)
{
- BL::Mesh::sculpt_vertex_colors_iterator l;
-
- for (b_mesh.sculpt_vertex_colors.begin(l); l != b_mesh.sculpt_vertex_colors.end(); ++l) {
- const bool active_render = l->active_render();
+ for (BL::MeshVertColorLayer &l : b_mesh.sculpt_vertex_colors) {
+ const bool active_render = l.active_render();
AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
- ustring vcol_name = ustring(l->name().c_str());
+ ustring vcol_name = ustring(l.name().c_str());
const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
mesh->need_attribute(scene, vcol_std);
@@ -307,7 +305,7 @@ static void attr_create_sculpt_vertex_color(Scene *scene,
int numverts = b_mesh.vertices.length();
for (int i = 0; i < numverts; i++) {
- *(cdata++) = get_float4(l->data[i].color());
+ *(cdata++) = get_float4(l.data[i].color());
}
}
}
@@ -315,12 +313,10 @@ static void attr_create_sculpt_vertex_color(Scene *scene,
/* Create vertex color attributes. */
static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
{
- BL::Mesh::vertex_colors_iterator l;
-
- for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) {
- const bool active_render = l->active_render();
+ for (BL::MeshLoopColorLayer &l : b_mesh.vertex_colors) {
+ const bool active_render = l.active_render();
AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
- ustring vcol_name = ustring(l->name().c_str());
+ ustring vcol_name = ustring(l.name().c_str());
const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
mesh->need_attribute(scene, vcol_std);
@@ -339,13 +335,12 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
vcol_attr = mesh->subd_attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
}
- BL::Mesh::polygons_iterator p;
uchar4 *cdata = vcol_attr->data_uchar4();
- for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
- int n = p->loop_total();
+ for (BL::MeshPolygon &p : b_mesh.polygons) {
+ int n = p.loop_total();
for (int i = 0; i < n; i++) {
- float4 color = get_float4(l->data[p->loop_start() + i].color());
+ float4 color = get_float4(l.data[p.loop_start() + i].color());
/* Compress/encode vertex color using the sRGB curve. */
*(cdata++) = color_float4_to_uchar4(color);
}
@@ -359,14 +354,13 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
vcol_attr = mesh->attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
}
- BL::Mesh::loop_triangles_iterator t;
uchar4 *cdata = vcol_attr->data_uchar4();
- for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
- int3 li = get_int3(t->loops());
- float4 c1 = get_float4(l->data[li[0]].color());
- float4 c2 = get_float4(l->data[li[1]].color());
- float4 c3 = get_float4(l->data[li[2]].color());
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ int3 li = get_int3(t.loops());
+ float4 c1 = get_float4(l.data[li[0]].color());
+ float4 c2 = get_float4(l.data[li[1]].color());
+ float4 c3 = get_float4(l.data[li[2]].color());
/* Compress/encode vertex color using the sRGB curve. */
cdata[0] = color_float4_to_uchar4(c1);
@@ -383,14 +377,12 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
{
if (b_mesh.uv_layers.length() != 0) {
- BL::Mesh::uv_layers_iterator l;
-
- for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l) {
- const bool active_render = l->active_render();
+ for (BL::MeshUVLoopLayer &l : b_mesh.uv_layers) {
+ const bool active_render = l.active_render();
AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
- ustring uv_name = ustring(l->name().c_str());
+ ustring uv_name = ustring(l.name().c_str());
AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE;
- ustring tangent_name = ustring((string(l->name().c_str()) + ".tangent").c_str());
+ ustring tangent_name = ustring((string(l.name().c_str()) + ".tangent").c_str());
/* Denotes whether UV map was requested directly. */
const bool need_uv = mesh->need_attribute(scene, uv_name) ||
@@ -412,14 +404,13 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
uv_attr = mesh->attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
}
- BL::Mesh::loop_triangles_iterator t;
float2 *fdata = uv_attr->data_float2();
- for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
- int3 li = get_int3(t->loops());
- fdata[0] = get_float2(l->data[li[0]].uv());
- fdata[1] = get_float2(l->data[li[1]].uv());
- fdata[2] = get_float2(l->data[li[2]].uv());
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ int3 li = get_int3(t.loops());
+ fdata[0] = get_float2(l.data[li[0]].uv());
+ fdata[1] = get_float2(l.data[li[1]].uv());
+ fdata[2] = get_float2(l.data[li[2]].uv());
fdata += 3;
}
}
@@ -427,10 +418,10 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
/* UV tangent */
if (need_tangent) {
AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE;
- ustring sign_name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str());
+ ustring sign_name = ustring((string(l.name().c_str()) + ".tangent_sign").c_str());
bool need_sign = (mesh->need_attribute(scene, sign_name) ||
mesh->need_attribute(scene, sign_std));
- mikk_compute_tangents(b_mesh, l->name().c_str(), mesh, need_sign, active_render);
+ mikk_compute_tangents(b_mesh, l.name().c_str(), mesh, need_sign, active_render);
}
/* Remove temporarily created UV attribute. */
if (!need_uv && uv_attr != NULL) {
@@ -480,13 +471,12 @@ static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
uv_attr->flags |= ATTR_SUBDIVIDED;
}
- BL::Mesh::polygons_iterator p;
float2 *fdata = uv_attr->data_float2();
- for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
- int n = p->loop_total();
+ for (BL::MeshPolygon &p : b_mesh.polygons) {
+ int n = p.loop_total();
for (int j = 0; j < n; j++) {
- *(fdata++) = get_float2(l->data[p->loop_start() + j].uv());
+ *(fdata++) = get_float2(l->data[p.loop_start() + j].uv());
}
}
}
@@ -706,9 +696,8 @@ static void attr_create_random_per_island(Scene *scene,
DisjointSet vertices_sets(number_of_vertices);
- BL::Mesh::edges_iterator e;
- for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
- vertices_sets.join(e->vertices()[0], e->vertices()[1]);
+ for (BL::MeshEdge &e : b_mesh.edges) {
+ vertices_sets.join(e.vertices()[0], e.vertices()[1]);
}
AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
@@ -716,15 +705,13 @@ static void attr_create_random_per_island(Scene *scene,
float *data = attribute->data_float();
if (!subdivision) {
- BL::Mesh::loop_triangles_iterator t;
- for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
- data[t->index()] = hash_uint_to_float(vertices_sets.find(t->vertices()[0]));
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ data[t.index()] = hash_uint_to_float(vertices_sets.find(t.vertices()[0]));
}
}
else {
- BL::Mesh::polygons_iterator p;
- for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
- data[p->index()] = hash_uint_to_float(vertices_sets.find(p->vertices()[0]));
+ for (BL::MeshPolygon &p : b_mesh.polygons) {
+ data[p.index()] = hash_uint_to_float(vertices_sets.find(p.vertices()[0]));
}
}
}
@@ -756,10 +743,9 @@ static void create_mesh(Scene *scene,
numtris = numfaces;
}
else {
- BL::Mesh::polygons_iterator p;
- for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
- numngons += (p->loop_total() == 4) ? 0 : 1;
- numcorners += p->loop_total();
+ for (BL::MeshPolygon &p : b_mesh.polygons) {
+ numngons += (p.loop_total() == 4) ? 0 : 1;
+ numcorners += p.loop_total();
}
}
@@ -803,17 +789,15 @@ static void create_mesh(Scene *scene,
/* create faces */
if (!subdivision) {
- BL::Mesh::loop_triangles_iterator t;
-
- for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
- BL::MeshPolygon p = b_mesh.polygons[t->polygon_index()];
- int3 vi = get_int3(t->vertices());
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ BL::MeshPolygon p = b_mesh.polygons[t.polygon_index()];
+ int3 vi = get_int3(t.vertices());
int shader = clamp(p.material_index(), 0, used_shaders.size() - 1);
bool smooth = p.use_smooth() || use_loop_normals;
if (use_loop_normals) {
- BL::Array<float, 9> loop_normals = t->split_normals();
+ BL::Array<float, 9> loop_normals = t.split_normals();
for (int i = 0; i < 3; i++) {
N[vi[i]] = make_float3(
loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);
@@ -828,18 +812,17 @@ static void create_mesh(Scene *scene,
}
}
else {
- BL::Mesh::polygons_iterator p;
vector<int> vi;
- for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
- int n = p->loop_total();
- int shader = clamp(p->material_index(), 0, used_shaders.size() - 1);
- bool smooth = p->use_smooth() || use_loop_normals;
+ for (BL::MeshPolygon &p : b_mesh.polygons) {
+ int n = p.loop_total();
+ int shader = clamp(p.material_index(), 0, used_shaders.size() - 1);
+ bool smooth = p.use_smooth() || use_loop_normals;
vi.resize(n);
for (int i = 0; i < n; i++) {
/* NOTE: Autosmooth is already taken care about. */
- vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index();
+ vi[i] = b_mesh.loops[p.loop_start() + i].vertex_index();
}
/* create subd faces */
@@ -891,19 +874,18 @@ static void create_subd_mesh(Scene *scene,
/* export creases */
size_t num_creases = 0;
- BL::Mesh::edges_iterator e;
- for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
- if (e->crease() != 0.0f) {
+ for (BL::MeshEdge &e : b_mesh.edges) {
+ if (e.crease() != 0.0f) {
num_creases++;
}
}
mesh->reserve_subd_creases(num_creases);
- for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
- if (e->crease() != 0.0f) {
- mesh->add_crease(e->vertices()[0], e->vertices()[1], e->crease());
+ for (BL::MeshEdge &e : b_mesh.edges) {
+ if (e.crease() != 0.0f) {
+ mesh->add_crease(e.vertices()[0], e.vertices()[1], e.crease());
}
}
@@ -1075,15 +1057,8 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me
mesh->set_value(socket, new_mesh, socket);
}
- mesh->attributes.clear();
- foreach (Attribute &attr, new_mesh.attributes.attributes) {
- mesh->attributes.attributes.push_back(std::move(attr));
- }
-
- mesh->subd_attributes.clear();
- foreach (Attribute &attr, new_mesh.subd_attributes.attributes) {
- mesh->subd_attributes.attributes.push_back(std::move(attr));
- }
+ mesh->attributes.update(std::move(new_mesh.attributes));
+ mesh->subd_attributes.update(std::move(new_mesh.subd_attributes));
mesh->set_num_subd_faces(new_mesh.get_num_subd_faces());
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 5261fbcee07..f0460b129c2 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -51,10 +51,11 @@ bool BlenderSync::BKE_object_is_modified(BL::Object &b_ob)
}
else {
/* object level material links */
- BL::Object::material_slots_iterator slot;
- for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
- if (slot->link() == BL::MaterialSlot::link_OBJECT)
+ for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
+ if (b_slot.link() == BL::MaterialSlot::link_OBJECT) {
return true;
+ }
+ }
}
return false;
@@ -243,9 +244,6 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
/* holdout */
object->set_use_holdout(use_holdout);
- if (object->use_holdout_is_modified()) {
- scene->object_manager->tag_update(scene);
- }
object->set_visibility(visibility);
diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp
index ca221b229b4..d5dd7215c47 100644
--- a/intern/cycles/blender/blender_particles.cpp
+++ b/intern/cycles/blender/blender_particles.cpp
@@ -57,7 +57,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
/* no update needed? */
if (!need_update && !object->get_geometry()->is_modified() &&
- !scene->object_manager->need_update)
+ !scene->object_manager->need_update())
return true;
/* first time used in this sync loop? clear and tag update */
@@ -85,7 +85,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
object->set_particle_index(psys->particles.size() - 1);
if (object->particle_index_is_modified())
- scene->object_manager->tag_update(scene);
+ scene->object_manager->tag_update(scene, ObjectManager::PARTICLE_MODIFIED);
/* return that this object has particle data */
return true;
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 525525e1047..5646bd5b2eb 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -597,22 +597,19 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
bool removed;
do {
- BL::Node::inputs_iterator b_input;
- BL::Node::outputs_iterator b_output;
-
removed = false;
- for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
- if (used_sockets.find(b_input->ptr.data) == used_sockets.end()) {
- b_node.inputs.remove(b_data, *b_input);
+ for (BL::NodeSocket &b_input : b_node.inputs) {
+ if (used_sockets.find(b_input.ptr.data) == used_sockets.end()) {
+ b_node.inputs.remove(b_data, b_input);
removed = true;
break;
}
}
- for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
- if (used_sockets.find(b_output->ptr.data) == used_sockets.end()) {
- b_node.outputs.remove(b_data, *b_output);
+ for (BL::NodeSocket &b_output : b_node.outputs) {
+ if (used_sockets.find(b_output.ptr.data) == used_sockets.end()) {
+ b_node.outputs.remove(b_data, b_output);
removed = true;
break;
}
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 8566d0e7ed5..ae13310789e 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -358,11 +358,7 @@ void BlenderSession::do_write_update_render_tile(RenderTile &rtile,
if (do_read_only) {
/* copy each pass */
- BL::RenderLayer::passes_iterator b_iter;
-
- for (b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
- BL::RenderPass b_pass(*b_iter);
-
+ for (BL::RenderPass &b_pass : b_rlay.passes) {
/* find matching pass type */
PassType pass_type = BlenderSync::get_pass_type(b_pass);
int components = b_pass.channels();
@@ -552,7 +548,6 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
int seed = scene->integrator->get_seed();
seed += hash_uint2(seed, hash_uint2(view_index * 0xdeadbeef, 0));
scene->integrator->set_seed(seed);
- scene->integrator->tag_update(scene);
}
/* Update number of samples per layer. */
@@ -736,10 +731,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderLayer &b_rlay,
if (!do_update_only) {
/* copy each pass */
- BL::RenderLayer::passes_iterator b_iter;
-
- for (b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
- BL::RenderPass b_pass(*b_iter);
+ for (BL::RenderPass &b_pass : b_rlay.passes) {
int components = b_pass.channels();
/* Copy pixels from regular render passes. */
@@ -1116,10 +1108,6 @@ void BlenderSession::update_resumable_tile_manager(int num_samples)
scene->integrator->set_start_sample(rounded_range_start_sample);
- if (scene->integrator->is_modified()) {
- scene->integrator->tag_update(scene);
- }
-
session->tile_manager.range_start_sample = rounded_range_start_sample;
session->tile_manager.range_num_samples = rounded_range_num_samples;
}
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index ac86cf3345c..02a6638b083 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -148,15 +148,13 @@ BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_r
static BL::NodeSocket get_node_output(BL::Node &b_node, const string &name)
{
- BL::Node::outputs_iterator b_out;
-
- for (b_node.outputs.begin(b_out); b_out != b_node.outputs.end(); ++b_out)
- if (b_out->name() == name)
- return *b_out;
-
+ for (BL::NodeSocket &b_out : b_node.outputs) {
+ if (b_out.name() == name) {
+ return b_out;
+ }
+ }
assert(0);
-
- return *b_out;
+ return *b_node.outputs.begin();
}
static float3 get_node_output_rgba(BL::Node &b_node, const string &name)
@@ -723,9 +721,8 @@ static ShaderNode *add_node(Scene *scene,
image->set_alpha_type(get_image_alpha_type(b_image));
array<int> tiles;
- BL::Image::tiles_iterator b_iter;
- for (b_image.tiles.begin(b_iter); b_iter != b_image.tiles.end(); ++b_iter) {
- tiles.push_back_slow(b_iter->number());
+ for (BL::UDIMTile &b_tile : b_image.tiles) {
+ tiles.push_back_slow(b_tile.number());
}
image->set_tiles(tiles);
@@ -885,7 +882,7 @@ static ShaderNode *add_node(Scene *scene,
sky->set_sun_intensity(b_sky_node.sun_intensity());
sky->set_sun_elevation(b_sky_node.sun_elevation());
sky->set_sun_rotation(b_sky_node.sun_rotation());
- sky->set_altitude(1000.0f * b_sky_node.altitude());
+ sky->set_altitude(b_sky_node.altitude());
sky->set_air_density(b_sky_node.air_density());
sky->set_dust_density(b_sky_node.dust_density());
sky->set_ozone_density(b_sky_node.ozone_density());
@@ -1012,18 +1009,18 @@ static ShaderInput *node_find_input_by_name(ShaderNode *node,
string name = b_socket.name();
if (node_use_modified_socket_name(node)) {
- BL::Node::inputs_iterator b_input;
bool found = false;
int counter = 0, total = 0;
- for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
- if (b_input->name() == name) {
- if (!found)
+ for (BL::NodeSocket &b_input : b_node.inputs) {
+ if (b_input.name() == name) {
+ if (!found) {
counter++;
+ }
total++;
}
- if (b_input->ptr.data == b_socket.ptr.data)
+ if (b_input.ptr.data == b_socket.ptr.data)
found = true;
}
@@ -1045,19 +1042,20 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node,
string name = b_socket.name();
if (node_use_modified_socket_name(node)) {
- BL::Node::outputs_iterator b_output;
bool found = false;
int counter = 0, total = 0;
- for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
- if (b_output->name() == name) {
- if (!found)
+ for (BL::NodeSocket &b_output : b_node.outputs) {
+ if (b_output.name() == name) {
+ if (!found) {
counter++;
+ }
total++;
}
- if (b_output->ptr.data == b_socket.ptr.data)
+ if (b_output.ptr.data == b_socket.ptr.data) {
found = true;
+ }
}
/* rename if needed */
@@ -1082,25 +1080,19 @@ static void add_nodes(Scene *scene,
const ProxyMap &proxy_output_map)
{
/* add nodes */
- BL::ShaderNodeTree::nodes_iterator b_node;
PtrInputMap input_map;
PtrOutputMap output_map;
- BL::Node::inputs_iterator b_input;
- BL::Node::outputs_iterator b_output;
-
/* find the node to use for output if there are multiple */
BL::ShaderNode output_node = b_ntree.get_output_node(
BL::ShaderNodeOutputMaterial::target_CYCLES);
/* add nodes */
- for (b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
- if (b_node->mute() || b_node->is_a(&RNA_NodeReroute)) {
+ for (BL::Node &b_node : b_ntree.nodes) {
+ if (b_node.mute() || b_node.is_a(&RNA_NodeReroute)) {
/* replace muted node with internal links */
- BL::Node::internal_links_iterator b_link;
- for (b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end();
- ++b_link) {
- BL::NodeSocket to_socket(b_link->to_socket());
+ for (BL::NodeLink &b_link : b_node.internal_links) {
+ BL::NodeSocket to_socket(b_link.to_socket());
SocketType::Type to_socket_type = convert_socket_type(to_socket);
if (to_socket_type == SocketType::UNDEFINED) {
continue;
@@ -1108,22 +1100,22 @@ static void add_nodes(Scene *scene,
ConvertNode *proxy = graph->create_node<ConvertNode>(to_socket_type, to_socket_type, true);
- input_map[b_link->from_socket().ptr.data] = proxy->inputs[0];
- output_map[b_link->to_socket().ptr.data] = proxy->outputs[0];
+ input_map[b_link.from_socket().ptr.data] = proxy->inputs[0];
+ output_map[b_link.to_socket().ptr.data] = proxy->outputs[0];
graph->add(proxy);
}
}
- else if (b_node->is_a(&RNA_ShaderNodeGroup) || b_node->is_a(&RNA_NodeCustomGroup) ||
- b_node->is_a(&RNA_ShaderNodeCustomGroup)) {
+ else if (b_node.is_a(&RNA_ShaderNodeGroup) || b_node.is_a(&RNA_NodeCustomGroup) ||
+ b_node.is_a(&RNA_ShaderNodeCustomGroup)) {
BL::ShaderNodeTree b_group_ntree(PointerRNA_NULL);
- if (b_node->is_a(&RNA_ShaderNodeGroup))
- b_group_ntree = BL::ShaderNodeTree(((BL::NodeGroup)(*b_node)).node_tree());
- else if (b_node->is_a(&RNA_NodeCustomGroup))
- b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(*b_node)).node_tree());
+ if (b_node.is_a(&RNA_ShaderNodeGroup))
+ b_group_ntree = BL::ShaderNodeTree(((BL::NodeGroup)(b_node)).node_tree());
+ else if (b_node.is_a(&RNA_NodeCustomGroup))
+ b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(b_node)).node_tree());
else
- b_group_ntree = BL::ShaderNodeTree(((BL::ShaderNodeCustomGroup)(*b_node)).node_tree());
+ b_group_ntree = BL::ShaderNodeTree(((BL::ShaderNodeCustomGroup)(b_node)).node_tree());
ProxyMap group_proxy_input_map, group_proxy_output_map;
@@ -1131,8 +1123,8 @@ static void add_nodes(Scene *scene,
* Do this even if the node group has no internal tree,
* so that links have something to connect to and assert won't fail.
*/
- for (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
- SocketType::Type input_type = convert_socket_type(*b_input);
+ for (BL::NodeSocket &b_input : b_node.inputs) {
+ SocketType::Type input_type = convert_socket_type(b_input);
if (input_type == SocketType::UNDEFINED) {
continue;
}
@@ -1141,14 +1133,14 @@ static void add_nodes(Scene *scene,
graph->add(proxy);
/* register the proxy node for internal binding */
- group_proxy_input_map[b_input->identifier()] = proxy;
+ group_proxy_input_map[b_input.identifier()] = proxy;
- input_map[b_input->ptr.data] = proxy->inputs[0];
+ input_map[b_input.ptr.data] = proxy->inputs[0];
- set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
+ set_default_value(proxy->inputs[0], b_input, b_data, b_ntree);
}
- for (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
- SocketType::Type output_type = convert_socket_type(*b_output);
+ for (BL::NodeSocket &b_output : b_node.outputs) {
+ SocketType::Type output_type = convert_socket_type(b_output);
if (output_type == SocketType::UNDEFINED) {
continue;
}
@@ -1157,9 +1149,9 @@ static void add_nodes(Scene *scene,
graph->add(proxy);
/* register the proxy node for internal binding */
- group_proxy_output_map[b_output->identifier()] = proxy;
+ group_proxy_output_map[b_output.identifier()] = proxy;
- output_map[b_output->ptr.data] = proxy->outputs[0];
+ output_map[b_output.ptr.data] = proxy->outputs[0];
}
if (b_group_ntree) {
@@ -1174,30 +1166,30 @@ static void add_nodes(Scene *scene,
group_proxy_output_map);
}
}
- else if (b_node->is_a(&RNA_NodeGroupInput)) {
+ else if (b_node.is_a(&RNA_NodeGroupInput)) {
/* map each socket to a proxy node */
- for (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
- ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output->identifier());
+ for (BL::NodeSocket &b_output : b_node.outputs) {
+ ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output.identifier());
if (proxy_it != proxy_input_map.end()) {
ConvertNode *proxy = proxy_it->second;
- output_map[b_output->ptr.data] = proxy->outputs[0];
+ output_map[b_output.ptr.data] = proxy->outputs[0];
}
}
}
- else if (b_node->is_a(&RNA_NodeGroupOutput)) {
- BL::NodeGroupOutput b_output_node(*b_node);
+ else if (b_node.is_a(&RNA_NodeGroupOutput)) {
+ BL::NodeGroupOutput b_output_node(b_node);
/* only the active group output is used */
if (b_output_node.is_active_output()) {
/* map each socket to a proxy node */
- for (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
- ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input->identifier());
+ for (BL::NodeSocket &b_input : b_node.inputs) {
+ ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input.identifier());
if (proxy_it != proxy_output_map.end()) {
ConvertNode *proxy = proxy_it->second;
- input_map[b_input->ptr.data] = proxy->inputs[0];
+ input_map[b_input.ptr.data] = proxy->inputs[0];
- set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
+ set_default_value(proxy->inputs[0], b_input, b_data, b_ntree);
}
}
}
@@ -1205,52 +1197,49 @@ static void add_nodes(Scene *scene,
else {
ShaderNode *node = NULL;
- if (b_node->ptr.data == output_node.ptr.data) {
+ if (b_node.ptr.data == output_node.ptr.data) {
node = graph->output();
}
else {
- BL::ShaderNode b_shader_node(*b_node);
+ BL::ShaderNode b_shader_node(b_node);
node = add_node(
scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree, b_shader_node);
}
if (node) {
/* map node sockets for linking */
- for (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
- ShaderInput *input = node_find_input_by_name(node, *b_node, *b_input);
+ for (BL::NodeSocket &b_input : b_node.inputs) {
+ ShaderInput *input = node_find_input_by_name(node, b_node, b_input);
if (!input) {
/* XXX should not happen, report error? */
continue;
}
- input_map[b_input->ptr.data] = input;
+ input_map[b_input.ptr.data] = input;
- set_default_value(input, *b_input, b_data, b_ntree);
+ set_default_value(input, b_input, b_data, b_ntree);
}
- for (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
- ShaderOutput *output = node_find_output_by_name(node, *b_node, *b_output);
+ for (BL::NodeSocket &b_output : b_node.outputs) {
+ ShaderOutput *output = node_find_output_by_name(node, b_node, b_output);
if (!output) {
/* XXX should not happen, report error? */
continue;
}
- output_map[b_output->ptr.data] = output;
+ output_map[b_output.ptr.data] = output;
}
}
}
}
/* connect nodes */
- BL::NodeTree::links_iterator b_link;
-
- for (b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
+ for (BL::NodeLink &b_link : b_ntree.links) {
/* Ignore invalid links to avoid unwanted cycles created in graph.
* Also ignore links with unavailable sockets. */
- if (!(b_link->is_valid() && b_link->from_socket().enabled() &&
- b_link->to_socket().enabled())) {
+ if (!(b_link.is_valid() && b_link.from_socket().enabled() && b_link.to_socket().enabled())) {
continue;
}
/* get blender link data */
- BL::NodeSocket b_from_sock = b_link->from_socket();
- BL::NodeSocket b_to_sock = b_link->to_socket();
+ BL::NodeSocket b_from_sock = b_link.from_socket();
+ BL::NodeSocket b_to_sock = b_link.to_socket();
ShaderOutput *output = 0;
ShaderInput *input = 0;
@@ -1298,13 +1287,12 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
TaskPool pool;
set<Shader *> updated_shaders;
- BL::Depsgraph::ids_iterator b_id;
- for (b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) {
- if (!b_id->is_a(&RNA_Material)) {
+ for (BL::ID &b_id : b_depsgraph.ids) {
+ if (!b_id.is_a(&RNA_Material)) {
continue;
}
- BL::Material b_mat(*b_id);
+ BL::Material b_mat(b_id);
Shader *shader;
/* test if we need to sync */
@@ -1497,7 +1485,6 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
shader->set_graph(graph);
shader->tag_update(scene);
- background->tag_update(scene);
}
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
@@ -1517,8 +1504,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
viewport_parameters.custom_viewport_parameters());
background->set_use_ao(background->get_use_ao() && view_layer.use_background_ao);
- if (background->is_modified())
- background->tag_update(scene);
+ background->tag_update(scene);
}
/* Sync Lights */
@@ -1527,13 +1513,12 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
{
shader_map.set_default(scene->default_light);
- BL::Depsgraph::ids_iterator b_id;
- for (b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) {
- if (!b_id->is_a(&RNA_Light)) {
+ for (BL::ID &b_id : b_depsgraph.ids) {
+ if (!b_id.is_a(&RNA_Light)) {
continue;
}
- BL::Light b_light(*b_id);
+ BL::Light b_light(b_id);
Shader *shader;
/* test if we need to sync */
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index e27daa2488d..4bcadab35a1 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -24,6 +24,7 @@
#include "render/mesh.h"
#include "render/nodes.h"
#include "render/object.h"
+#include "render/procedural.h"
#include "render/scene.h"
#include "render/shader.h"
@@ -131,9 +132,8 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
}
/* Iterate over all IDs in this depsgraph. */
- BL::Depsgraph::updates_iterator b_update;
- for (b_depsgraph.updates.begin(b_update); b_update != b_depsgraph.updates.end(); ++b_update) {
- BL::ID b_id(b_update->id());
+ for (BL::DepsgraphUpdate &b_update : b_depsgraph.updates) {
+ BL::ID b_id(b_update.id());
/* Material */
if (b_id.is_a(&RNA_Material)) {
@@ -151,17 +151,17 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
const bool is_geometry = object_is_geometry(b_ob);
const bool is_light = !is_geometry && object_is_light(b_ob);
- if (b_ob.is_instancer() && b_update->is_updated_shading()) {
+ if (b_ob.is_instancer() && b_update.is_updated_shading()) {
/* Needed for e.g. object color updates on instancer. */
object_map.set_recalc(b_ob);
}
if (is_geometry || is_light) {
- const bool updated_geometry = b_update->is_updated_geometry();
+ const bool updated_geometry = b_update.is_updated_geometry();
/* Geometry (mesh, hair, volume). */
if (is_geometry) {
- if (b_update->is_updated_transform() || b_update->is_updated_shading()) {
+ if (b_update.is_updated_transform() || b_update.is_updated_shading()) {
object_map.set_recalc(b_ob);
}
@@ -181,7 +181,7 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
}
/* Light */
else if (is_light) {
- if (b_update->is_updated_transform() || b_update->is_updated_shading()) {
+ if (b_update.is_updated_transform() || b_update.is_updated_shading()) {
object_map.set_recalc(b_ob);
light_map.set_recalc(b_ob);
}
@@ -302,11 +302,6 @@ void BlenderSync::sync_integrator()
integrator->set_sample_clamp_direct(get_float(cscene, "sample_clamp_direct"));
integrator->set_sample_clamp_indirect(get_float(cscene, "sample_clamp_indirect"));
if (!preview) {
- if (integrator->get_motion_blur() != r.use_motion_blur()) {
- scene->object_manager->tag_update(scene);
- scene->camera->tag_modified();
- }
-
integrator->set_motion_blur(r.use_motion_blur());
}
@@ -375,8 +370,8 @@ void BlenderSync::sync_integrator()
integrator->set_ao_bounces(0);
}
- if (integrator->is_modified())
- integrator->tag_update(scene);
+ /* UPDATE_NONE as we don't want to tag the integrator as modified, just tag dependent things */
+ integrator->tag_update(scene, Integrator::UPDATE_NONE);
}
/* Film */
@@ -471,16 +466,15 @@ void BlenderSync::sync_images()
return;
}
/* Free buffers used by images which are not needed for render. */
- BL::BlendData::images_iterator b_image;
- for (b_data.images.begin(b_image); b_image != b_data.images.end(); ++b_image) {
+ for (BL::Image &b_image : b_data.images) {
/* TODO(sergey): Consider making it an utility function to check
* whether image is considered builtin.
*/
- const bool is_builtin = b_image->packed_file() ||
- b_image->source() == BL::Image::source_GENERATED ||
- b_image->source() == BL::Image::source_MOVIE || b_engine.is_preview();
+ const bool is_builtin = b_image.packed_file() ||
+ b_image.source() == BL::Image::source_GENERATED ||
+ b_image.source() == BL::Image::source_MOVIE || b_engine.is_preview();
if (is_builtin == false) {
- b_image->buffers_free();
+ b_image.buffers_free();
}
/* TODO(sergey): Free builtin images not used by any shader. */
}
@@ -581,10 +575,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
vector<Pass> passes;
/* loop over passes */
- BL::RenderLayer::passes_iterator b_pass_iter;
-
- for (b_rlay.passes.begin(b_pass_iter); b_pass_iter != b_rlay.passes.end(); ++b_pass_iter) {
- BL::RenderPass b_pass(*b_pass_iter);
+ for (BL::RenderPass &b_pass : b_rlay.passes) {
PassType pass_type = get_pass_type(b_pass);
if (pass_type == PASS_MOTION && scene->integrator->get_motion_blur())
@@ -729,7 +720,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold());
scene->film->tag_passes_update(scene, passes);
- scene->integrator->tag_update(scene);
+ scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
return passes;
}
@@ -752,9 +743,8 @@ void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph)
/* TODO(sergey): We can actually remove the whole dependency graph,
* but that will need some API support first.
*/
- BL::Depsgraph::objects_iterator b_ob;
- for (b_depsgraph.objects.begin(b_ob); b_ob != b_depsgraph.objects.end(); ++b_ob) {
- b_ob->cache_release();
+ for (BL::Object &b_ob : b_depsgraph.objects) {
+ b_ob.cache_release();
}
}
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index ccf059d7704..1c43522a57e 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -134,6 +134,7 @@ class BlenderSync {
void sync_view();
/* Shader */
+ array<Node *> find_used_shaders(BL::Object &b_ob);
void sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all);
void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree);
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 5185ebae789..43dbb4105df 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -538,11 +538,9 @@ static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_
static inline BL::FluidDomainSettings object_fluid_liquid_domain_find(BL::Object &b_ob)
{
- BL::Object::modifiers_iterator b_mod;
-
- for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
- if (b_mod->is_a(&RNA_FluidModifier)) {
- BL::FluidModifier b_mmd(*b_mod);
+ for (BL::Modifier &b_mod : b_ob.modifiers) {
+ if (b_mod.is_a(&RNA_FluidModifier)) {
+ BL::FluidModifier b_mmd(b_mod);
if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_LIQUID) {
@@ -556,11 +554,9 @@ static inline BL::FluidDomainSettings object_fluid_liquid_domain_find(BL::Object
static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
{
- BL::Object::modifiers_iterator b_mod;
-
- for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
- if (b_mod->is_a(&RNA_FluidModifier)) {
- BL::FluidModifier b_mmd(*b_mod);
+ for (BL::Modifier &b_mod : b_ob.modifiers) {
+ if (b_mod.is_a(&RNA_FluidModifier)) {
+ BL::FluidModifier b_mmd(b_mod);
if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_GAS) {
diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp
index 094d4bbc08c..410f7a72cf5 100644
--- a/intern/cycles/blender/blender_volume.cpp
+++ b/intern/cycles/blender/blender_volume.cpp
@@ -222,9 +222,7 @@ class BlenderVolumeLoader : public VDBImageLoader {
b_volume.grids.load(b_data.ptr.data);
#ifdef WITH_OPENVDB
- BL::Volume::grids_iterator b_grid_iter;
- for (b_volume.grids.begin(b_grid_iter); b_grid_iter != b_volume.grids.end(); ++b_grid_iter) {
- BL::VolumeGrid b_volume_grid(*b_grid_iter);
+ for (BL::VolumeGrid &b_volume_grid : b_volume.grids) {
if (b_volume_grid.name() == grid_name) {
const bool unload = !b_volume_grid.is_loaded();
@@ -260,9 +258,7 @@ static void sync_volume_object(BL::BlendData &b_data,
volume->set_object_space((b_render.space() == BL::VolumeRender::space_OBJECT));
/* Find grid with matching name. */
- BL::Volume::grids_iterator b_grid_iter;
- for (b_volume.grids.begin(b_grid_iter); b_grid_iter != b_volume.grids.end(); ++b_grid_iter) {
- BL::VolumeGrid b_grid = *b_grid_iter;
+ for (BL::VolumeGrid &b_grid : b_volume.grids) {
ustring name = ustring(b_grid.name());
AttributeStandard std = ATTR_STD_NONE;
diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h
index 00b2aa864aa..1f63a152458 100644
--- a/intern/cycles/device/device_memory.h
+++ b/intern/cycles/device/device_memory.h
@@ -259,6 +259,8 @@ class device_memory {
device_ptr original_device_ptr;
size_t original_device_size;
Device *original_device;
+ bool need_realloc_;
+ bool modified;
};
/* Device Only Memory
@@ -329,6 +331,8 @@ template<typename T> class device_vector : public device_memory {
{
data_type = device_type_traits<T>::data_type;
data_elements = device_type_traits<T>::num_elements;
+ modified = true;
+ need_realloc_ = true;
assert(data_elements > 0);
}
@@ -347,6 +351,7 @@ template<typename T> class device_vector : public device_memory {
device_free();
host_free();
host_pointer = host_alloc(sizeof(T) * new_size);
+ modified = true;
assert(device_pointer == 0);
}
@@ -400,6 +405,19 @@ template<typename T> class device_vector : public device_memory {
assert(device_pointer == 0);
}
+ void give_data(array<T> &to)
+ {
+ device_free();
+
+ to.set_data((T *)host_pointer, data_size);
+ data_size = 0;
+ data_width = 0;
+ data_height = 0;
+ data_depth = 0;
+ host_pointer = 0;
+ assert(device_pointer == 0);
+ }
+
/* Free device and host memory. */
void free()
{
@@ -411,10 +429,40 @@ template<typename T> class device_vector : public device_memory {
data_height = 0;
data_depth = 0;
host_pointer = 0;
+ modified = true;
+ need_realloc_ = true;
assert(device_pointer == 0);
}
- size_t size()
+ void free_if_need_realloc(bool force_free)
+ {
+ if (need_realloc_ || force_free) {
+ free();
+ }
+ }
+
+ bool is_modified() const
+ {
+ return modified;
+ }
+
+ bool need_realloc()
+ {
+ return need_realloc_;
+ }
+
+ void tag_modified()
+ {
+ modified = true;
+ }
+
+ void tag_realloc()
+ {
+ need_realloc_ = true;
+ tag_modified();
+ }
+
+ size_t size() const
{
return data_size;
}
@@ -432,7 +480,24 @@ template<typename T> class device_vector : public device_memory {
void copy_to_device()
{
- device_copy_to();
+ if (data_size != 0) {
+ device_copy_to();
+ }
+ }
+
+ void copy_to_device_if_modified()
+ {
+ if (!modified) {
+ return;
+ }
+
+ copy_to_device();
+ }
+
+ void clear_modified()
+ {
+ modified = false;
+ need_realloc_ = false;
}
void copy_from_device()
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h b/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h
index d87e5f193ad..bb6b8a40e8e 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h
+++ b/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h
@@ -18,7 +18,7 @@
/* Data type to replace `double` used in the NanoVDB headers. Cycles don't need doubles, and is
* safer and more portable to never use double datatype on GPU.
* Use a special structure, so that the following is true:
- * - No unnoticed implicit cast or mathermatical operations used on scalar 64bit type
+ * - No unnoticed implicit cast or mathematical operations used on scalar 64bit type
* (which rules out trick like using `uint64_t` as a drop-in replacement for double).
* - Padding rules are matching exactly `double`
* (which rules out array of `uint8_t`). */
diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h
index caca3c28c8d..f1789f0d7eb 100644
--- a/intern/cycles/kernel/osl/osl_globals.h
+++ b/intern/cycles/kernel/osl/osl_globals.h
@@ -43,7 +43,7 @@ class ColorSpaceProcessor;
*
* Data needed by OSL render services, that is global to a rendering session.
* This includes all OSL shaders, name to attribute mapping and texture handles.
- * */
+ */
struct OSLGlobals {
OSLGlobals()
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index 9663e25cd93..389f913b145 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC_SYS
)
set(SRC
+ alembic.cpp
attribute.cpp
background.cpp
bake.cpp
@@ -48,6 +49,7 @@ set(SRC
mesh_displace.cpp
mesh_subdivision.cpp
nodes.cpp
+ procedural.cpp
object.cpp
osl.cpp
particles.cpp
@@ -64,6 +66,7 @@ set(SRC
)
set(SRC_HEADERS
+ alembic.h
attribute.h
bake.h
background.h
@@ -90,6 +93,7 @@ set(SRC_HEADERS
object.h
osl.h
particles.h
+ procedural.h
curves.h
scene.h
session.h
@@ -144,6 +148,16 @@ if(WITH_OPENVDB)
)
endif()
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_ALEMBIC)
+ list(APPEND INC_SYS
+ ${ALEMBIC_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${ALEMBIC_LIBRARIES}
+ )
+endif()
+
if(WITH_NANOVDB)
list(APPEND INC_SYS
${NANOVDB_INCLUDE_DIRS}
diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp
new file mode 100644
index 00000000000..e0e50d99f84
--- /dev/null
+++ b/intern/cycles/render/alembic.cpp
@@ -0,0 +1,1869 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "render/alembic.h"
+
+#include "render/camera.h"
+#include "render/curves.h"
+#include "render/mesh.h"
+#include "render/object.h"
+#include "render/scene.h"
+#include "render/shader.h"
+
+#include "util/util_foreach.h"
+#include "util/util_progress.h"
+#include "util/util_transform.h"
+#include "util/util_vector.h"
+
+#ifdef WITH_ALEMBIC
+
+using namespace Alembic::AbcGeom;
+
+CCL_NAMESPACE_BEGIN
+
+/* TODO(@kevindietrich): motion blur support */
+
+void CachedData::clear()
+{
+ attributes.clear();
+ curve_first_key.clear();
+ curve_keys.clear();
+ curve_radius.clear();
+ curve_shader.clear();
+ num_ngons.clear();
+ shader.clear();
+ subd_creases_edge.clear();
+ subd_creases_weight.clear();
+ subd_face_corners.clear();
+ subd_num_corners.clear();
+ subd_ptex_offset.clear();
+ subd_smooth.clear();
+ subd_start_corner.clear();
+ transforms.clear();
+ triangles.clear();
+ triangles_loops.clear();
+ vertices.clear();
+
+ for (CachedAttribute &attr : attributes) {
+ attr.data.clear();
+ }
+
+ attributes.clear();
+}
+
+CachedData::CachedAttribute &CachedData::add_attribute(const ustring &name,
+ const TimeSampling &time_sampling)
+{
+ for (auto &attr : attributes) {
+ if (attr.name == name) {
+ return attr;
+ }
+ }
+
+ CachedAttribute &attr = attributes.emplace_back();
+ attr.name = name;
+ attr.data.set_time_sampling(time_sampling);
+ return attr;
+}
+
+bool CachedData::is_constant() const
+{
+# define CHECK_IF_CONSTANT(data) \
+ if (!data.is_constant()) { \
+ return false; \
+ }
+
+ CHECK_IF_CONSTANT(curve_first_key)
+ CHECK_IF_CONSTANT(curve_keys)
+ CHECK_IF_CONSTANT(curve_radius)
+ CHECK_IF_CONSTANT(curve_shader)
+ CHECK_IF_CONSTANT(num_ngons)
+ CHECK_IF_CONSTANT(shader)
+ CHECK_IF_CONSTANT(subd_creases_edge)
+ CHECK_IF_CONSTANT(subd_creases_weight)
+ CHECK_IF_CONSTANT(subd_face_corners)
+ CHECK_IF_CONSTANT(subd_num_corners)
+ CHECK_IF_CONSTANT(subd_ptex_offset)
+ CHECK_IF_CONSTANT(subd_smooth)
+ CHECK_IF_CONSTANT(subd_start_corner)
+ CHECK_IF_CONSTANT(transforms)
+ CHECK_IF_CONSTANT(triangles)
+ CHECK_IF_CONSTANT(triangles_loops)
+ CHECK_IF_CONSTANT(vertices)
+
+ for (const CachedAttribute &attr : attributes) {
+ if (!attr.data.is_constant()) {
+ return false;
+ }
+ }
+
+ return true;
+
+# undef CHECK_IF_CONSTANT
+}
+
+void CachedData::invalidate_last_loaded_time(bool attributes_only)
+{
+ if (attributes_only) {
+ for (CachedAttribute &attr : attributes) {
+ attr.data.invalidate_last_loaded_time();
+ }
+
+ return;
+ }
+
+ curve_first_key.invalidate_last_loaded_time();
+ curve_keys.invalidate_last_loaded_time();
+ curve_radius.invalidate_last_loaded_time();
+ curve_shader.invalidate_last_loaded_time();
+ num_ngons.invalidate_last_loaded_time();
+ shader.invalidate_last_loaded_time();
+ subd_creases_edge.invalidate_last_loaded_time();
+ subd_creases_weight.invalidate_last_loaded_time();
+ subd_face_corners.invalidate_last_loaded_time();
+ subd_num_corners.invalidate_last_loaded_time();
+ subd_ptex_offset.invalidate_last_loaded_time();
+ subd_smooth.invalidate_last_loaded_time();
+ subd_start_corner.invalidate_last_loaded_time();
+ transforms.invalidate_last_loaded_time();
+ triangles.invalidate_last_loaded_time();
+ triangles_loops.invalidate_last_loaded_time();
+ vertices.invalidate_last_loaded_time();
+}
+
+void CachedData::set_time_sampling(TimeSampling time_sampling)
+{
+ curve_first_key.set_time_sampling(time_sampling);
+ curve_keys.set_time_sampling(time_sampling);
+ curve_radius.set_time_sampling(time_sampling);
+ curve_shader.set_time_sampling(time_sampling);
+ num_ngons.set_time_sampling(time_sampling);
+ shader.set_time_sampling(time_sampling);
+ subd_creases_edge.set_time_sampling(time_sampling);
+ subd_creases_weight.set_time_sampling(time_sampling);
+ subd_face_corners.set_time_sampling(time_sampling);
+ subd_num_corners.set_time_sampling(time_sampling);
+ subd_ptex_offset.set_time_sampling(time_sampling);
+ subd_smooth.set_time_sampling(time_sampling);
+ subd_start_corner.set_time_sampling(time_sampling);
+ transforms.set_time_sampling(time_sampling);
+ triangles.set_time_sampling(time_sampling);
+ triangles_loops.set_time_sampling(time_sampling);
+ vertices.set_time_sampling(time_sampling);
+
+ for (CachedAttribute &attr : attributes) {
+ attr.data.set_time_sampling(time_sampling);
+ }
+}
+
+/* get the sample times to load data for the given the start and end frame of the procedural */
+static set<chrono_t> get_relevant_sample_times(AlembicProcedural *proc,
+ const TimeSampling &time_sampling,
+ size_t num_samples)
+{
+ set<chrono_t> result;
+
+ if (num_samples < 2) {
+ result.insert(0.0);
+ return result;
+ }
+
+ double start_frame = (double)(proc->get_start_frame() / proc->get_frame_rate());
+ double end_frame = (double)((proc->get_end_frame() + 1) / proc->get_frame_rate());
+
+ size_t start_index = time_sampling.getFloorIndex(start_frame, num_samples).first;
+ size_t end_index = time_sampling.getCeilIndex(end_frame, num_samples).first;
+
+ for (size_t i = start_index; i < end_index; ++i) {
+ result.insert(time_sampling.getSampleTime(i));
+ }
+
+ return result;
+}
+
+static float3 make_float3_from_yup(const V3f &v)
+{
+ return make_float3(v.x, -v.z, v.y);
+}
+
+static M44d convert_yup_zup(const M44d &mtx, float scale_mult)
+{
+ V3d scale, shear, rotation, translation;
+ extractSHRT(mtx,
+ scale,
+ shear,
+ rotation,
+ translation,
+ true,
+ IMATH_INTERNAL_NAMESPACE::Euler<double>::XZY);
+
+ M44d rot_mat, scale_mat, trans_mat;
+ rot_mat.setEulerAngles(V3d(rotation.x, -rotation.z, rotation.y));
+ scale_mat.setScale(V3d(scale.x, scale.z, scale.y));
+ trans_mat.setTranslation(V3d(translation.x, -translation.z, translation.y));
+
+ M44d temp_mat = scale_mat * rot_mat * trans_mat;
+
+ scale_mat.setScale(static_cast<double>(scale_mult));
+
+ return temp_mat * scale_mat;
+}
+
+static void transform_decompose(
+ const M44d &mat, V3d &scale, V3d &shear, Quatd &rotation, V3d &translation)
+{
+ M44d mat_remainder(mat);
+
+ /* extract scale and shear */
+ Imath::extractAndRemoveScalingAndShear(mat_remainder, scale, shear);
+
+ /* extract translation */
+ translation.x = mat_remainder[3][0];
+ translation.y = mat_remainder[3][1];
+ translation.z = mat_remainder[3][2];
+
+ /* extract rotation */
+ rotation = extractQuat(mat_remainder);
+}
+
+static M44d transform_compose(const V3d &scale,
+ const V3d &shear,
+ const Quatd &rotation,
+ const V3d &translation)
+{
+ M44d scale_mat, shear_mat, rot_mat, trans_mat;
+
+ scale_mat.setScale(scale);
+ shear_mat.setShear(shear);
+ rot_mat = rotation.toMatrix44();
+ trans_mat.setTranslation(translation);
+
+ return scale_mat * shear_mat * rot_mat * trans_mat;
+}
+
+/* get the matrix for the specified time, or return the identity matrix if there is no exact match
+ */
+static M44d get_matrix_for_time(const MatrixSampleMap &samples, chrono_t time)
+{
+ MatrixSampleMap::const_iterator iter = samples.find(time);
+ if (iter != samples.end()) {
+ return iter->second;
+ }
+
+ return M44d();
+}
+
+/* get the matrix for the specified time, or interpolate between samples if there is no exact match
+ */
+static M44d get_interpolated_matrix_for_time(const MatrixSampleMap &samples, chrono_t time)
+{
+ if (samples.empty()) {
+ return M44d();
+ }
+
+ /* see if exact match */
+ MatrixSampleMap::const_iterator iter = samples.find(time);
+ if (iter != samples.end()) {
+ return iter->second;
+ }
+
+ if (samples.size() == 1) {
+ return samples.begin()->second;
+ }
+
+ if (time <= samples.begin()->first) {
+ return samples.begin()->second;
+ }
+
+ if (time >= samples.rbegin()->first) {
+ return samples.rbegin()->second;
+ }
+
+ /* find previous and next time sample to interpolate */
+ chrono_t prev_time = samples.begin()->first;
+ chrono_t next_time = samples.rbegin()->first;
+
+ for (MatrixSampleMap::const_iterator I = samples.begin(); I != samples.end(); ++I) {
+ chrono_t current_time = (*I).first;
+
+ if (current_time > prev_time && current_time <= time) {
+ prev_time = current_time;
+ }
+
+ if (current_time > next_time && current_time >= time) {
+ next_time = current_time;
+ }
+ }
+
+ const M44d prev_mat = get_matrix_for_time(samples, prev_time);
+ const M44d next_mat = get_matrix_for_time(samples, next_time);
+
+ V3d prev_scale, next_scale;
+ V3d prev_shear, next_shear;
+ V3d prev_translation, next_translation;
+ Quatd prev_rotation, next_rotation;
+
+ transform_decompose(prev_mat, prev_scale, prev_shear, prev_rotation, prev_translation);
+ transform_decompose(next_mat, next_scale, next_shear, next_rotation, next_translation);
+
+ chrono_t t = (time - prev_time) / (next_time - prev_time);
+
+ /* ensure rotation around the shortest angle */
+ if ((prev_rotation ^ next_rotation) < 0) {
+ next_rotation = -next_rotation;
+ }
+
+ return transform_compose(Imath::lerp(prev_scale, next_scale, t),
+ Imath::lerp(prev_shear, next_shear, t),
+ Imath::slerp(prev_rotation, next_rotation, t),
+ Imath::lerp(prev_translation, next_translation, t));
+}
+
+static void concatenate_xform_samples(const MatrixSampleMap &parent_samples,
+ const MatrixSampleMap &local_samples,
+ MatrixSampleMap &output_samples)
+{
+ set<chrono_t> union_of_samples;
+
+ for (const std::pair<chrono_t, M44d> pair : parent_samples) {
+ union_of_samples.insert(pair.first);
+ }
+
+ for (const std::pair<chrono_t, M44d> pair : local_samples) {
+ union_of_samples.insert(pair.first);
+ }
+
+ foreach (chrono_t time, union_of_samples) {
+ M44d parent_matrix = get_interpolated_matrix_for_time(parent_samples, time);
+ M44d local_matrix = get_interpolated_matrix_for_time(local_samples, time);
+
+ output_samples[time] = local_matrix * parent_matrix;
+ }
+}
+
+static Transform make_transform(const M44d &a, float scale)
+{
+ M44d m = convert_yup_zup(a, scale);
+ Transform trans;
+ for (int j = 0; j < 3; j++) {
+ for (int i = 0; i < 4; i++) {
+ trans[j][i] = static_cast<float>(m[i][j]);
+ }
+ }
+ return trans;
+}
+
+static void add_uvs(AlembicProcedural *proc,
+ const IV2fGeomParam &uvs,
+ CachedData &cached_data,
+ Progress &progress)
+{
+ if (uvs.getScope() != kFacevaryingScope) {
+ return;
+ }
+
+ const TimeSamplingPtr time_sampling_ptr = uvs.getTimeSampling();
+
+ TimeSampling time_sampling;
+ if (time_sampling_ptr) {
+ time_sampling = *time_sampling_ptr;
+ }
+
+ std::string name = Alembic::Abc::GetSourceName(uvs.getMetaData());
+
+ /* According to the convention, primary UVs should have had their name
+ * set using Alembic::Abc::SetSourceName, but you can't expect everyone
+ * to follow it! :) */
+ if (name.empty()) {
+ name = uvs.getName();
+ }
+
+ CachedData::CachedAttribute &attr = cached_data.add_attribute(ustring(name), time_sampling);
+ attr.std = ATTR_STD_UV;
+
+ ccl::set<chrono_t> times = get_relevant_sample_times(proc, time_sampling, uvs.getNumSamples());
+
+ foreach (chrono_t time, times) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ const ISampleSelector iss = ISampleSelector(time);
+ const IV2fGeomParam::Sample sample = uvs.getExpandedValue(iss);
+
+ const IV2fGeomParam::Sample uvsample = uvs.getIndexedValue(iss);
+
+ if (!uvsample.valid()) {
+ continue;
+ }
+
+ const array<int3> *triangles = cached_data.triangles.data_for_time_no_check(time);
+ const array<int3> *triangles_loops = cached_data.triangles_loops.data_for_time_no_check(time);
+
+ if (!triangles || !triangles_loops) {
+ continue;
+ }
+
+ array<char> data;
+ data.resize(triangles->size() * 3 * sizeof(float2));
+
+ float2 *data_float2 = reinterpret_cast<float2 *>(data.data());
+
+ const unsigned int *indices = uvsample.getIndices()->get();
+ const V2f *values = uvsample.getVals()->get();
+
+ for (const int3 &loop : *triangles_loops) {
+ unsigned int v0 = indices[loop.x];
+ unsigned int v1 = indices[loop.y];
+ unsigned int v2 = indices[loop.z];
+
+ data_float2[0] = make_float2(values[v0][0], values[v0][1]);
+ data_float2[1] = make_float2(values[v1][0], values[v1][1]);
+ data_float2[2] = make_float2(values[v2][0], values[v2][1]);
+ data_float2 += 3;
+ }
+
+ attr.data.add_data(data, time);
+ }
+}
+
+static void add_normals(const Int32ArraySamplePtr face_indices,
+ const IN3fGeomParam &normals,
+ double time,
+ CachedData &cached_data)
+{
+ switch (normals.getScope()) {
+ case kFacevaryingScope: {
+ const ISampleSelector iss = ISampleSelector(time);
+ const IN3fGeomParam::Sample sample = normals.getExpandedValue(iss);
+
+ if (!sample.valid()) {
+ return;
+ }
+
+ CachedData::CachedAttribute &attr = cached_data.add_attribute(ustring(normals.getName()),
+ *normals.getTimeSampling());
+ attr.std = ATTR_STD_VERTEX_NORMAL;
+
+ const array<float3> *vertices = cached_data.vertices.data_for_time_no_check(time);
+
+ if (!vertices) {
+ return;
+ }
+
+ array<char> data;
+ data.resize(vertices->size() * sizeof(float3));
+
+ float3 *data_float3 = reinterpret_cast<float3 *>(data.data());
+
+ const int *face_indices_array = face_indices->get();
+ const N3fArraySamplePtr values = sample.getVals();
+
+ for (size_t i = 0; i < face_indices->size(); ++i) {
+ int point_index = face_indices_array[i];
+ data_float3[point_index] = make_float3_from_yup(values->get()[i]);
+ }
+
+ attr.data.add_data(data, time);
+ break;
+ }
+ case kVaryingScope:
+ case kVertexScope: {
+ const ISampleSelector iss = ISampleSelector(time);
+ const IN3fGeomParam::Sample sample = normals.getExpandedValue(iss);
+
+ if (!sample.valid()) {
+ return;
+ }
+
+ CachedData::CachedAttribute &attr = cached_data.add_attribute(ustring(normals.getName()),
+ *normals.getTimeSampling());
+ attr.std = ATTR_STD_VERTEX_NORMAL;
+
+ const array<float3> *vertices = cached_data.vertices.data_for_time_no_check(time);
+
+ if (!vertices) {
+ return;
+ }
+
+ array<char> data;
+ data.resize(vertices->size() * sizeof(float3));
+
+ float3 *data_float3 = reinterpret_cast<float3 *>(data.data());
+
+ const Imath::V3f *values = sample.getVals()->get();
+
+ for (size_t i = 0; i < vertices->size(); ++i) {
+ data_float3[i] = make_float3_from_yup(values[i]);
+ }
+
+ attr.data.add_data(data, time);
+
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+static void add_positions(const P3fArraySamplePtr positions, double time, CachedData &cached_data)
+{
+ if (!positions) {
+ return;
+ }
+
+ array<float3> vertices;
+ vertices.reserve(positions->size());
+
+ for (size_t i = 0; i < positions->size(); i++) {
+ V3f f = positions->get()[i];
+ vertices.push_back_reserved(make_float3_from_yup(f));
+ }
+
+ cached_data.vertices.add_data(vertices, time);
+}
+
+static void add_triangles(const Int32ArraySamplePtr face_counts,
+ const Int32ArraySamplePtr face_indices,
+ double time,
+ CachedData &cached_data,
+ const array<int> &polygon_to_shader)
+{
+ if (!face_counts || !face_indices) {
+ return;
+ }
+
+ const size_t num_faces = face_counts->size();
+ const int *face_counts_array = face_counts->get();
+ const int *face_indices_array = face_indices->get();
+
+ size_t num_triangles = 0;
+ for (size_t i = 0; i < face_counts->size(); i++) {
+ num_triangles += face_counts_array[i] - 2;
+ }
+
+ array<int> shader;
+ array<int3> triangles;
+ array<int3> triangles_loops;
+ shader.reserve(num_triangles);
+ triangles.reserve(num_triangles);
+ triangles_loops.reserve(num_triangles);
+ int index_offset = 0;
+
+ for (size_t i = 0; i < num_faces; i++) {
+ int current_shader = 0;
+
+ if (!polygon_to_shader.empty()) {
+ current_shader = polygon_to_shader[i];
+ }
+
+ for (int j = 0; j < face_counts_array[i] - 2; j++) {
+ int v0 = face_indices_array[index_offset];
+ int v1 = face_indices_array[index_offset + j + 1];
+ int v2 = face_indices_array[index_offset + j + 2];
+
+ shader.push_back_reserved(current_shader);
+
+ /* Alembic orders the loops following the RenderMan convention, so need to go in reverse. */
+ triangles.push_back_reserved(make_int3(v2, v1, v0));
+ triangles_loops.push_back_reserved(
+ make_int3(index_offset + j + 2, index_offset + j + 1, index_offset));
+ }
+
+ index_offset += face_counts_array[i];
+ }
+
+ cached_data.triangles.add_data(triangles, time);
+ cached_data.triangles_loops.add_data(triangles_loops, time);
+ cached_data.shader.add_data(shader, time);
+}
+
+NODE_DEFINE(AlembicObject)
+{
+ NodeType *type = NodeType::add("alembic_object", create);
+
+ SOCKET_STRING(path, "Alembic Path", ustring());
+ SOCKET_NODE_ARRAY(used_shaders, "Used Shaders", &Shader::node_type);
+
+ SOCKET_INT(subd_max_level, "Max Subdivision Level", 1);
+ SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 1.0f);
+
+ SOCKET_FLOAT(radius_scale, "Radius Scale", 1.0f);
+
+ return type;
+}
+
+AlembicObject::AlembicObject() : Node(node_type)
+{
+}
+
+AlembicObject::~AlembicObject()
+{
+}
+
+void AlembicObject::set_object(Object *object_)
+{
+ object = object_;
+}
+
+Object *AlembicObject::get_object()
+{
+ return object;
+}
+
+bool AlembicObject::has_data_loaded() const
+{
+ return data_loaded;
+}
+
+void AlembicObject::update_shader_attributes(const ICompoundProperty &arb_geom_params,
+ Progress &progress)
+{
+ AttributeRequestSet requested_attributes = get_requested_attributes();
+
+ foreach (const AttributeRequest &attr, requested_attributes.requests) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ bool attr_exists = false;
+ foreach (CachedData::CachedAttribute &cached_attr, cached_data.attributes) {
+ if (cached_attr.name == attr.name) {
+ attr_exists = true;
+ break;
+ }
+ }
+
+ if (attr_exists) {
+ continue;
+ }
+
+ read_attribute(arb_geom_params, attr.name, progress);
+ }
+
+ cached_data.invalidate_last_loaded_time(true);
+ need_shader_update = false;
+}
+
+template<typename SchemaType>
+void AlembicObject::read_face_sets(SchemaType &schema,
+ array<int> &polygon_to_shader,
+ ISampleSelector sample_sel)
+{
+ std::vector<std::string> face_sets;
+ schema.getFaceSetNames(face_sets);
+
+ if (face_sets.empty()) {
+ return;
+ }
+
+ const Int32ArraySamplePtr face_counts = schema.getFaceCountsProperty().getValue();
+
+ polygon_to_shader.resize(face_counts->size());
+
+ foreach (const std::string &face_set_name, face_sets) {
+ int shader_index = 0;
+
+ foreach (Node *node, get_used_shaders()) {
+ if (node->name == face_set_name) {
+ break;
+ }
+
+ ++shader_index;
+ }
+
+ if (shader_index >= get_used_shaders().size()) {
+ /* use the first shader instead if none was found */
+ shader_index = 0;
+ }
+
+ const IFaceSet face_set = schema.getFaceSet(face_set_name);
+
+ if (!face_set.valid()) {
+ continue;
+ }
+
+ const IFaceSetSchema face_schem = face_set.getSchema();
+ const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel);
+ const Int32ArraySamplePtr group_faces = face_sample.getFaces();
+ const size_t num_group_faces = group_faces->size();
+
+ for (size_t l = 0; l < num_group_faces; l++) {
+ size_t pos = (*group_faces)[l];
+
+ if (pos >= polygon_to_shader.size()) {
+ continue;
+ }
+
+ polygon_to_shader[pos] = shader_index;
+ }
+ }
+}
+
+void AlembicObject::load_all_data(AlembicProcedural *proc,
+ IPolyMeshSchema &schema,
+ float scale,
+ Progress &progress)
+{
+ cached_data.clear();
+
+ const TimeSamplingPtr time_sampling = schema.getTimeSampling();
+ cached_data.set_time_sampling(*time_sampling);
+
+ const IN3fGeomParam &normals = schema.getNormalsParam();
+
+ ccl::set<chrono_t> times = get_relevant_sample_times(
+ proc, *time_sampling, schema.getNumSamples());
+
+ /* read topology */
+ foreach (chrono_t time, times) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ const ISampleSelector iss = ISampleSelector(time);
+ const IPolyMeshSchema::Sample sample = schema.getValue(iss);
+
+ add_positions(sample.getPositions(), time, cached_data);
+
+ /* Only copy triangles for other frames if the topology is changing over time as well.
+ *
+ * TODO(@kevindietrich): even for dynamic simulations, this is a waste of memory and
+ * processing time if only the positions are changing in a subsequence of frames but we
+ * cannot optimize in this current system if the attributes are changing over time as well,
+ * as we need valid data for each time point. This can be solved by using reference counting
+ * on the ccl::array and simply share the array across frames. */
+ if (schema.getTopologyVariance() != kHomogenousTopology || cached_data.triangles.size() == 0) {
+ /* start by reading the face sets (per face shader), as we directly split polygons to
+ * triangles
+ */
+ array<int> polygon_to_shader;
+ read_face_sets(schema, polygon_to_shader, iss);
+
+ add_triangles(
+ sample.getFaceCounts(), sample.getFaceIndices(), time, cached_data, polygon_to_shader);
+ }
+
+ if (normals.valid()) {
+ add_normals(sample.getFaceIndices(), normals, time, cached_data);
+ }
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ update_shader_attributes(schema.getArbGeomParams(), progress);
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ const IV2fGeomParam &uvs = schema.getUVsParam();
+
+ if (uvs.valid()) {
+ add_uvs(proc, uvs, cached_data, progress);
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ setup_transform_cache(scale);
+
+ data_loaded = true;
+}
+
+void AlembicObject::load_all_data(AlembicProcedural *proc,
+ ISubDSchema &schema,
+ float scale,
+ Progress &progress)
+{
+ cached_data.clear();
+
+ AttributeRequestSet requested_attributes = get_requested_attributes();
+
+ const TimeSamplingPtr time_sampling = schema.getTimeSampling();
+ cached_data.set_time_sampling(*time_sampling);
+
+ ccl::set<chrono_t> times = get_relevant_sample_times(
+ proc, *time_sampling, schema.getNumSamples());
+
+ /* read topology */
+ foreach (chrono_t time, times) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ const ISampleSelector iss = ISampleSelector(time);
+ const ISubDSchema::Sample sample = schema.getValue(iss);
+
+ add_positions(sample.getPositions(), time, cached_data);
+
+ const Int32ArraySamplePtr face_counts = sample.getFaceCounts();
+ const Int32ArraySamplePtr face_indices = sample.getFaceIndices();
+
+ /* start by reading the face sets (per face shader) */
+ array<int> polygon_to_shader;
+ read_face_sets(schema, polygon_to_shader, iss);
+
+ /* read faces */
+ array<int> subd_start_corner;
+ array<int> shader;
+ array<int> subd_num_corners;
+ array<bool> subd_smooth;
+ array<int> subd_ptex_offset;
+ array<int> subd_face_corners;
+
+ const size_t num_faces = face_counts->size();
+ const int *face_counts_array = face_counts->get();
+ const int *face_indices_array = face_indices->get();
+
+ int num_ngons = 0;
+ int num_corners = 0;
+ for (size_t i = 0; i < face_counts->size(); i++) {
+ num_ngons += (face_counts_array[i] == 4 ? 0 : 1);
+ num_corners += face_counts_array[i];
+ }
+
+ subd_start_corner.reserve(num_faces);
+ subd_num_corners.reserve(num_faces);
+ subd_smooth.reserve(num_faces);
+ subd_ptex_offset.reserve(num_faces);
+ shader.reserve(num_faces);
+ subd_face_corners.reserve(num_corners);
+
+ int start_corner = 0;
+ int current_shader = 0;
+ int ptex_offset = 0;
+
+ for (size_t i = 0; i < face_counts->size(); i++) {
+ num_corners = face_counts_array[i];
+
+ if (!polygon_to_shader.empty()) {
+ current_shader = polygon_to_shader[i];
+ }
+
+ subd_start_corner.push_back_reserved(start_corner);
+ subd_num_corners.push_back_reserved(num_corners);
+
+ for (int j = 0; j < num_corners; ++j) {
+ subd_face_corners.push_back_reserved(face_indices_array[start_corner + j]);
+ }
+
+ shader.push_back_reserved(current_shader);
+ subd_smooth.push_back_reserved(1);
+ subd_ptex_offset.push_back_reserved(ptex_offset);
+
+ ptex_offset += (num_corners == 4 ? 1 : num_corners);
+
+ start_corner += num_corners;
+ }
+
+ cached_data.shader.add_data(shader, time);
+ cached_data.subd_start_corner.add_data(subd_start_corner, time);
+ cached_data.subd_num_corners.add_data(subd_num_corners, time);
+ cached_data.subd_smooth.add_data(subd_smooth, time);
+ cached_data.subd_ptex_offset.add_data(subd_ptex_offset, time);
+ cached_data.subd_face_corners.add_data(subd_face_corners, time);
+ cached_data.num_ngons.add_data(num_ngons, time);
+
+ /* read creases */
+ Int32ArraySamplePtr creases_length = sample.getCreaseLengths();
+ Int32ArraySamplePtr creases_indices = sample.getCreaseIndices();
+ FloatArraySamplePtr creases_sharpnesses = sample.getCreaseSharpnesses();
+
+ if (creases_length && creases_indices && creases_sharpnesses) {
+ array<int> creases_edge;
+ array<float> creases_weight;
+
+ creases_edge.reserve(creases_sharpnesses->size() * 2);
+ creases_weight.reserve(creases_sharpnesses->size());
+
+ int length_offset = 0;
+ int weight_offset = 0;
+ for (size_t c = 0; c < creases_length->size(); ++c) {
+ const int crease_length = creases_length->get()[c];
+
+ for (size_t j = 0; j < crease_length - 1; ++j) {
+ creases_edge.push_back_reserved(creases_indices->get()[length_offset + j]);
+ creases_edge.push_back_reserved(creases_indices->get()[length_offset + j + 1]);
+ creases_weight.push_back_reserved(creases_sharpnesses->get()[weight_offset++]);
+ }
+
+ length_offset += crease_length;
+ }
+
+ cached_data.subd_creases_edge.add_data(creases_edge, time);
+ cached_data.subd_creases_weight.add_data(creases_weight, time);
+ }
+ }
+
+ /* TODO(@kevindietrich) : attributes, need test files */
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ setup_transform_cache(scale);
+
+ data_loaded = true;
+}
+
+void AlembicObject::load_all_data(AlembicProcedural *proc,
+ const ICurvesSchema &schema,
+ float scale,
+ Progress &progress,
+ float default_radius)
+{
+ cached_data.clear();
+
+ const TimeSamplingPtr time_sampling = schema.getTimeSampling();
+ cached_data.set_time_sampling(*time_sampling);
+
+ ccl::set<chrono_t> times = get_relevant_sample_times(
+ proc, *time_sampling, schema.getNumSamples());
+
+ foreach (chrono_t time, times) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ const ISampleSelector iss = ISampleSelector(time);
+ const ICurvesSchema::Sample sample = schema.getValue(iss);
+
+ const Int32ArraySamplePtr curves_num_vertices = sample.getCurvesNumVertices();
+ const P3fArraySamplePtr position = sample.getPositions();
+
+ const IFloatGeomParam widths_param = schema.getWidthsParam();
+ FloatArraySamplePtr radiuses;
+
+ if (widths_param.valid()) {
+ IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(iss);
+ radiuses = wsample.getVals();
+ }
+
+ const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
+ float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : default_radius;
+
+ array<float3> curve_keys;
+ array<float> curve_radius;
+ array<int> curve_first_key;
+ array<int> curve_shader;
+
+ curve_keys.reserve(position->size());
+ curve_radius.reserve(position->size());
+ curve_first_key.reserve(curves_num_vertices->size());
+ curve_shader.reserve(curves_num_vertices->size());
+
+ int offset = 0;
+ for (size_t i = 0; i < curves_num_vertices->size(); i++) {
+ const int num_vertices = curves_num_vertices->get()[i];
+
+ for (int j = 0; j < num_vertices; j++) {
+ const V3f &f = position->get()[offset + j];
+ curve_keys.push_back_reserved(make_float3_from_yup(f));
+
+ if (do_radius) {
+ radius = (*radiuses)[offset + j];
+ }
+
+ curve_radius.push_back_reserved(radius * radius_scale);
+ }
+
+ curve_first_key.push_back_reserved(offset);
+ curve_shader.push_back_reserved(0);
+
+ offset += num_vertices;
+ }
+
+ cached_data.curve_keys.add_data(curve_keys, time);
+ cached_data.curve_radius.add_data(curve_radius, time);
+ cached_data.curve_first_key.add_data(curve_first_key, time);
+ cached_data.curve_shader.add_data(curve_shader, time);
+ }
+
+ // TODO(@kevindietrich): attributes, need example files
+
+ setup_transform_cache(scale);
+
+ data_loaded = true;
+}
+
+void AlembicObject::setup_transform_cache(float scale)
+{
+ cached_data.transforms.clear();
+ cached_data.transforms.invalidate_last_loaded_time();
+
+ if (xform_samples.size() == 0) {
+ Transform tfm = transform_scale(make_float3(scale));
+ cached_data.transforms.add_data(tfm, 0.0);
+ }
+ else {
+ /* It is possible for a leaf node of the hierarchy to have multiple samples for its transforms
+ * if a sibling has animated transforms. So check if we indeed have animated transformations.
+ */
+ M44d first_matrix = xform_samples.begin()->first;
+ bool has_animation = false;
+ for (const std::pair<chrono_t, M44d> pair : xform_samples) {
+ if (pair.second != first_matrix) {
+ has_animation = true;
+ break;
+ }
+ }
+
+ if (!has_animation) {
+ Transform tfm = make_transform(first_matrix, scale);
+ cached_data.transforms.add_data(tfm, 0.0);
+ }
+ else {
+ for (const std::pair<chrono_t, M44d> pair : xform_samples) {
+ Transform tfm = make_transform(pair.second, scale);
+ cached_data.transforms.add_data(tfm, pair.first);
+ }
+ }
+ }
+}
+
+AttributeRequestSet AlembicObject::get_requested_attributes()
+{
+ AttributeRequestSet requested_attributes;
+
+ Geometry *geometry = object->get_geometry();
+ assert(geometry);
+
+ foreach (Node *node, geometry->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+
+ foreach (const AttributeRequest &attr, shader->attributes.requests) {
+ if (attr.name != "") {
+ requested_attributes.add(attr.name);
+ }
+ }
+ }
+
+ return requested_attributes;
+}
+
+void AlembicObject::read_attribute(const ICompoundProperty &arb_geom_params,
+ const ustring &attr_name,
+ Progress &progress)
+{
+ const PropertyHeader *prop = arb_geom_params.getPropertyHeader(attr_name.c_str());
+
+ if (prop == nullptr) {
+ return;
+ }
+
+ if (IV2fProperty::matches(prop->getMetaData()) && Alembic::AbcGeom::isUV(*prop)) {
+ const IV2fGeomParam &param = IV2fGeomParam(arb_geom_params, prop->getName());
+
+ CachedData::CachedAttribute &attribute = cached_data.add_attribute(attr_name,
+ *param.getTimeSampling());
+
+ for (size_t i = 0; i < param.getNumSamples(); ++i) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ ISampleSelector iss = ISampleSelector(index_t(i));
+
+ IV2fGeomParam::Sample sample;
+ param.getIndexed(sample, iss);
+
+ const chrono_t time = param.getTimeSampling()->getSampleTime(index_t(i));
+
+ if (param.getScope() == kFacevaryingScope) {
+ V2fArraySamplePtr values = sample.getVals();
+ UInt32ArraySamplePtr indices = sample.getIndices();
+
+ attribute.std = ATTR_STD_NONE;
+ attribute.element = ATTR_ELEMENT_CORNER;
+ attribute.type_desc = TypeFloat2;
+
+ const array<int3> *triangles = cached_data.triangles.data_for_time_no_check(time);
+ const array<int3> *triangles_loops = cached_data.triangles_loops.data_for_time_no_check(
+ time);
+
+ if (!triangles || !triangles_loops) {
+ return;
+ }
+
+ array<char> data;
+ data.resize(triangles->size() * 3 * sizeof(float2));
+
+ float2 *data_float2 = reinterpret_cast<float2 *>(data.data());
+
+ for (const int3 &loop : *triangles_loops) {
+ unsigned int v0 = (*indices)[loop.x];
+ unsigned int v1 = (*indices)[loop.y];
+ unsigned int v2 = (*indices)[loop.z];
+
+ data_float2[0] = make_float2((*values)[v0][0], (*values)[v0][1]);
+ data_float2[1] = make_float2((*values)[v1][0], (*values)[v1][1]);
+ data_float2[2] = make_float2((*values)[v2][0], (*values)[v2][1]);
+ data_float2 += 3;
+ }
+
+ attribute.data.set_time_sampling(*param.getTimeSampling());
+ attribute.data.add_data(data, time);
+ }
+ }
+ }
+ else if (IC3fProperty::matches(prop->getMetaData())) {
+ const IC3fGeomParam &param = IC3fGeomParam(arb_geom_params, prop->getName());
+
+ CachedData::CachedAttribute &attribute = cached_data.add_attribute(attr_name,
+ *param.getTimeSampling());
+
+ for (size_t i = 0; i < param.getNumSamples(); ++i) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ ISampleSelector iss = ISampleSelector(index_t(i));
+
+ IC3fGeomParam::Sample sample;
+ param.getIndexed(sample, iss);
+
+ const chrono_t time = param.getTimeSampling()->getSampleTime(index_t(i));
+
+ C3fArraySamplePtr values = sample.getVals();
+
+ attribute.std = ATTR_STD_NONE;
+
+ if (param.getScope() == kVaryingScope) {
+ attribute.element = ATTR_ELEMENT_CORNER_BYTE;
+ attribute.type_desc = TypeRGBA;
+
+ const array<int3> *triangles = cached_data.triangles.data_for_time_no_check(time);
+
+ if (!triangles) {
+ return;
+ }
+
+ array<char> data;
+ data.resize(triangles->size() * 3 * sizeof(uchar4));
+
+ uchar4 *data_uchar4 = reinterpret_cast<uchar4 *>(data.data());
+
+ int offset = 0;
+ for (const int3 &tri : *triangles) {
+ Imath::C3f v = (*values)[tri.x];
+ data_uchar4[offset + 0] = color_float_to_byte(make_float3(v.x, v.y, v.z));
+
+ v = (*values)[tri.y];
+ data_uchar4[offset + 1] = color_float_to_byte(make_float3(v.x, v.y, v.z));
+
+ v = (*values)[tri.z];
+ data_uchar4[offset + 2] = color_float_to_byte(make_float3(v.x, v.y, v.z));
+
+ offset += 3;
+ }
+
+ attribute.data.set_time_sampling(*param.getTimeSampling());
+ attribute.data.add_data(data, time);
+ }
+ }
+ }
+ else if (IC4fProperty::matches(prop->getMetaData())) {
+ const IC4fGeomParam &param = IC4fGeomParam(arb_geom_params, prop->getName());
+
+ CachedData::CachedAttribute &attribute = cached_data.add_attribute(attr_name,
+ *param.getTimeSampling());
+
+ for (size_t i = 0; i < param.getNumSamples(); ++i) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ ISampleSelector iss = ISampleSelector(index_t(i));
+
+ IC4fGeomParam::Sample sample;
+ param.getIndexed(sample, iss);
+
+ const chrono_t time = param.getTimeSampling()->getSampleTime(index_t(i));
+
+ C4fArraySamplePtr values = sample.getVals();
+
+ attribute.std = ATTR_STD_NONE;
+
+ if (param.getScope() == kVaryingScope) {
+ attribute.element = ATTR_ELEMENT_CORNER_BYTE;
+ attribute.type_desc = TypeRGBA;
+
+ const array<int3> *triangles = cached_data.triangles.data_for_time_no_check(time);
+
+ if (!triangles) {
+ return;
+ }
+
+ array<char> data;
+ data.resize(triangles->size() * 3 * sizeof(uchar4));
+
+ uchar4 *data_uchar4 = reinterpret_cast<uchar4 *>(data.data());
+
+ int offset = 0;
+ for (const int3 &tri : *triangles) {
+ Imath::C4f v = (*values)[tri.x];
+ data_uchar4[offset + 0] = color_float4_to_uchar4(make_float4(v.r, v.g, v.b, v.a));
+
+ v = (*values)[tri.y];
+ data_uchar4[offset + 1] = color_float4_to_uchar4(make_float4(v.r, v.g, v.b, v.a));
+
+ v = (*values)[tri.z];
+ data_uchar4[offset + 2] = color_float4_to_uchar4(make_float4(v.r, v.g, v.b, v.a));
+
+ offset += 3;
+ }
+
+ attribute.data.set_time_sampling(*param.getTimeSampling());
+ attribute.data.add_data(data, time);
+ }
+ }
+ }
+}
+
+/* Update existing attributes and remove any attribute not in the cached_data, those attributes
+ * were added by Cycles (e.g. face normals) */
+static void update_attributes(AttributeSet &attributes, CachedData &cached_data, double frame_time)
+{
+ set<Attribute *> cached_attributes;
+
+ for (CachedData::CachedAttribute &attribute : cached_data.attributes) {
+ const array<char> *attr_data = attribute.data.data_for_time(frame_time);
+
+ Attribute *attr = nullptr;
+ if (attribute.std != ATTR_STD_NONE) {
+ attr = attributes.add(attribute.std, attribute.name);
+ }
+ else {
+ attr = attributes.add(attribute.name, attribute.type_desc, attribute.element);
+ }
+ assert(attr);
+
+ cached_attributes.insert(attr);
+
+ if (!attr_data) {
+ /* no new data */
+ continue;
+ }
+
+ /* weak way of detecting if the topology has changed
+ * todo: reuse code from device_update patch */
+ if (attr->buffer.size() != attr_data->size()) {
+ attr->buffer.resize(attr_data->size());
+ }
+
+ memcpy(attr->data(), attr_data->data(), attr_data->size());
+ }
+
+ /* remove any attributes not in cached_attributes */
+ list<Attribute>::iterator it;
+ for (it = attributes.attributes.begin(); it != attributes.attributes.end();) {
+ if (cached_attributes.find(&(*it)) == cached_attributes.end()) {
+ attributes.attributes.erase(it++);
+ continue;
+ }
+
+ it++;
+ }
+}
+
+NODE_DEFINE(AlembicProcedural)
+{
+ NodeType *type = NodeType::add("alembic", create);
+
+ SOCKET_STRING(filepath, "Filename", ustring());
+ SOCKET_FLOAT(frame, "Frame", 1.0f);
+ SOCKET_FLOAT(start_frame, "Start Frame", 1.0f);
+ SOCKET_FLOAT(end_frame, "End Frame", 1.0f);
+ SOCKET_FLOAT(frame_rate, "Frame Rate", 24.0f);
+ SOCKET_FLOAT(frame_offset, "Frame Offset", 0.0f);
+ SOCKET_FLOAT(default_radius, "Default Radius", 0.01f);
+ SOCKET_FLOAT(scale, "Scale", 1.0f);
+
+ SOCKET_NODE_ARRAY(objects, "Objects", &AlembicObject::node_type);
+
+ return type;
+}
+
+AlembicProcedural::AlembicProcedural() : Procedural(node_type)
+{
+ objects_loaded = false;
+ scene_ = nullptr;
+}
+
+AlembicProcedural::~AlembicProcedural()
+{
+ ccl::set<Geometry *> geometries_set;
+ ccl::set<Object *> objects_set;
+ ccl::set<AlembicObject *> abc_objects_set;
+
+ foreach (Node *node, objects) {
+ AlembicObject *abc_object = static_cast<AlembicObject *>(node);
+
+ objects_set.insert(abc_object->get_object());
+ geometries_set.insert(abc_object->get_object()->get_geometry());
+
+ delete_node(abc_object);
+ }
+
+ scene_->delete_nodes(geometries_set, this);
+ scene_->delete_nodes(objects_set, this);
+}
+
+void AlembicProcedural::generate(Scene *scene, Progress &progress)
+{
+ assert(scene_ == nullptr || scene_ == scene);
+ scene_ = scene;
+
+ bool need_shader_updates = false;
+
+ /* check for changes in shaders (newly requested atttributes) */
+ foreach (Node *object_node, objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(object_node);
+
+ foreach (Node *shader_node, object->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(shader_node);
+
+ if (shader->need_update_geometry()) {
+ object->need_shader_update = true;
+ need_shader_updates = true;
+ }
+ }
+ }
+
+ if (!is_modified() && !need_shader_updates) {
+ return;
+ }
+
+ if (!archive.valid()) {
+ Alembic::AbcCoreFactory::IFactory factory;
+ factory.setPolicy(Alembic::Abc::ErrorHandler::kQuietNoopPolicy);
+ archive = factory.getArchive(filepath.c_str());
+
+ if (!archive.valid()) {
+ /* avoid potential infinite update loops in viewport synchronization */
+ filepath.clear();
+ clear_modified();
+ return;
+ }
+ }
+
+ if (!objects_loaded || objects_is_modified()) {
+ load_objects(progress);
+ objects_loaded = true;
+ }
+
+ const chrono_t frame_time = (chrono_t)((frame - frame_offset) / frame_rate);
+
+ foreach (Node *node, objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(node);
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ /* skip constant objects */
+ if (object->has_data_loaded() && object->is_constant() && !object->is_modified() &&
+ !object->need_shader_update && !scale_is_modified()) {
+ continue;
+ }
+
+ if (IPolyMesh::matches(object->iobject.getHeader())) {
+ read_mesh(scene, object, frame_time, progress);
+ }
+ else if (ICurves::matches(object->iobject.getHeader())) {
+ read_curves(scene, object, frame_time, progress);
+ }
+ else if (ISubD::matches(object->iobject.getHeader())) {
+ read_subd(scene, object, frame_time, progress);
+ }
+
+ object->clear_modified();
+ }
+
+ clear_modified();
+}
+
+void AlembicProcedural::add_object(AlembicObject *object)
+{
+ objects.push_back_slow(object);
+ tag_objects_modified();
+}
+
+void AlembicProcedural::tag_update(Scene *scene)
+{
+ scene->procedural_manager->tag_update();
+}
+
+AlembicObject *AlembicProcedural::get_or_create_object(const ustring &path)
+{
+ foreach (Node *node, objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(node);
+
+ if (object->get_path() == path) {
+ return object;
+ }
+ }
+
+ AlembicObject *object = create_node<AlembicObject>();
+ object->set_path(path);
+
+ add_object(object);
+
+ return object;
+}
+
+void AlembicProcedural::load_objects(Progress &progress)
+{
+ unordered_map<string, AlembicObject *> object_map;
+
+ foreach (Node *node, objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(node);
+
+ /* only consider newly added objects */
+ if (object->get_object() == nullptr) {
+ object_map.insert({object->get_path().c_str(), object});
+ }
+ }
+
+ IObject root = archive.getTop();
+
+ for (size_t i = 0; i < root.getNumChildren(); ++i) {
+ walk_hierarchy(root, root.getChildHeader(i), nullptr, object_map, progress);
+ }
+}
+
+void AlembicProcedural::read_mesh(Scene *scene,
+ AlembicObject *abc_object,
+ Abc::chrono_t frame_time,
+ Progress &progress)
+{
+ IPolyMesh polymesh(abc_object->iobject, Alembic::Abc::kWrapExisting);
+
+ Mesh *mesh = nullptr;
+
+ /* create a mesh node in the scene if not already done */
+ if (!abc_object->get_object()) {
+ mesh = scene->create_node<Mesh>();
+ mesh->set_owner(this);
+ mesh->name = abc_object->iobject.getName();
+
+ array<Node *> used_shaders = abc_object->get_used_shaders();
+ mesh->set_used_shaders(used_shaders);
+
+ /* create object*/
+ Object *object = scene->create_node<Object>();
+ object->set_owner(this);
+ object->set_geometry(mesh);
+ object->set_tfm(abc_object->xform);
+ object->name = abc_object->iobject.getName();
+
+ abc_object->set_object(object);
+ }
+ else {
+ mesh = static_cast<Mesh *>(abc_object->get_object()->get_geometry());
+ }
+
+ CachedData &cached_data = abc_object->get_cached_data();
+ IPolyMeshSchema schema = polymesh.getSchema();
+
+ if (!abc_object->has_data_loaded()) {
+ abc_object->load_all_data(this, schema, scale, progress);
+ }
+ else {
+ if (abc_object->need_shader_update) {
+ abc_object->update_shader_attributes(schema.getArbGeomParams(), progress);
+ }
+
+ if (scale_is_modified()) {
+ abc_object->setup_transform_cache(scale);
+ }
+ }
+
+ /* update sockets */
+
+ Object *object = abc_object->get_object();
+ cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
+
+ cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket());
+
+ cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_shader_socket());
+
+ array<int3> *triangle_data = cached_data.triangles.data_for_time(frame_time);
+ if (triangle_data) {
+ array<int> triangles;
+ array<bool> smooth;
+
+ triangles.reserve(triangle_data->size() * 3);
+ smooth.reserve(triangle_data->size());
+
+ for (size_t i = 0; i < triangle_data->size(); ++i) {
+ int3 tri = (*triangle_data)[i];
+ triangles.push_back_reserved(tri.x);
+ triangles.push_back_reserved(tri.y);
+ triangles.push_back_reserved(tri.z);
+ smooth.push_back_reserved(1);
+ }
+
+ mesh->set_triangles(triangles);
+ mesh->set_smooth(smooth);
+ }
+
+ /* update attributes */
+
+ update_attributes(mesh->attributes, cached_data, frame_time);
+
+ /* we don't yet support arbitrary attributes, for now add vertex
+ * coordinates as generated coordinates if requested */
+ if (mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
+ Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
+ memcpy(
+ attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size());
+ }
+
+ if (mesh->is_modified()) {
+ bool need_rebuild = mesh->triangles_is_modified();
+ mesh->tag_update(scene, need_rebuild);
+ }
+}
+
+void AlembicProcedural::read_subd(Scene *scene,
+ AlembicObject *abc_object,
+ Abc::chrono_t frame_time,
+ Progress &progress)
+{
+ ISubD subd_mesh(abc_object->iobject, Alembic::Abc::kWrapExisting);
+ ISubDSchema schema = subd_mesh.getSchema();
+
+ Mesh *mesh = nullptr;
+
+ /* create a mesh node in the scene if not already done */
+ if (!abc_object->get_object()) {
+ mesh = scene->create_node<Mesh>();
+ mesh->set_owner(this);
+ mesh->name = abc_object->iobject.getName();
+
+ array<Node *> used_shaders = abc_object->get_used_shaders();
+ mesh->set_used_shaders(used_shaders);
+
+ /* Alembic is OpenSubDiv compliant, there is no option to set another subdivision type. */
+ mesh->set_subdivision_type(Mesh::SubdivisionType::SUBDIVISION_CATMULL_CLARK);
+
+ /* create object*/
+ Object *object = scene->create_node<Object>();
+ object->set_owner(this);
+ object->set_geometry(mesh);
+ object->set_tfm(abc_object->xform);
+ object->name = abc_object->iobject.getName();
+
+ abc_object->set_object(object);
+ }
+ else {
+ mesh = static_cast<Mesh *>(abc_object->get_object()->get_geometry());
+ }
+
+ if (!abc_object->has_data_loaded()) {
+ abc_object->load_all_data(this, schema, scale, progress);
+ }
+ else {
+ if (abc_object->need_shader_update) {
+ abc_object->update_shader_attributes(schema.getArbGeomParams(), progress);
+ }
+
+ if (scale_is_modified()) {
+ abc_object->setup_transform_cache(scale);
+ }
+ }
+
+ mesh->set_subd_max_level(abc_object->get_subd_max_level());
+ mesh->set_subd_dicing_rate(abc_object->get_subd_dicing_rate());
+
+ CachedData &cached_data = abc_object->get_cached_data();
+
+ if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) {
+ /* need to reset the current data is something changed */
+ cached_data.invalidate_last_loaded_time();
+ }
+
+ /* Cycles overwrites the original triangles when computing displacement, so we always have to
+ * repass the data if something is animated (vertices most likely) to avoid buffer overflows. */
+ if (!cached_data.is_constant()) {
+ cached_data.invalidate_last_loaded_time();
+
+ /* remove previous triangles, if any */
+ array<int> triangles;
+ mesh->set_triangles(triangles);
+ }
+
+ mesh->clear_non_sockets();
+
+ /* udpate sockets */
+
+ Object *object = abc_object->get_object();
+ cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
+
+ cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket());
+
+ /* cached_data.shader is also used for subd_shader */
+ cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_subd_shader_socket());
+
+ cached_data.subd_start_corner.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_start_corner_socket());
+
+ cached_data.subd_num_corners.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_num_corners_socket());
+
+ cached_data.subd_smooth.copy_to_socket(frame_time, mesh, mesh->get_subd_smooth_socket());
+
+ cached_data.subd_ptex_offset.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_ptex_offset_socket());
+
+ cached_data.subd_face_corners.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_face_corners_socket());
+
+ cached_data.num_ngons.copy_to_socket(frame_time, mesh, mesh->get_num_ngons_socket());
+
+ cached_data.subd_creases_edge.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_creases_edge_socket());
+
+ cached_data.subd_creases_weight.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_creases_weight_socket());
+
+ mesh->set_num_subd_faces(mesh->get_subd_shader().size());
+
+ /* udpate attributes */
+
+ update_attributes(mesh->subd_attributes, cached_data, frame_time);
+
+ /* we don't yet support arbitrary attributes, for now add vertex
+ * coordinates as generated coordinates if requested */
+ if (mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
+ Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
+ memcpy(
+ attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size());
+ }
+
+ if (mesh->is_modified()) {
+ bool need_rebuild = (mesh->triangles_is_modified()) ||
+ (mesh->subd_num_corners_is_modified()) ||
+ (mesh->subd_shader_is_modified()) || (mesh->subd_smooth_is_modified()) ||
+ (mesh->subd_ptex_offset_is_modified()) ||
+ (mesh->subd_start_corner_is_modified()) ||
+ (mesh->subd_face_corners_is_modified());
+
+ mesh->tag_update(scene, need_rebuild);
+ }
+}
+
+void AlembicProcedural::read_curves(Scene *scene,
+ AlembicObject *abc_object,
+ Abc::chrono_t frame_time,
+ Progress &progress)
+{
+ ICurves curves(abc_object->iobject, Alembic::Abc::kWrapExisting);
+ Hair *hair;
+
+ /* create a hair node in the scene if not already done */
+ if (!abc_object->get_object()) {
+ hair = scene->create_node<Hair>();
+ hair->set_owner(this);
+ hair->name = abc_object->iobject.getName();
+
+ array<Node *> used_shaders = abc_object->get_used_shaders();
+ hair->set_used_shaders(used_shaders);
+
+ /* create object*/
+ Object *object = scene->create_node<Object>();
+ object->set_owner(this);
+ object->set_geometry(hair);
+ object->set_tfm(abc_object->xform);
+ object->name = abc_object->iobject.getName();
+
+ abc_object->set_object(object);
+ }
+ else {
+ hair = static_cast<Hair *>(abc_object->get_object()->get_geometry());
+ }
+
+ ICurvesSchema schema = curves.getSchema();
+
+ if (!abc_object->has_data_loaded() || default_radius_is_modified() ||
+ abc_object->radius_scale_is_modified()) {
+ abc_object->load_all_data(this, schema, scale, progress, default_radius);
+ }
+ else {
+ if (scale_is_modified()) {
+ abc_object->setup_transform_cache(scale);
+ }
+ }
+
+ CachedData &cached_data = abc_object->get_cached_data();
+
+ /* update sockets */
+
+ Object *object = abc_object->get_object();
+ cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
+
+ cached_data.curve_keys.copy_to_socket(frame_time, hair, hair->get_curve_keys_socket());
+
+ cached_data.curve_radius.copy_to_socket(frame_time, hair, hair->get_curve_radius_socket());
+
+ cached_data.curve_shader.copy_to_socket(frame_time, hair, hair->get_curve_shader_socket());
+
+ cached_data.curve_first_key.copy_to_socket(frame_time, hair, hair->get_curve_first_key_socket());
+
+ /* update attributes */
+
+ update_attributes(hair->attributes, cached_data, frame_time);
+
+ /* we don't yet support arbitrary attributes, for now add first keys as generated coordinates if
+ * requested */
+ if (hair->need_attribute(scene, ATTR_STD_GENERATED)) {
+ Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED);
+ float3 *generated = attr_generated->data_float3();
+
+ for (size_t i = 0; i < hair->num_curves(); i++) {
+ generated[i] = hair->get_curve_keys()[hair->get_curve(i).first_key];
+ }
+ }
+
+ const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
+ hair->tag_update(scene, rebuild);
+}
+
+void AlembicProcedural::walk_hierarchy(
+ IObject parent,
+ const ObjectHeader &header,
+ MatrixSampleMap *xform_samples,
+ const unordered_map<std::string, AlembicObject *> &object_map,
+ Progress &progress)
+{
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ IObject next_object;
+
+ MatrixSampleMap concatenated_xform_samples;
+
+ if (IXform::matches(header)) {
+ IXform xform(parent, header.getName());
+
+ IXformSchema &xs = xform.getSchema();
+
+ if (xs.getNumOps() > 0) {
+ TimeSamplingPtr ts = xs.getTimeSampling();
+ MatrixSampleMap local_xform_samples;
+
+ MatrixSampleMap *temp_xform_samples = nullptr;
+ if (xform_samples == nullptr) {
+ /* If there is no parent transforms, fill the map directly. */
+ temp_xform_samples = &concatenated_xform_samples;
+ }
+ else {
+ /* use a temporary map */
+ temp_xform_samples = &local_xform_samples;
+ }
+
+ for (size_t i = 0; i < xs.getNumSamples(); ++i) {
+ chrono_t sample_time = ts->getSampleTime(index_t(i));
+ XformSample sample = xs.getValue(ISampleSelector(sample_time));
+ temp_xform_samples->insert({sample_time, sample.getMatrix()});
+ }
+
+ if (xform_samples != nullptr) {
+ concatenate_xform_samples(*xform_samples, local_xform_samples, concatenated_xform_samples);
+ }
+
+ xform_samples = &concatenated_xform_samples;
+ }
+
+ next_object = xform;
+ }
+ else if (ISubD::matches(header)) {
+ ISubD subd(parent, header.getName());
+
+ unordered_map<std::string, AlembicObject *>::const_iterator iter;
+ iter = object_map.find(subd.getFullName());
+
+ if (iter != object_map.end()) {
+ AlembicObject *abc_object = iter->second;
+ abc_object->iobject = subd;
+
+ if (xform_samples) {
+ abc_object->xform_samples = *xform_samples;
+ }
+ }
+
+ next_object = subd;
+ }
+ else if (IPolyMesh::matches(header)) {
+ IPolyMesh mesh(parent, header.getName());
+
+ unordered_map<std::string, AlembicObject *>::const_iterator iter;
+ iter = object_map.find(mesh.getFullName());
+
+ if (iter != object_map.end()) {
+ AlembicObject *abc_object = iter->second;
+ abc_object->iobject = mesh;
+
+ if (xform_samples) {
+ abc_object->xform_samples = *xform_samples;
+ }
+ }
+
+ next_object = mesh;
+ }
+ else if (ICurves::matches(header)) {
+ ICurves curves(parent, header.getName());
+
+ unordered_map<std::string, AlembicObject *>::const_iterator iter;
+ iter = object_map.find(curves.getFullName());
+
+ if (iter != object_map.end()) {
+ AlembicObject *abc_object = iter->second;
+ abc_object->iobject = curves;
+
+ if (xform_samples) {
+ abc_object->xform_samples = *xform_samples;
+ }
+ }
+
+ next_object = curves;
+ }
+ else if (IFaceSet::matches(header)) {
+ // ignore the face set, it will be read along with the data
+ }
+ else {
+ // unsupported type for now (Points, NuPatch)
+ next_object = parent.getChild(header.getName());
+ }
+
+ if (next_object.valid()) {
+ for (size_t i = 0; i < next_object.getNumChildren(); ++i) {
+ walk_hierarchy(
+ next_object, next_object.getChildHeader(i), xform_samples, object_map, progress);
+ }
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h
new file mode 100644
index 00000000000..77bdac09ba2
--- /dev/null
+++ b/intern/cycles/render/alembic.h
@@ -0,0 +1,404 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "graph/node.h"
+#include "render/attribute.h"
+#include "render/procedural.h"
+#include "util/util_set.h"
+#include "util/util_transform.h"
+#include "util/util_vector.h"
+
+#ifdef WITH_ALEMBIC
+
+# include <Alembic/AbcCoreFactory/All.h>
+# include <Alembic/AbcGeom/All.h>
+
+CCL_NAMESPACE_BEGIN
+
+class AlembicProcedural;
+class Geometry;
+class Object;
+class Progress;
+class Shader;
+
+using MatrixSampleMap = std::map<Alembic::Abc::chrono_t, Alembic::Abc::M44d>;
+
+/* Helpers to detect if some type is a ccl::array. */
+template<typename> struct is_array : public std::false_type {
+};
+
+template<typename T> struct is_array<array<T>> : public std::true_type {
+};
+
+/* Store the data set for an animation at every time points, or at the beginning of the animation
+ * for constant data.
+ *
+ * The data is supposed to be stored in chronological order, and is looked up using the current
+ * animation time in seconds using the TimeSampling from the Alembic property. */
+template<typename T> class DataStore {
+ struct DataTimePair {
+ double time = 0;
+ T data{};
+ };
+
+ vector<DataTimePair> data{};
+ Alembic::AbcCoreAbstract::TimeSampling time_sampling{};
+
+ double last_loaded_time = std::numeric_limits<double>::max();
+
+ public:
+ void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling_)
+ {
+ time_sampling = time_sampling_;
+ }
+
+ Alembic::AbcCoreAbstract::TimeSampling get_time_sampling() const
+ {
+ return time_sampling;
+ }
+
+ /* Get the data for the specified time.
+ * Return nullptr if there is no data or if the data for this time was already loaded. */
+ T *data_for_time(double time)
+ {
+ if (size() == 0) {
+ return nullptr;
+ }
+
+ std::pair<size_t, Alembic::Abc::chrono_t> index_pair;
+ index_pair = time_sampling.getNearIndex(time, data.size());
+ DataTimePair &data_pair = data[index_pair.first];
+
+ if (last_loaded_time == data_pair.time) {
+ return nullptr;
+ }
+
+ last_loaded_time = data_pair.time;
+
+ return &data_pair.data;
+ }
+
+ /* get the data for the specified time, but do not check if the data was already loaded for this
+ * time return nullptr if there is no data */
+ T *data_for_time_no_check(double time)
+ {
+ if (size() == 0) {
+ return nullptr;
+ }
+
+ std::pair<size_t, Alembic::Abc::chrono_t> index_pair;
+ index_pair = time_sampling.getNearIndex(time, data.size());
+ DataTimePair &data_pair = data[index_pair.first];
+ return &data_pair.data;
+ }
+
+ void add_data(T &data_, double time)
+ {
+ if constexpr (is_array<T>::value) {
+ data.emplace_back();
+ data.back().data.steal_data(data_);
+ data.back().time = time;
+ return;
+ }
+
+ data.push_back({time, data_});
+ }
+
+ bool is_constant() const
+ {
+ return data.size() <= 1;
+ }
+
+ size_t size() const
+ {
+ return data.size();
+ }
+
+ void clear()
+ {
+ invalidate_last_loaded_time();
+ data.clear();
+ }
+
+ void invalidate_last_loaded_time()
+ {
+ last_loaded_time = std::numeric_limits<double>::max();
+ }
+
+ /* Copy the data for the specified time to the node's socket. If there is no
+ * data for this time or it was already loaded, do nothing. */
+ void copy_to_socket(double time, Node *node, const SocketType *socket)
+ {
+ T *data_ = data_for_time(time);
+
+ if (data_ == nullptr) {
+ return;
+ }
+
+ /* TODO(kevindietrich): arrays are emptied when passed to the sockets, so for now we copy the
+ * arrays to avoid reloading the data */
+ T value = *data_;
+ node->set(*socket, value);
+ }
+};
+
+/* Actual cache for the stored data.
+ * This caches the topological, transformation, and attribute data for a Mesh node or a Hair node
+ * inside of DataStores.
+ */
+struct CachedData {
+ DataStore<Transform> transforms{};
+
+ /* mesh data */
+ DataStore<array<float3>> vertices;
+ DataStore<array<int3>> triangles{};
+ /* triangle "loops" are the polygons' vertices indices used for indexing face varying attributes
+ * (like UVs) */
+ DataStore<array<int3>> triangles_loops{};
+ DataStore<array<int>> shader{};
+
+ /* subd data */
+ DataStore<array<int>> subd_start_corner;
+ DataStore<array<int>> subd_num_corners;
+ DataStore<array<bool>> subd_smooth;
+ DataStore<array<int>> subd_ptex_offset;
+ DataStore<array<int>> subd_face_corners;
+ DataStore<int> num_ngons;
+ DataStore<array<int>> subd_creases_edge;
+ DataStore<array<float>> subd_creases_weight;
+
+ /* hair data */
+ DataStore<array<float3>> curve_keys;
+ DataStore<array<float>> curve_radius;
+ DataStore<array<int>> curve_first_key;
+ DataStore<array<int>> curve_shader;
+
+ struct CachedAttribute {
+ AttributeStandard std;
+ AttributeElement element;
+ TypeDesc type_desc;
+ ustring name;
+ DataStore<array<char>> data{};
+ };
+
+ vector<CachedAttribute> attributes{};
+
+ void clear();
+
+ CachedAttribute &add_attribute(const ustring &name,
+ const Alembic::Abc::TimeSampling &time_sampling);
+
+ bool is_constant() const;
+
+ void invalidate_last_loaded_time(bool attributes_only = false);
+
+ void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling);
+};
+
+/* Representation of an Alembic object for the AlembicProcedural.
+ *
+ * The AlembicObject holds the path to the Alembic IObject inside of the archive that is desired
+ * for rendering, as well as the list of shaders that it is using.
+ *
+ * The names of the shaders should correspond to the names of the FaceSets inside of the Alembic
+ * archive for per-triangle shader association. If there is no FaceSets, or the names do not
+ * match, the first shader is used for rendering for all triangles.
+ */
+class AlembicObject : public Node {
+ public:
+ NODE_DECLARE
+
+ /* Path to the IObject inside of the archive. */
+ NODE_SOCKET_API(ustring, path)
+
+ /* Shaders used for rendering. */
+ NODE_SOCKET_API_ARRAY(array<Node *>, used_shaders)
+
+ /* Maximum number of subdivisions for ISubD objects. */
+ NODE_SOCKET_API(int, subd_max_level)
+
+ /* Finest level of detail (in pixels) for the subdivision. */
+ NODE_SOCKET_API(float, subd_dicing_rate)
+
+ /* Scale the radius of points and curves. */
+ NODE_SOCKET_API(float, radius_scale)
+
+ AlembicObject();
+ ~AlembicObject();
+
+ private:
+ friend class AlembicProcedural;
+
+ void set_object(Object *object);
+ Object *get_object();
+
+ void load_all_data(AlembicProcedural *proc,
+ Alembic::AbcGeom::IPolyMeshSchema &schema,
+ float scale,
+ Progress &progress);
+ void load_all_data(AlembicProcedural *proc,
+ Alembic::AbcGeom::ISubDSchema &schema,
+ float scale,
+ Progress &progress);
+ void load_all_data(AlembicProcedural *proc,
+ const Alembic::AbcGeom::ICurvesSchema &schema,
+ float scale,
+ Progress &progress,
+ float default_radius);
+
+ bool has_data_loaded() const;
+
+ bool need_shader_update = true;
+
+ MatrixSampleMap xform_samples;
+ Alembic::AbcGeom::IObject iobject;
+ Transform xform;
+
+ CachedData &get_cached_data()
+ {
+ return cached_data;
+ }
+
+ bool is_constant() const
+ {
+ return cached_data.is_constant();
+ }
+
+ Object *object = nullptr;
+
+ bool data_loaded = false;
+
+ CachedData cached_data;
+
+ void update_shader_attributes(const Alembic::AbcGeom::ICompoundProperty &arb_geom_params,
+ Progress &progress);
+
+ void read_attribute(const Alembic::AbcGeom::ICompoundProperty &arb_geom_params,
+ const ustring &attr_name,
+ Progress &progress);
+
+ template<typename SchemaType>
+ void read_face_sets(SchemaType &schema,
+ array<int> &polygon_to_shader,
+ Alembic::AbcGeom::ISampleSelector sample_sel);
+
+ void setup_transform_cache(float scale);
+
+ AttributeRequestSet get_requested_attributes();
+};
+
+/* Procedural to render objects from a single Alembic archive.
+ *
+ * Every object desired to be rendered should be passed as an AlembicObject through the objects
+ * socket.
+ *
+ * This procedural will load the data set for the entire animation in memory on the first frame,
+ * and directly set the data for the new frames on the created Nodes if needed. This allows for
+ * faster updates between frames as it avoids reseeking the data on disk.
+ */
+class AlembicProcedural : public Procedural {
+ Alembic::AbcGeom::IArchive archive;
+ bool objects_loaded;
+ Scene *scene_;
+
+ public:
+ NODE_DECLARE
+
+ /* The file path to the Alembic archive */
+ NODE_SOCKET_API(ustring, filepath)
+
+ /* The current frame to render. */
+ NODE_SOCKET_API(float, frame)
+
+ /* The first frame to load data for. */
+ NODE_SOCKET_API(float, start_frame)
+
+ /* The last frame to load data for. */
+ NODE_SOCKET_API(float, end_frame)
+
+ /* Subtracted to the current frame. */
+ NODE_SOCKET_API(float, frame_offset)
+
+ /* The frame rate used for rendering in units of frames per second. */
+ NODE_SOCKET_API(float, frame_rate)
+
+ /* List of AlembicObjects to render. */
+ NODE_SOCKET_API_ARRAY(array<Node *>, objects)
+
+ /* Set the default radius to use for curves when the Alembic Curves Schemas do not have radius
+ * information. */
+ NODE_SOCKET_API(float, default_radius)
+
+ /* Multiplier to account for differences in default units for measuring objects in various
+ * software. */
+ NODE_SOCKET_API(float, scale)
+
+ AlembicProcedural();
+ ~AlembicProcedural();
+
+ /* Populates the Cycles scene with Nodes for every contained AlembicObject on the first
+ * invocation, and updates the data on subsequent invocations if the frame changed. */
+ void generate(Scene *scene, Progress &progress);
+
+ /* Add an object to our list of objects, and tag the socket as modified. */
+ void add_object(AlembicObject *object);
+
+ /* Tag for an update only if something was modified. */
+ void tag_update(Scene *scene);
+
+ /* Returns a pointer to an exisiting or a newly created AlembicObject for the given path. */
+ AlembicObject *get_or_create_object(const ustring &path);
+
+ private:
+ /* Load the data for all the objects whose data has not yet been loaded. */
+ void load_objects(Progress &progress);
+
+ /* Traverse the Alembic hierarchy to lookup the IObjects for the AlembicObjects that were
+ * specified in our objects socket, and accumulate all of the transformations samples along the
+ * way for each IObject. */
+ void walk_hierarchy(Alembic::AbcGeom::IObject parent,
+ const Alembic::AbcGeom::ObjectHeader &ohead,
+ MatrixSampleMap *xform_samples,
+ const unordered_map<string, AlembicObject *> &object_map,
+ Progress &progress);
+
+ /* Read the data for an IPolyMesh at the specified frame_time. Creates corresponding Geometry and
+ * Object Nodes in the Cycles scene if none exist yet. */
+ void read_mesh(Scene *scene,
+ AlembicObject *abc_object,
+ Alembic::AbcGeom::Abc::chrono_t frame_time,
+ Progress &progress);
+
+ /* Read the data for an ICurves at the specified frame_time. Creates corresponding Geometry and
+ * Object Nodes in the Cycles scene if none exist yet. */
+ void read_curves(Scene *scene,
+ AlembicObject *abc_object,
+ Alembic::AbcGeom::Abc::chrono_t frame_time,
+ Progress &progress);
+
+ /* Read the data for an ISubD at the specified frame_time. Creates corresponding Geometry and
+ * Object Nodes in the Cycles scene if none exist yet. */
+ void read_subd(Scene *scene,
+ AlembicObject *abc_object,
+ Alembic::AbcGeom::Abc::chrono_t frame_time,
+ Progress &progress);
+};
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index b478aae9ae2..ce4ae6e4295 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -28,7 +28,7 @@ CCL_NAMESPACE_BEGIN
Attribute::Attribute(
ustring name, TypeDesc type, AttributeElement element, Geometry *geom, AttributePrimitive prim)
- : name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0)
+ : name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0), modified(true)
{
/* string and matrix not supported! */
assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
@@ -82,6 +82,8 @@ void Attribute::add(const float &f)
for (size_t i = 0; i < size; i++)
buffer.push_back(data[i]);
+
+ modified = true;
}
void Attribute::add(const uchar4 &f)
@@ -93,6 +95,8 @@ void Attribute::add(const uchar4 &f)
for (size_t i = 0; i < size; i++)
buffer.push_back(data[i]);
+
+ modified = true;
}
void Attribute::add(const float2 &f)
@@ -104,6 +108,8 @@ void Attribute::add(const float2 &f)
for (size_t i = 0; i < size; i++)
buffer.push_back(data[i]);
+
+ modified = true;
}
void Attribute::add(const float3 &f)
@@ -115,6 +121,8 @@ void Attribute::add(const float3 &f)
for (size_t i = 0; i < size; i++)
buffer.push_back(data[i]);
+
+ modified = true;
}
void Attribute::add(const Transform &f)
@@ -126,6 +134,8 @@ void Attribute::add(const Transform &f)
for (size_t i = 0; i < size; i++)
buffer.push_back(data[i]);
+
+ modified = true;
}
void Attribute::add(const char *data)
@@ -134,6 +144,26 @@ void Attribute::add(const char *data)
for (size_t i = 0; i < size; i++)
buffer.push_back(data[i]);
+
+ modified = true;
+}
+
+void Attribute::set_data_from(Attribute &&other)
+{
+ assert(other.std == std);
+ assert(other.type == type);
+ assert(other.element == element);
+
+ this->flags = other.flags;
+
+ if (this->buffer.size() != other.buffer.size()) {
+ this->buffer = std::move(other.buffer);
+ modified = true;
+ }
+ else if (memcmp(this->data(), other.data(), other.buffer.size()) != 0) {
+ this->buffer = std::move(other.buffer);
+ modified = true;
+ }
}
size_t Attribute::data_sizeof() const
@@ -627,6 +657,42 @@ void AttributeSet::clear(bool preserve_voxel_data)
}
}
+void AttributeSet::update(AttributeSet &&new_attributes)
+{
+ /* add or update old_attributes based on the new_attributes */
+ foreach (Attribute &attr, new_attributes.attributes) {
+ Attribute *nattr = add(attr.name, attr.type, attr.element);
+ nattr->std = attr.std;
+ nattr->set_data_from(std::move(attr));
+ }
+
+ /* remove any attributes not on new_attributes */
+ list<Attribute>::iterator it;
+ for (it = attributes.begin(); it != attributes.end();) {
+ if (it->std != ATTR_STD_NONE) {
+ if (new_attributes.find(it->std) == nullptr) {
+ attributes.erase(it++);
+ continue;
+ }
+ }
+ else if (it->name != "") {
+ if (new_attributes.find(it->name) == nullptr) {
+ attributes.erase(it++);
+ continue;
+ }
+ }
+
+ it++;
+ }
+}
+
+void AttributeSet::clear_modified()
+{
+ foreach (Attribute &attr, attributes) {
+ attr.modified = false;
+ }
+}
+
/* AttributeRequest */
AttributeRequest::AttributeRequest(ustring name_)
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index 9990a1325a7..f9997d3c422 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -54,6 +54,8 @@ class Attribute {
AttributeElement element;
uint flags; /* enum AttributeFlag */
+ bool modified;
+
Attribute(ustring name,
TypeDesc type,
AttributeElement element,
@@ -159,6 +161,8 @@ class Attribute {
void add(const Transform &tfm);
void add(const char *data);
+ void set_data_from(Attribute &&other);
+
static bool same_storage(TypeDesc a, TypeDesc b);
static const char *standard_name(AttributeStandard std);
static AttributeStandard name_standard(const char *name);
@@ -194,6 +198,12 @@ class AttributeSet {
void resize(bool reserve_only = false);
void clear(bool preserve_voxel_data = false);
+
+ /* Update the attributes in this AttributeSet with the ones from the new set,
+ * and remove any attribute not found on the new set from this. */
+ void update(AttributeSet &&new_attributes);
+
+ void clear_modified();
};
/* AttributeRequest
diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp
index 7bdcb1578c3..1303f894912 100644
--- a/intern/cycles/render/background.cpp
+++ b/intern/cycles/render/background.cpp
@@ -130,8 +130,9 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
void Background::tag_update(Scene *scene)
{
- scene->integrator->tag_update(scene);
- tag_modified();
+ if (ao_factor_is_modified() || use_ao_is_modified()) {
+ scene->integrator->tag_update(scene, Integrator::BACKGROUND_AO_MODIFIED);
+ }
}
Shader *Background::get_shader(const Scene *scene)
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
index 439ebdedb8e..317a3937cab 100644
--- a/intern/cycles/render/bake.cpp
+++ b/intern/cycles/render/bake.cpp
@@ -78,7 +78,7 @@ BakeManager::BakeManager()
type = SHADER_EVAL_BAKE;
pass_filter = 0;
- need_update = true;
+ need_update_ = true;
}
BakeManager::~BakeManager()
@@ -114,9 +114,9 @@ void BakeManager::set(Scene *scene,
/* create device and update scene */
scene->film->tag_modified();
- scene->integrator->tag_update(scene);
+ scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
- need_update = true;
+ need_update_ = true;
}
void BakeManager::device_update(Device * /*device*/,
@@ -124,7 +124,7 @@ void BakeManager::device_update(Device * /*device*/,
Scene *scene,
Progress & /* progress */)
{
- if (!need_update)
+ if (!need_update())
return;
scoped_callback_timer timer([scene](double time) {
@@ -152,11 +152,21 @@ void BakeManager::device_update(Device * /*device*/,
object_index++;
}
- need_update = false;
+ need_update_ = false;
}
void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
{
}
+void BakeManager::tag_update()
+{
+ need_update_ = true;
+}
+
+bool BakeManager::need_update() const
+{
+ return need_update_;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h
index 93e664c2ab1..655b9b1cf7e 100644
--- a/intern/cycles/render/bake.h
+++ b/intern/cycles/render/bake.h
@@ -36,9 +36,12 @@ class BakeManager {
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
void device_free(Device *device, DeviceScene *dscene);
- bool need_update;
+ void tag_update();
+
+ bool need_update() const;
private:
+ bool need_update_;
ShaderEvalType type;
int pass_filter;
std::string object_name;
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index 5c3778f6ae5..9b7657802d6 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -688,16 +688,16 @@ void Film::device_free(Device * /*device*/, DeviceScene * /*dscene*/, Scene *sce
void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes)
{
if (Pass::contains(scene->passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) {
- scene->geometry_manager->tag_update(scene);
+ scene->geometry_manager->tag_update(scene, GeometryManager::UV_PASS_NEEDED);
foreach (Shader *shader, scene->shaders)
- shader->need_update_geometry = true;
+ shader->need_update_uvs = true;
}
else if (Pass::contains(scene->passes, PASS_MOTION) != Pass::contains(passes_, PASS_MOTION)) {
- scene->geometry_manager->tag_update(scene);
+ scene->geometry_manager->tag_update(scene, GeometryManager::MOTION_PASS_NEEDED);
}
else if (Pass::contains(scene->passes, PASS_AO) != Pass::contains(passes_, PASS_AO)) {
- scene->integrator->tag_update(scene);
+ scene->integrator->tag_update(scene, Integrator::AO_PASS_MODIFIED);
}
if (update_passes) {
diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp
index 6fc217f2d76..b6fe8a66b87 100644
--- a/intern/cycles/render/geometry.cpp
+++ b/intern/cycles/render/geometry.cpp
@@ -240,7 +240,6 @@ void Geometry::compute_bvh(
}
}
- clear_modified();
need_update_rebuild = false;
}
@@ -262,22 +261,21 @@ bool Geometry::has_voxel_attributes() const
void Geometry::tag_update(Scene *scene, bool rebuild)
{
- tag_modified();
-
if (rebuild) {
need_update_rebuild = true;
- scene->light_manager->need_update = true;
+ scene->light_manager->tag_update(scene, LightManager::MESH_NEED_REBUILD);
}
else {
foreach (Node *node, used_shaders) {
Shader *shader = static_cast<Shader *>(node);
- if (shader->has_surface_emission)
- scene->light_manager->need_update = true;
+ if (shader->has_surface_emission) {
+ scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED);
+ break;
+ }
}
}
- scene->geometry_manager->need_update = true;
- scene->object_manager->need_update = true;
+ scene->geometry_manager->tag_update(scene, GeometryManager::GEOMETRY_MODIFIED);
}
void Geometry::tag_bvh_update(bool rebuild)
@@ -293,7 +291,7 @@ void Geometry::tag_bvh_update(bool rebuild)
GeometryManager::GeometryManager()
{
- need_update = true;
+ update_flags = UPDATE_ALL;
need_flags_update = true;
}
@@ -494,6 +492,10 @@ void GeometryManager::update_svm_attributes(Device *,
if (attr_map_size == 0)
return;
+ if (!dscene->attributes_map.need_realloc()) {
+ return;
+ }
+
/* create attribute map */
uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size);
memset(attr_map, 0, dscene->attributes_map.size() * sizeof(uint));
@@ -602,8 +604,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
offset = attr_uchar4_offset;
assert(attr_uchar4.size() >= offset + size);
- for (size_t k = 0; k < size; k++) {
- attr_uchar4[offset + k] = data[k];
+ if (mattr->modified) {
+ for (size_t k = 0; k < size; k++) {
+ attr_uchar4[offset + k] = data[k];
+ }
}
attr_uchar4_offset += size;
}
@@ -612,8 +616,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
offset = attr_float_offset;
assert(attr_float.size() >= offset + size);
- for (size_t k = 0; k < size; k++) {
- attr_float[offset + k] = data[k];
+ if (mattr->modified) {
+ for (size_t k = 0; k < size; k++) {
+ attr_float[offset + k] = data[k];
+ }
}
attr_float_offset += size;
}
@@ -622,8 +628,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
offset = attr_float2_offset;
assert(attr_float2.size() >= offset + size);
- for (size_t k = 0; k < size; k++) {
- attr_float2[offset + k] = data[k];
+ if (mattr->modified) {
+ for (size_t k = 0; k < size; k++) {
+ attr_float2[offset + k] = data[k];
+ }
}
attr_float2_offset += size;
}
@@ -632,8 +640,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
offset = attr_float3_offset;
assert(attr_float3.size() >= offset + size * 3);
- for (size_t k = 0; k < size * 3; k++) {
- attr_float3[offset + k] = (&tfm->x)[k];
+ if (mattr->modified) {
+ for (size_t k = 0; k < size * 3; k++) {
+ attr_float3[offset + k] = (&tfm->x)[k];
+ }
}
attr_float3_offset += size * 3;
}
@@ -642,8 +652,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
offset = attr_float3_offset;
assert(attr_float3.size() >= offset + size);
- for (size_t k = 0; k < size; k++) {
- attr_float3[offset + k] = data[k];
+ if (mattr->modified) {
+ for (size_t k = 0; k < size; k++) {
+ attr_float3[offset + k] = data[k];
+ }
}
attr_float3_offset += size;
}
@@ -808,6 +820,11 @@ void GeometryManager::device_update_attributes(Device *device,
dscene->attributes_float3.alloc(attr_float3_size);
dscene->attributes_uchar4.alloc(attr_uchar4_size);
+ const bool copy_all_data = dscene->attributes_float.need_realloc() ||
+ dscene->attributes_float2.need_realloc() ||
+ dscene->attributes_float3.need_realloc() ||
+ dscene->attributes_uchar4.need_realloc();
+
size_t attr_float_offset = 0;
size_t attr_float2_offset = 0;
size_t attr_float3_offset = 0;
@@ -822,6 +839,12 @@ void GeometryManager::device_update_attributes(Device *device,
* they actually refer to the same mesh attributes, optimize */
foreach (AttributeRequest &req, attributes.requests) {
Attribute *attr = geom->attributes.find(req);
+
+ if (attr) {
+ /* force a copy if we need to reallocate all the data */
+ attr->modified |= copy_all_data;
+ }
+
update_attribute_element_offset(geom,
dscene->attributes_float,
attr_float_offset,
@@ -840,6 +863,11 @@ void GeometryManager::device_update_attributes(Device *device,
Mesh *mesh = static_cast<Mesh *>(geom);
Attribute *subd_attr = mesh->subd_attributes.find(req);
+ if (subd_attr) {
+ /* force a copy if we need to reallocate all the data */
+ subd_attr->modified |= copy_all_data;
+ }
+
update_attribute_element_offset(mesh,
dscene->attributes_float,
attr_float_offset,
@@ -903,18 +931,10 @@ void GeometryManager::device_update_attributes(Device *device,
/* copy to device */
progress.set_status("Updating Mesh", "Copying Attributes to device");
- if (dscene->attributes_float.size()) {
- dscene->attributes_float.copy_to_device();
- }
- if (dscene->attributes_float2.size()) {
- dscene->attributes_float2.copy_to_device();
- }
- if (dscene->attributes_float3.size()) {
- dscene->attributes_float3.copy_to_device();
- }
- if (dscene->attributes_uchar4.size()) {
- dscene->attributes_uchar4.copy_to_device();
- }
+ dscene->attributes_float.copy_to_device();
+ dscene->attributes_float2.copy_to_device();
+ dscene->attributes_float3.copy_to_device();
+ dscene->attributes_uchar4.copy_to_device();
if (progress.get_cancel())
return;
@@ -1066,17 +1086,34 @@ void GeometryManager::device_update_mesh(
uint *tri_patch = dscene->tri_patch.alloc(tri_size);
float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
+ const bool copy_all_data = dscene->tri_shader.need_realloc() ||
+ dscene->tri_vindex.need_realloc() ||
+ dscene->tri_vnormal.need_realloc() ||
+ dscene->tri_patch.need_realloc() ||
+ dscene->tri_patch_uv.need_realloc();
+
foreach (Geometry *geom, scene->geometry) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
- mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
- mesh->pack_normals(&vnormal[mesh->vert_offset]);
- mesh->pack_verts(tri_prim_index,
- &tri_vindex[mesh->prim_offset],
- &tri_patch[mesh->prim_offset],
- &tri_patch_uv[mesh->vert_offset],
- mesh->vert_offset,
- mesh->prim_offset);
+
+ if (mesh->shader_is_modified() || mesh->smooth_is_modified() ||
+ mesh->triangles_is_modified() || copy_all_data) {
+ mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
+ }
+
+ if (mesh->verts_is_modified() || copy_all_data) {
+ mesh->pack_normals(&vnormal[mesh->vert_offset]);
+ }
+
+ if (mesh->triangles_is_modified() || mesh->vert_patch_uv_is_modified() || copy_all_data) {
+ mesh->pack_verts(tri_prim_index,
+ &tri_vindex[mesh->prim_offset],
+ &tri_patch[mesh->prim_offset],
+ &tri_patch_uv[mesh->vert_offset],
+ mesh->vert_offset,
+ mesh->prim_offset);
+ }
+
if (progress.get_cancel())
return;
}
@@ -1085,11 +1122,11 @@ void GeometryManager::device_update_mesh(
/* vertex coordinates */
progress.set_status("Updating Mesh", "Copying Mesh to device");
- dscene->tri_shader.copy_to_device();
- dscene->tri_vnormal.copy_to_device();
- dscene->tri_vindex.copy_to_device();
- dscene->tri_patch.copy_to_device();
- dscene->tri_patch_uv.copy_to_device();
+ dscene->tri_shader.copy_to_device_if_modified();
+ dscene->tri_vnormal.copy_to_device_if_modified();
+ dscene->tri_vindex.copy_to_device_if_modified();
+ dscene->tri_patch.copy_to_device_if_modified();
+ dscene->tri_patch_uv.copy_to_device_if_modified();
}
if (curve_size != 0) {
@@ -1098,9 +1135,21 @@ void GeometryManager::device_update_mesh(
float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size);
float4 *curves = dscene->curves.alloc(curve_size);
+ const bool copy_all_data = dscene->curve_keys.need_realloc() || dscene->curves.need_realloc();
+
foreach (Geometry *geom, scene->geometry) {
if (geom->is_hair()) {
Hair *hair = static_cast<Hair *>(geom);
+
+ bool curve_keys_co_modified = hair->curve_radius_is_modified() ||
+ hair->curve_keys_is_modified();
+ bool curve_data_modified = hair->curve_shader_is_modified() ||
+ hair->curve_first_key_is_modified();
+
+ if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) {
+ continue;
+ }
+
hair->pack_curves(scene,
&curve_keys[hair->curvekey_offset],
&curves[hair->prim_offset],
@@ -1110,11 +1159,11 @@ void GeometryManager::device_update_mesh(
}
}
- dscene->curve_keys.copy_to_device();
- dscene->curves.copy_to_device();
+ dscene->curve_keys.copy_to_device_if_modified();
+ dscene->curves.copy_to_device_if_modified();
}
- if (patch_size != 0) {
+ if (patch_size != 0 && dscene->patches.need_realloc()) {
progress.set_status("Updating Mesh", "Copying Patches to device");
uint *patch_data = dscene->patches.alloc(patch_size);
@@ -1180,16 +1229,25 @@ void GeometryManager::device_update_bvh(Device *device,
VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
- delete scene->bvh;
- BVH *bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
- device->build_bvh(bvh, progress, false);
+ const bool can_refit = scene->bvh != nullptr &&
+ (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX);
+ const bool pack_all = scene->bvh == nullptr;
+
+ BVH *bvh = scene->bvh;
+ if (!scene->bvh) {
+ bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
+ }
+
+ device->build_bvh(bvh, progress, can_refit);
if (progress.get_cancel()) {
return;
}
+ const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2);
+
PackedBVH pack;
- if (bparams.bvh_layout == BVH_LAYOUT_BVH2) {
+ if (has_bvh2_layout) {
pack = std::move(static_cast<BVH2 *>(bvh)->pack);
}
else {
@@ -1210,12 +1268,22 @@ void GeometryManager::device_update_bvh(Device *device,
}
pack.root_index = -1;
- pack.prim_tri_index.reserve(num_prims);
- pack.prim_tri_verts.reserve(num_tri_verts);
- pack.prim_type.reserve(num_prims);
- pack.prim_index.reserve(num_prims);
- pack.prim_object.reserve(num_prims);
- pack.prim_visibility.reserve(num_prims);
+
+ if (!pack_all) {
+ /* if we do not need to recreate the BVH, then only the vertices are updated, so we can
+ * safely retake the memory */
+ dscene->prim_tri_verts.give_data(pack.prim_tri_verts);
+ }
+ else {
+ /* It is not strictly necessary to skip those resizes we if do not have to repack, as the OS
+ * will not allocate pages if we do not touch them, however it does help catching bugs. */
+ pack.prim_tri_index.resize(num_prims);
+ pack.prim_tri_verts.resize(num_tri_verts);
+ pack.prim_type.resize(num_prims);
+ pack.prim_index.resize(num_prims);
+ pack.prim_object.resize(num_prims);
+ pack.prim_visibility.resize(num_prims);
+ }
// Merge visibility flags of all objects and find object index for non-instanced geometry
unordered_map<const Geometry *, pair<int, uint>> geometry_to_object_info;
@@ -1229,17 +1297,27 @@ void GeometryManager::device_update_bvh(Device *device,
}
}
+ TaskPool pool;
// Iterate over scene mesh list instead of objects, since 'optix_prim_offset' was calculated
// based on that list, which may be ordered differently from the object list.
foreach (Geometry *geom, scene->geometry) {
+ if (!pack_all && !geom->is_modified()) {
+ continue;
+ }
+
const pair<int, uint> &info = geometry_to_object_info[geom];
- geom->pack_primitives(pack, info.first, info.second);
+ pool.push(function_bind(
+ &Geometry::pack_primitives, geom, &pack, info.first, info.second, pack_all));
}
+ pool.wait_work();
}
/* copy to device */
progress.set_status("Updating Scene BVH", "Copying BVH to device");
+ /* When using BVH2, we always have to copy/update the data as its layout is dependent on the
+ * BVH's leaf nodes which may be different when the objects or vertices move. */
+
if (pack.nodes.size()) {
dscene->bvh_nodes.steal_data(pack.nodes);
dscene->bvh_nodes.copy_to_device();
@@ -1252,7 +1330,7 @@ void GeometryManager::device_update_bvh(Device *device,
dscene->object_node.steal_data(pack.object_node);
dscene->object_node.copy_to_device();
}
- if (pack.prim_tri_index.size()) {
+ if (pack.prim_tri_index.size() && (dscene->prim_tri_index.need_realloc() || has_bvh2_layout)) {
dscene->prim_tri_index.steal_data(pack.prim_tri_index);
dscene->prim_tri_index.copy_to_device();
}
@@ -1260,23 +1338,23 @@ void GeometryManager::device_update_bvh(Device *device,
dscene->prim_tri_verts.steal_data(pack.prim_tri_verts);
dscene->prim_tri_verts.copy_to_device();
}
- if (pack.prim_type.size()) {
+ if (pack.prim_type.size() && (dscene->prim_type.need_realloc() || has_bvh2_layout)) {
dscene->prim_type.steal_data(pack.prim_type);
dscene->prim_type.copy_to_device();
}
- if (pack.prim_visibility.size()) {
+ if (pack.prim_visibility.size() && (dscene->prim_visibility.need_realloc() || has_bvh2_layout)) {
dscene->prim_visibility.steal_data(pack.prim_visibility);
dscene->prim_visibility.copy_to_device();
}
- if (pack.prim_index.size()) {
+ if (pack.prim_index.size() && (dscene->prim_index.need_realloc() || has_bvh2_layout)) {
dscene->prim_index.steal_data(pack.prim_index);
dscene->prim_index.copy_to_device();
}
- if (pack.prim_object.size()) {
+ if (pack.prim_object.size() && (dscene->prim_object.need_realloc() || has_bvh2_layout)) {
dscene->prim_object.steal_data(pack.prim_object);
dscene->prim_object.copy_to_device();
}
- if (pack.prim_time.size()) {
+ if (pack.prim_time.size() && (dscene->prim_time.need_realloc() || has_bvh2_layout)) {
dscene->prim_time.steal_data(pack.prim_time);
dscene->prim_time.copy_to_device();
}
@@ -1289,12 +1367,65 @@ void GeometryManager::device_update_bvh(Device *device,
dscene->data.bvh.scene = NULL;
}
+/* Set of flags used to help determining what data has been modified or needs reallocation, so we
+ * can decide which device data to free or update. */
+enum {
+ DEVICE_CURVE_DATA_MODIFIED = (1 << 0),
+ DEVICE_MESH_DATA_MODIFIED = (1 << 1),
+
+ ATTR_FLOAT_MODIFIED = (1 << 2),
+ ATTR_FLOAT2_MODIFIED = (1 << 3),
+ ATTR_FLOAT3_MODIFIED = (1 << 4),
+ ATTR_UCHAR4_MODIFIED = (1 << 5),
+
+ CURVE_DATA_NEED_REALLOC = (1 << 6),
+ MESH_DATA_NEED_REALLOC = (1 << 7),
+
+ ATTR_FLOAT_NEEDS_REALLOC = (1 << 8),
+ ATTR_FLOAT2_NEEDS_REALLOC = (1 << 9),
+ ATTR_FLOAT3_NEEDS_REALLOC = (1 << 10),
+ ATTR_UCHAR4_NEEDS_REALLOC = (1 << 11),
+
+ ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC |
+ ATTR_FLOAT3_NEEDS_REALLOC | ATTR_UCHAR4_NEEDS_REALLOC),
+ DEVICE_MESH_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
+ DEVICE_CURVE_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
+};
+
+static void update_device_flags_attribute(uint32_t &device_update_flags,
+ const AttributeSet &attributes)
+{
+ foreach (const Attribute &attr, attributes.attributes) {
+ if (!attr.modified) {
+ continue;
+ }
+
+ if (attr.element == ATTR_ELEMENT_CORNER) {
+ device_update_flags |= ATTR_UCHAR4_MODIFIED;
+ }
+ else if (attr.type == TypeDesc::TypeFloat) {
+ device_update_flags |= ATTR_FLOAT_MODIFIED;
+ }
+ else if (attr.type == TypeFloat2) {
+ device_update_flags |= ATTR_FLOAT2_MODIFIED;
+ }
+ else if (attr.type == TypeDesc::TypeMatrix) {
+ device_update_flags |= ATTR_FLOAT3_MODIFIED;
+ }
+ else if (attr.element != ATTR_ELEMENT_VOXEL) {
+ device_update_flags |= ATTR_FLOAT3_MODIFIED;
+ }
+ }
+}
+
void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress)
{
- if (!need_update && !need_flags_update) {
+ if (!need_update() && !need_flags_update) {
return;
}
+ uint32_t device_update_flags = 0;
+
scoped_callback_timer timer([scene](double time) {
if (scene->update_stats) {
scene->update_stats->geometry.times.add_entry({"device_update_preprocess", time});
@@ -1314,9 +1445,54 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
if (shader->has_volume) {
geom->has_volume = true;
}
+
if (shader->has_surface_bssrdf) {
geom->has_surface_bssrdf = true;
}
+
+ if (shader->need_update_uvs) {
+ device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC;
+
+ /* Attributes might need to be tesselated if added. */
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->need_tesselation()) {
+ mesh->tag_modified();
+ }
+ }
+ }
+
+ if (shader->need_update_attribute) {
+ device_update_flags |= ATTRS_NEED_REALLOC;
+
+ /* Attributes might need to be tesselated if added. */
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->need_tesselation()) {
+ mesh->tag_modified();
+ }
+ }
+ }
+
+ if (shader->need_update_displacement) {
+ /* tag displacement related sockets as modified */
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ mesh->tag_verts_modified();
+ mesh->tag_subd_dicing_rate_modified();
+ mesh->tag_subd_max_level_modified();
+ mesh->tag_subd_objecttoworld_modified();
+
+ device_update_flags |= ATTRS_NEED_REALLOC;
+ }
+ }
+ }
+
+ /* only check for modified attributes if we do not need to reallocate them already */
+ if ((device_update_flags & ATTRS_NEED_REALLOC) == 0) {
+ update_device_flags_attribute(device_update_flags, geom->attributes);
+ /* don't check for subd_attributes, as if they were modified, we would need to reallocate
+ * anyway */
}
/* Re-create volume mesh if we will rebuild or refit the BVH. Note we
@@ -1332,13 +1508,119 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
Volume *volume = static_cast<Volume *>(geom);
create_volume_mesh(volume, progress);
+
+ /* always reallocate when we have a volume, as we need to rebuild the BVH */
+ device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
}
if (geom->is_hair()) {
/* Set curve shape, still a global scene setting for now. */
Hair *hair = static_cast<Hair *>(geom);
hair->curve_shape = scene->params.hair_shape;
+
+ if (hair->need_update_rebuild) {
+ device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
+ }
+ else if (hair->is_modified()) {
+ device_update_flags |= DEVICE_CURVE_DATA_MODIFIED;
+ }
}
+
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+
+ if (mesh->need_update_rebuild) {
+ device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
+ }
+ else if (mesh->is_modified()) {
+ device_update_flags |= DEVICE_MESH_DATA_MODIFIED;
+ }
+ }
+ }
+
+ if (update_flags & (MESH_ADDED | MESH_REMOVED)) {
+ device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
+ }
+
+ if (update_flags & (HAIR_ADDED | HAIR_REMOVED)) {
+ device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
+ }
+
+ /* tag the device arrays for reallocation or modification */
+ DeviceScene *dscene = &scene->dscene;
+
+ if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC)) {
+ delete scene->bvh;
+ scene->bvh = nullptr;
+
+ dscene->bvh_nodes.tag_realloc();
+ dscene->bvh_leaf_nodes.tag_realloc();
+ dscene->object_node.tag_realloc();
+ dscene->prim_tri_verts.tag_realloc();
+ dscene->prim_tri_index.tag_realloc();
+ dscene->prim_type.tag_realloc();
+ dscene->prim_visibility.tag_realloc();
+ dscene->prim_index.tag_realloc();
+ dscene->prim_object.tag_realloc();
+ dscene->prim_time.tag_realloc();
+
+ if (device_update_flags & DEVICE_MESH_DATA_NEEDS_REALLOC) {
+ dscene->tri_vnormal.tag_realloc();
+ dscene->tri_vindex.tag_realloc();
+ dscene->tri_patch.tag_realloc();
+ dscene->tri_vnormal.tag_realloc();
+ dscene->tri_patch_uv.tag_realloc();
+ dscene->patches.tag_realloc();
+ }
+
+ if (device_update_flags & DEVICE_CURVE_DATA_NEEDS_REALLOC) {
+ dscene->curves.tag_realloc();
+ dscene->curve_keys.tag_realloc();
+ }
+ }
+
+ if (device_update_flags & ATTR_FLOAT_NEEDS_REALLOC) {
+ dscene->attributes_map.tag_realloc();
+ dscene->attributes_float.tag_realloc();
+ }
+ else if (device_update_flags & ATTR_FLOAT_MODIFIED) {
+ dscene->attributes_float.tag_modified();
+ }
+
+ if (device_update_flags & ATTR_FLOAT2_NEEDS_REALLOC) {
+ dscene->attributes_map.tag_realloc();
+ dscene->attributes_float2.tag_realloc();
+ }
+ else if (device_update_flags & ATTR_FLOAT_MODIFIED) {
+ dscene->attributes_float.tag_modified();
+ }
+
+ if (device_update_flags & ATTR_FLOAT3_NEEDS_REALLOC) {
+ dscene->attributes_map.tag_realloc();
+ dscene->attributes_float3.tag_realloc();
+ }
+ else if (device_update_flags & ATTR_FLOAT_MODIFIED) {
+ dscene->attributes_float.tag_modified();
+ }
+
+ if (device_update_flags & ATTR_UCHAR4_NEEDS_REALLOC) {
+ dscene->attributes_map.tag_realloc();
+ dscene->attributes_uchar4.tag_realloc();
+ }
+ else if (device_update_flags & ATTR_UCHAR4_MODIFIED) {
+ dscene->attributes_uchar4.tag_modified();
+ }
+
+ if (device_update_flags & DEVICE_MESH_DATA_MODIFIED) {
+ /* if anything else than vertices or shaders are modified, we would need to reallocate, so
+ * these are the only arrays that can be updated */
+ dscene->tri_vnormal.tag_modified();
+ dscene->tri_shader.tag_modified();
+ }
+
+ if (device_update_flags & DEVICE_CURVE_DATA_MODIFIED) {
+ dscene->curve_keys.tag_modified();
+ dscene->curves.tag_modified();
}
need_flags_update = false;
@@ -1423,7 +1705,7 @@ void GeometryManager::device_update(Device *device,
Scene *scene,
Progress &progress)
{
- if (!need_update)
+ if (!need_update())
return;
VLOG(1) << "Total " << scene->geometry.size() << " meshes.";
@@ -1439,12 +1721,6 @@ void GeometryManager::device_update(Device *device,
});
foreach (Geometry *geom, scene->geometry) {
- foreach (Node *node, geom->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->need_update_geometry)
- geom->tag_modified();
- }
-
if (geom->is_modified() &&
(geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME)) {
Mesh *mesh = static_cast<Mesh *>(geom);
@@ -1541,7 +1817,7 @@ void GeometryManager::device_update(Device *device,
}
/* Device update. */
- device_free(device, dscene);
+ device_free(device, dscene, false);
const BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
device->get_bvh_layout_mask());
@@ -1614,7 +1890,7 @@ void GeometryManager::device_update(Device *device,
{"device_update (displacement: attributes)", time});
}
});
- device_free(device, dscene);
+ device_free(device, dscene, false);
device_update_attributes(device, dscene, scene, progress);
if (progress.get_cancel()) {
@@ -1622,6 +1898,9 @@ void GeometryManager::device_update(Device *device,
}
}
+ /* update the bvh even when there is no geometry so the kernel bvh data is still valid,
+ * especially when removing all of the objects during interactive renders */
+ bool need_update_scene_bvh = (scene->bvh == nullptr);
{
scoped_callback_timer timer([scene](double time) {
if (scene->update_stats) {
@@ -1633,6 +1912,7 @@ void GeometryManager::device_update(Device *device,
size_t i = 0;
foreach (Geometry *geom, scene->geometry) {
if (geom->is_modified()) {
+ need_update_scene_bvh = true;
pool.push(function_bind(
&Geometry::compute_bvh, geom, device, dscene, &scene->params, &progress, i, num_bvh));
if (geom->need_build_bvh(bvh_layout)) {
@@ -1647,7 +1927,9 @@ void GeometryManager::device_update(Device *device,
}
foreach (Shader *shader, scene->shaders) {
- shader->need_update_geometry = false;
+ shader->need_update_uvs = false;
+ shader->need_update_attribute = false;
+ shader->need_update_displacement = false;
}
Scene::MotionType need_motion = scene->need_motion();
@@ -1670,7 +1952,7 @@ void GeometryManager::device_update(Device *device,
return;
}
- {
+ if (need_update_scene_bvh) {
scoped_callback_timer timer([scene](double time) {
if (scene->update_stats) {
scene->update_stats->geometry.times.add_entry({"device_update (build scene BVH)", time});
@@ -1695,8 +1977,6 @@ void GeometryManager::device_update(Device *device,
}
}
- need_update = false;
-
if (true_displacement_used) {
/* Re-tag flags for update, so they're re-evaluated
* for meshes with correct bounding boxes.
@@ -1706,33 +1986,71 @@ void GeometryManager::device_update(Device *device,
*/
scene->object_manager->need_flags_update = old_need_object_flags_update;
}
+
+ /* unset flags */
+
+ foreach (Geometry *geom, scene->geometry) {
+ geom->clear_modified();
+ geom->attributes.clear_modified();
+
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ mesh->subd_attributes.clear_modified();
+ }
+ }
+
+ update_flags = UPDATE_NONE;
+
+ dscene->bvh_nodes.clear_modified();
+ dscene->bvh_leaf_nodes.clear_modified();
+ dscene->object_node.clear_modified();
+ dscene->prim_tri_verts.clear_modified();
+ dscene->prim_tri_index.clear_modified();
+ dscene->prim_type.clear_modified();
+ dscene->prim_visibility.clear_modified();
+ dscene->prim_index.clear_modified();
+ dscene->prim_object.clear_modified();
+ dscene->prim_time.clear_modified();
+ dscene->tri_shader.clear_modified();
+ dscene->tri_vindex.clear_modified();
+ dscene->tri_patch.clear_modified();
+ dscene->tri_vnormal.clear_modified();
+ dscene->tri_patch_uv.clear_modified();
+ dscene->curves.clear_modified();
+ dscene->curve_keys.clear_modified();
+ dscene->patches.clear_modified();
+ dscene->attributes_map.clear_modified();
+ dscene->attributes_float.clear_modified();
+ dscene->attributes_float2.clear_modified();
+ dscene->attributes_float3.clear_modified();
+ dscene->attributes_uchar4.clear_modified();
}
-void GeometryManager::device_free(Device *device, DeviceScene *dscene)
+void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool force_free)
{
- dscene->bvh_nodes.free();
- dscene->bvh_leaf_nodes.free();
- dscene->object_node.free();
- dscene->prim_tri_verts.free();
- dscene->prim_tri_index.free();
- dscene->prim_type.free();
- dscene->prim_visibility.free();
- dscene->prim_index.free();
- dscene->prim_object.free();
- dscene->prim_time.free();
- dscene->tri_shader.free();
- dscene->tri_vnormal.free();
- dscene->tri_vindex.free();
- dscene->tri_patch.free();
- dscene->tri_patch_uv.free();
- dscene->curves.free();
- dscene->curve_keys.free();
- dscene->patches.free();
- dscene->attributes_map.free();
- dscene->attributes_float.free();
- dscene->attributes_float2.free();
- dscene->attributes_float3.free();
- dscene->attributes_uchar4.free();
+ dscene->bvh_nodes.free_if_need_realloc(force_free);
+ dscene->bvh_leaf_nodes.free_if_need_realloc(force_free);
+ dscene->object_node.free_if_need_realloc(force_free);
+ dscene->prim_tri_verts.free_if_need_realloc(force_free);
+ dscene->prim_tri_index.free_if_need_realloc(force_free);
+ dscene->prim_type.free_if_need_realloc(force_free);
+ dscene->prim_visibility.free_if_need_realloc(force_free);
+ dscene->prim_index.free_if_need_realloc(force_free);
+ dscene->prim_object.free_if_need_realloc(force_free);
+ dscene->prim_time.free_if_need_realloc(force_free);
+ dscene->tri_shader.free_if_need_realloc(force_free);
+ dscene->tri_vnormal.free_if_need_realloc(force_free);
+ dscene->tri_vindex.free_if_need_realloc(force_free);
+ dscene->tri_patch.free_if_need_realloc(force_free);
+ dscene->tri_patch_uv.free_if_need_realloc(force_free);
+ dscene->curves.free_if_need_realloc(force_free);
+ dscene->curve_keys.free_if_need_realloc(force_free);
+ dscene->patches.free_if_need_realloc(force_free);
+ dscene->attributes_map.free_if_need_realloc(force_free);
+ dscene->attributes_float.free_if_need_realloc(force_free);
+ dscene->attributes_float2.free_if_need_realloc(force_free);
+ dscene->attributes_float3.free_if_need_realloc(force_free);
+ dscene->attributes_uchar4.free_if_need_realloc(force_free);
/* Signal for shaders like displacement not to do ray tracing. */
dscene->data.bvh.bvh_layout = BVH_LAYOUT_NONE;
@@ -1750,10 +2068,19 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene)
#endif
}
-void GeometryManager::tag_update(Scene *scene)
+void GeometryManager::tag_update(Scene *scene, uint32_t flag)
+{
+ update_flags |= flag;
+
+ /* do not tag the object manager for an update if it is the one who tagged us */
+ if ((flag & OBJECT_MANAGER) == 0) {
+ scene->object_manager->tag_update(scene, ObjectManager::GEOMETRY_MANAGER);
+ }
+}
+
+bool GeometryManager::need_update() const
{
- need_update = true;
- scene->object_manager->need_update = true;
+ return update_flags != UPDATE_NONE;
}
void GeometryManager::collect_statistics(const Scene *scene, RenderStats *stats)
diff --git a/intern/cycles/render/geometry.h b/intern/cycles/render/geometry.h
index b124e950ad2..88388f31a9b 100644
--- a/intern/cycles/render/geometry.h
+++ b/intern/cycles/render/geometry.h
@@ -125,7 +125,7 @@ class Geometry : public Node {
int n,
int total);
- virtual void pack_primitives(PackedBVH &pack, int object, uint visibility) = 0;
+ virtual void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) = 0;
/* Check whether the geometry should have own BVH built separately. Briefly,
* own BVH is needed for geometry, if:
@@ -155,6 +155,11 @@ class Geometry : public Node {
return geometry_type == HAIR;
}
+ bool is_volume() const
+ {
+ return geometry_type == VOLUME;
+ }
+
/* Updates */
void tag_update(Scene *scene, bool rebuild);
@@ -164,9 +169,32 @@ class Geometry : public Node {
/* Geometry Manager */
class GeometryManager {
+ uint32_t update_flags;
+
public:
+ enum : uint32_t {
+ UV_PASS_NEEDED = (1 << 0),
+ MOTION_PASS_NEEDED = (1 << 1),
+ GEOMETRY_MODIFIED = (1 << 2),
+ OBJECT_MANAGER = (1 << 3),
+ MESH_ADDED = (1 << 4),
+ MESH_REMOVED = (1 << 5),
+ HAIR_ADDED = (1 << 6),
+ HAIR_REMOVED = (1 << 7),
+
+ SHADER_ATTRIBUTE_MODIFIED = (1 << 8),
+ SHADER_DISPLACEMENT_MODIFIED = (1 << 9),
+
+ GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED,
+ GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED,
+
+ /* tag everything in the manager for an update */
+ UPDATE_ALL = ~0u,
+
+ UPDATE_NONE = 0u,
+ };
+
/* Update Flags */
- bool need_update;
bool need_flags_update;
/* Constructor/Destructor */
@@ -176,10 +204,12 @@ class GeometryManager {
/* Device Updates */
void device_update_preprocess(Device *device, Scene *scene, Progress &progress);
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
- void device_free(Device *device, DeviceScene *dscene);
+ void device_free(Device *device, DeviceScene *dscene, bool force_free);
/* Updates */
- void tag_update(Scene *scene);
+ void tag_update(Scene *scene, uint32_t flag);
+
+ bool need_update() const;
/* Statistics */
void collect_statistics(const Scene *scene, RenderStats *stats);
diff --git a/intern/cycles/render/hair.cpp b/intern/cycles/render/hair.cpp
index 896e798b6f9..e94cad6b32e 100644
--- a/intern/cycles/render/hair.cpp
+++ b/intern/cycles/render/hair.cpp
@@ -494,33 +494,38 @@ void Hair::pack_curves(Scene *scene,
}
}
-void Hair::pack_primitives(PackedBVH &pack, int object, uint visibility)
+void Hair::pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all)
{
if (curve_first_key.empty())
return;
- const size_t num_prims = num_segments();
- pack.prim_tri_index.reserve(pack.prim_tri_index.size() + num_prims);
- pack.prim_type.reserve(pack.prim_type.size() + num_prims);
- pack.prim_visibility.reserve(pack.prim_visibility.size() + num_prims);
- pack.prim_index.reserve(pack.prim_index.size() + num_prims);
- pack.prim_object.reserve(pack.prim_object.size() + num_prims);
- // 'pack.prim_time' is unused by Embree and OptiX
+ /* If the BVH does not have to be recreated, we can bail out. */
+ if (!pack_all) {
+ return;
+ }
+
+ unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
+ int *prim_type = &pack->prim_type[optix_prim_offset];
+ unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset];
+ int *prim_index = &pack->prim_index[optix_prim_offset];
+ int *prim_object = &pack->prim_object[optix_prim_offset];
+ // 'pack->prim_time' is unused by Embree and OptiX
uint type = has_motion_blur() ?
((curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
PRIMITIVE_MOTION_CURVE_THICK) :
((curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON : PRIMITIVE_CURVE_THICK);
+ size_t index = 0;
for (size_t j = 0; j < num_curves(); ++j) {
Curve curve = get_curve(j);
- for (size_t k = 0; k < curve.num_segments(); ++k) {
- pack.prim_tri_index.push_back_reserved(-1);
- pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(type, k));
- pack.prim_visibility.push_back_reserved(visibility);
+ for (size_t k = 0; k < curve.num_segments(); ++k, ++index) {
+ prim_tri_index[index] = -1;
+ prim_type[index] = PRIMITIVE_PACK_SEGMENT(type, k);
+ prim_visibility[index] = visibility;
// Each curve segment points back to its curve index
- pack.prim_index.push_back_reserved(j + prim_offset);
- pack.prim_object.push_back_reserved(object);
+ prim_index[index] = j + prim_offset;
+ prim_object[index] = object;
}
}
}
diff --git a/intern/cycles/render/hair.h b/intern/cycles/render/hair.h
index c7be08d679c..4b949f984e5 100644
--- a/intern/cycles/render/hair.h
+++ b/intern/cycles/render/hair.h
@@ -146,7 +146,7 @@ class Hair : public Geometry {
/* BVH */
void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset);
- void pack_primitives(PackedBVH &pack, int object, uint visibility) override;
+ void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) override;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 30858c4f68b..a09a680f93f 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -298,7 +298,7 @@ bool ImageLoader::is_vdb_loader() const
ImageManager::ImageManager(const DeviceInfo &info)
{
- need_update = true;
+ need_update_ = true;
osl_texture_system = NULL;
animation_frame = 0;
@@ -451,7 +451,7 @@ int ImageManager::add_image_slot(ImageLoader *loader,
images[slot] = img;
- need_update = true;
+ need_update_ = true;
return slot;
}
@@ -478,7 +478,7 @@ void ImageManager::remove_image_user(int slot)
* the reasons for this is that on shader changes we add and remove nodes
* that use them, but we do not want to reload the image all the time. */
if (image->users == 0)
- need_update = true;
+ need_update_ = true;
}
static bool image_associate_alpha(ImageManager::Image *img)
@@ -810,7 +810,7 @@ void ImageManager::device_free_image(Device *, int slot)
void ImageManager::device_update(Device *device, Scene *scene, Progress &progress)
{
- if (!need_update) {
+ if (!need_update()) {
return;
}
@@ -834,7 +834,7 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres
pool.wait_work();
- need_update = false;
+ need_update_ = false;
}
void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress)
@@ -854,7 +854,7 @@ void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &p
{
/* Load only builtin images, Blender needs this to load evaluated
* scene data from depsgraph before it is freed. */
- if (!need_update) {
+ if (!need_update()) {
return;
}
@@ -896,4 +896,14 @@ void ImageManager::collect_statistics(RenderStats *stats)
}
}
+void ImageManager::tag_update()
+{
+ need_update_ = true;
+}
+
+bool ImageManager::need_update() const
+{
+ return need_update_;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 6ac1db9ed63..c802521db56 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -189,7 +189,9 @@ class ImageManager {
void collect_statistics(RenderStats *stats);
- bool need_update;
+ void tag_update();
+
+ bool need_update() const;
struct Image {
ImageParams params;
@@ -209,6 +211,7 @@ class ImageManager {
};
private:
+ bool need_update_;
bool has_half_images;
thread_mutex device_mutex;
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index e5b9e6bfabf..d93856ceb61 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -17,9 +17,11 @@
#include "render/integrator.h"
#include "device/device.h"
#include "render/background.h"
+#include "render/camera.h"
#include "render/film.h"
#include "render/jitter.h"
#include "render/light.h"
+#include "render/object.h"
#include "render/scene.h"
#include "render/shader.h"
#include "render/sobol.h"
@@ -113,6 +115,18 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
}
});
+ const bool need_update_lut = ao_samples_is_modified() || diffuse_samples_is_modified() ||
+ glossy_samples_is_modified() || max_bounce_is_modified() ||
+ max_transmission_bounce_is_modified() ||
+ mesh_light_samples_is_modified() || method_is_modified() ||
+ sampling_pattern_is_modified() ||
+ subsurface_samples_is_modified() ||
+ transmission_samples_is_modified() || volume_samples_is_modified();
+
+ if (need_update_lut) {
+ dscene->sample_pattern_lut.tag_realloc();
+ }
+
device_free(device, dscene);
KernelIntegrator *kintegrator = &dscene->data.integrator;
@@ -242,45 +256,69 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
int dimensions = PRNG_BASE_NUM + max_samples * PRNG_BOUNCE_NUM;
dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS);
- if (sampling_pattern == SAMPLING_PATTERN_SOBOL) {
- uint *directions = dscene->sample_pattern_lut.alloc(SOBOL_BITS * dimensions);
+ if (need_update_lut) {
+ if (sampling_pattern == SAMPLING_PATTERN_SOBOL) {
+ uint *directions = dscene->sample_pattern_lut.alloc(SOBOL_BITS * dimensions);
- sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
+ sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
- dscene->sample_pattern_lut.copy_to_device();
- }
- else {
- constexpr int sequence_size = NUM_PMJ_SAMPLES;
- constexpr int num_sequences = NUM_PMJ_PATTERNS;
- float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size * num_sequences *
- 2);
- TaskPool pool;
- for (int j = 0; j < num_sequences; ++j) {
- float2 *sequence = directions + j * sequence_size;
- pool.push(
- function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j));
+ dscene->sample_pattern_lut.copy_to_device();
+ }
+ else {
+ constexpr int sequence_size = NUM_PMJ_SAMPLES;
+ constexpr int num_sequences = NUM_PMJ_PATTERNS;
+ float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size *
+ num_sequences * 2);
+ TaskPool pool;
+ for (int j = 0; j < num_sequences; ++j) {
+ float2 *sequence = directions + j * sequence_size;
+ pool.push(
+ function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j));
+ }
+ pool.wait_work();
+ dscene->sample_pattern_lut.copy_to_device();
}
- pool.wait_work();
- dscene->sample_pattern_lut.copy_to_device();
}
+ dscene->sample_pattern_lut.clear_modified();
clear_modified();
}
-void Integrator::device_free(Device *, DeviceScene *dscene)
+void Integrator::device_free(Device *, DeviceScene *dscene, bool force_free)
{
- dscene->sample_pattern_lut.free();
+ dscene->sample_pattern_lut.free_if_need_realloc(force_free);
}
-void Integrator::tag_update(Scene *scene)
+void Integrator::tag_update(Scene *scene, uint32_t flag)
{
- foreach (Shader *shader, scene->shaders) {
- if (shader->has_integrator_dependency) {
- scene->shader_manager->need_update = true;
- break;
+ if (flag & UPDATE_ALL) {
+ tag_modified();
+ }
+
+ if (flag & (AO_PASS_MODIFIED | BACKGROUND_AO_MODIFIED)) {
+ /* tag only the ao_bounces socket as modified so we avoid updating sample_pattern_lut
+ * unnecessarily */
+ tag_ao_bounces_modified();
+ }
+
+ if ((flag & LIGHT_SAMPLES_MODIFIED) && (method == BRANCHED_PATH)) {
+ /* the number of light samples may affect the size of the sample_pattern_lut */
+ tag_sampling_pattern_modified();
+ }
+
+ if (filter_glossy_is_modified()) {
+ foreach (Shader *shader, scene->shaders) {
+ if (shader->has_integrator_dependency) {
+ scene->shader_manager->tag_update(scene, ShaderManager::INTEGRATOR_MODIFIED);
+ break;
+ }
}
}
- tag_modified();
+
+ if (motion_blur_is_modified()) {
+ scene->object_manager->tag_update(scene, ObjectManager::MOTION_BLUR_MODIFIED);
+ scene->camera->tag_modified();
+ }
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h
index 9fe46ad591c..4eeeda92d41 100644
--- a/intern/cycles/render/integrator.h
+++ b/intern/cycles/render/integrator.h
@@ -89,13 +89,24 @@ class Integrator : public Node {
NODE_SOCKET_API(SamplingPattern, sampling_pattern)
+ enum : uint32_t {
+ AO_PASS_MODIFIED = (1 << 0),
+ BACKGROUND_AO_MODIFIED = (1 << 1),
+ LIGHT_SAMPLES_MODIFIED = (1 << 2),
+
+ /* tag everything in the manager for an update */
+ UPDATE_ALL = ~0u,
+
+ UPDATE_NONE = 0u,
+ };
+
Integrator();
~Integrator();
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
- void device_free(Device *device, DeviceScene *dscene);
+ void device_free(Device *device, DeviceScene *dscene, bool force_free = false);
- void tag_update(Scene *scene);
+ void tag_update(Scene *scene, uint32_t flag);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index 2bde3242b26..638ac376157 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -162,7 +162,13 @@ Light::Light() : Node(node_type)
void Light::tag_update(Scene *scene)
{
- scene->light_manager->need_update = is_modified();
+ if (is_modified()) {
+ scene->light_manager->tag_update(scene, LightManager::LIGHT_MODIFIED);
+
+ if (samples_is_modified()) {
+ scene->integrator->tag_update(scene, Integrator::LIGHT_SAMPLES_MODIFIED);
+ }
+ }
}
bool Light::has_contribution(Scene *scene)
@@ -183,7 +189,7 @@ bool Light::has_contribution(Scene *scene)
LightManager::LightManager()
{
- need_update = true;
+ update_flags = UPDATE_ALL;
need_update_background = true;
use_light_visibility = false;
last_background_enabled = false;
@@ -962,7 +968,7 @@ void LightManager::device_update(Device *device,
Scene *scene,
Progress &progress)
{
- if (!need_update)
+ if (!need_update())
return;
scoped_callback_timer timer([scene](double time) {
@@ -1000,7 +1006,7 @@ void LightManager::device_update(Device *device,
scene->film->set_use_light_visibility(use_light_visibility);
- need_update = false;
+ update_flags = UPDATE_NONE;
need_update_background = false;
}
@@ -1015,9 +1021,14 @@ void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_ba
dscene->ies_lights.free();
}
-void LightManager::tag_update(Scene * /*scene*/)
+void LightManager::tag_update(Scene * /*scene*/, uint32_t flag)
+{
+ update_flags |= flag;
+}
+
+bool LightManager::need_update() const
{
- need_update = true;
+ return update_flags != UPDATE_NONE;
}
int LightManager::add_ies_from_file(const string &filename)
@@ -1063,7 +1074,7 @@ int LightManager::add_ies(const string &content)
ies_slots[slot]->users = 1;
ies_slots[slot]->hash = hash;
- need_update = true;
+ update_flags = UPDATE_ALL;
need_update_background = true;
return slot;
@@ -1082,8 +1093,10 @@ void LightManager::remove_ies(int slot)
ies_slots[slot]->users--;
/* If the slot has no more users, update the device to remove it. */
- need_update |= (ies_slots[slot]->users == 0);
- need_update_background |= need_update;
+ if (ies_slots[slot]->users == 0) {
+ update_flags |= UPDATE_ALL;
+ need_update_background = true;
+ }
}
void LightManager::device_update_ies(DeviceScene *dscene)
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index e590e13b489..39014b5d667 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -91,8 +91,23 @@ class Light : public Node {
class LightManager {
public:
+ enum : uint32_t {
+ MESH_NEED_REBUILD = (1 << 0),
+ EMISSIVE_MESH_MODIFIED = (1 << 1),
+ LIGHT_MODIFIED = (1 << 2),
+ LIGHT_ADDED = (1 << 3),
+ LIGHT_REMOVED = (1 << 4),
+ OBJECT_MANAGER = (1 << 5),
+ SHADER_COMPILED = (1 << 6),
+ SHADER_MODIFIED = (1 << 7),
+
+ /* tag everything in the manager for an update */
+ UPDATE_ALL = ~0u,
+
+ UPDATE_NONE = 0u,
+ };
+
bool use_light_visibility;
- bool need_update;
/* Need to update background (including multiple importance map) */
bool need_update_background;
@@ -108,7 +123,9 @@ class LightManager {
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
void device_free(Device *device, DeviceScene *dscene, const bool free_background = true);
- void tag_update(Scene *scene);
+ void tag_update(Scene *scene, uint32_t flag);
+
+ bool need_update() const;
/* Check whether there is a background light. */
bool has_background_light(Scene *scene);
@@ -145,6 +162,8 @@ class LightManager {
bool last_background_enabled;
int last_background_resolution;
+
+ uint32_t update_flags;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index a0afdd3b841..5f62da8f18b 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -805,34 +805,42 @@ void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, ui
}
}
-void Mesh::pack_primitives(PackedBVH &pack, int object, uint visibility)
+void Mesh::pack_primitives(ccl::PackedBVH *pack, int object, uint visibility, bool pack_all)
{
if (triangles.empty())
return;
const size_t num_prims = num_triangles();
- pack.prim_tri_index.reserve(pack.prim_tri_index.size() + num_prims);
- pack.prim_tri_verts.reserve(pack.prim_tri_verts.size() + num_prims * 3);
- pack.prim_type.reserve(pack.prim_type.size() + num_prims);
- pack.prim_visibility.reserve(pack.prim_visibility.size() + num_prims);
- pack.prim_index.reserve(pack.prim_index.size() + num_prims);
- pack.prim_object.reserve(pack.prim_object.size() + num_prims);
- // 'pack.prim_time' is unused by Embree and OptiX
+
+ /* Use prim_offset for indexing as it is computed per geometry type, and prim_tri_verts does not
+ * contain data for Hair geometries. */
+ float4 *prim_tri_verts = &pack->prim_tri_verts[prim_offset * 3];
+ // 'pack->prim_time' is unused by Embree and OptiX
uint type = has_motion_blur() ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE;
- for (size_t k = 0; k < num_prims; ++k) {
- pack.prim_tri_index.push_back_reserved(pack.prim_tri_verts.size());
+ if (pack_all) {
+ /* Use optix_prim_offset for indexing as those arrays also contain data for Hair geometries. */
+ unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
+ int *prim_type = &pack->prim_type[optix_prim_offset];
+ unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset];
+ int *prim_index = &pack->prim_index[optix_prim_offset];
+ int *prim_object = &pack->prim_object[optix_prim_offset];
+
+ for (size_t k = 0; k < num_prims; ++k) {
+ prim_tri_index[k] = (prim_offset + k) * 3;
+ prim_type[k] = type;
+ prim_index[k] = prim_offset + k;
+ prim_object[k] = object;
+ prim_visibility[k] = visibility;
+ }
+ }
+ for (size_t k = 0; k < num_prims; ++k) {
const Mesh::Triangle t = get_triangle(k);
- pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[0]]));
- pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[1]]));
- pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[2]]));
-
- pack.prim_type.push_back_reserved(type);
- pack.prim_visibility.push_back_reserved(visibility);
- pack.prim_index.push_back_reserved(k + prim_offset);
- pack.prim_object.push_back_reserved(object);
+ prim_tri_verts[k * 3] = float3_to_float4(verts[t.v[0]]);
+ prim_tri_verts[k * 3 + 1] = float3_to_float4(verts[t.v[1]]);
+ prim_tri_verts[k * 3 + 2] = float3_to_float4(verts[t.v[2]]);
}
}
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index b0a16fdfd8f..2b0ff92ab62 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -232,7 +232,7 @@ class Mesh : public Geometry {
size_t tri_offset);
void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset);
- void pack_primitives(PackedBVH &pack, int object, uint visibility) override;
+ void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) override;
void tessellate(DiagSplit *split);
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index 406982e3ef9..0f16a4fc12c 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -153,6 +153,10 @@ void Object::update_motion()
void Object::compute_bounds(bool motion_blur)
{
+ if (!is_modified() && !geometry->is_modified()) {
+ return;
+ }
+
BoundBox mbounds = geometry->bounds;
if (motion_blur && use_motion()) {
@@ -205,20 +209,39 @@ void Object::apply_transform(bool apply_to_motion)
void Object::tag_update(Scene *scene)
{
+ uint32_t flag = ObjectManager::UPDATE_NONE;
+
+ if (is_modified()) {
+ flag |= ObjectManager::OBJECT_MODIFIED;
+
+ if (use_holdout_is_modified()) {
+ flag |= ObjectManager::HOLDOUT_MODIFIED;
+ }
+ }
+
if (geometry) {
- if (geometry->transform_applied)
- geometry->tag_modified();
+ if (tfm_is_modified()) {
+ /* tag the geometry as modified so the BVH is updated, but do not tag everything as modified
+ */
+ if (geometry->is_mesh() || geometry->is_volume()) {
+ Mesh *mesh = static_cast<Mesh *>(geometry);
+ mesh->tag_verts_modified();
+ }
+ else if (geometry->is_hair()) {
+ Hair *hair = static_cast<Hair *>(geometry);
+ hair->tag_curve_keys_modified();
+ }
+ }
foreach (Node *node, geometry->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (shader->get_use_mis() && shader->has_surface_emission)
- scene->light_manager->need_update = true;
+ scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED);
}
}
scene->camera->need_flags_update = true;
- scene->geometry_manager->need_update = true;
- scene->object_manager->need_update = true;
+ scene->object_manager->tag_update(scene, flag);
}
bool Object::use_motion() const
@@ -361,7 +384,7 @@ int Object::get_device_index() const
ObjectManager::ObjectManager()
{
- need_update = true;
+ update_flags = UPDATE_ALL;
need_flags_update = true;
}
@@ -382,7 +405,9 @@ static float object_volume_density(const Transform &tfm, Geometry *geom)
return 1.0f;
}
-void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, Object *ob)
+void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state,
+ Object *ob,
+ bool update_all)
{
KernelObject &kobject = state->objects[ob->index];
Transform *object_motion_pass = state->object_motion_pass;
@@ -456,8 +481,11 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
kobject.motion_offset = state->motion_offset[ob->index];
/* Decompose transforms for interpolation. */
- DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
- transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
+ if (ob->tfm_is_modified() || update_all) {
+ DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
+ transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
+ }
+
flag |= SD_OBJECT_MOTION;
state->have_motion = true;
}
@@ -480,10 +508,14 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
0;
kobject.patch_map_offset = 0;
kobject.attribute_map_offset = 0;
- uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0);
- uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
- kobject.cryptomatte_object = util_hash_to_float(hash_name);
- kobject.cryptomatte_asset = util_hash_to_float(hash_asset);
+
+ if (ob->asset_name_is_modified() || update_all) {
+ uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0);
+ uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
+ kobject.cryptomatte_object = util_hash_to_float(hash_name);
+ kobject.cryptomatte_asset = util_hash_to_float(hash_asset);
+ }
+
kobject.shadow_terminator_offset = 1.0f / (1.0f - 0.5f * ob->shadow_terminator_offset);
/* Object flag. */
@@ -544,6 +576,9 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
numparticles += psys->particles.size();
}
+ /* as all the arrays are the same size, checking only dscene.objects is sufficient */
+ const bool update_all = dscene->objects.need_realloc();
+
/* Parallel object update, with grain size to avoid too much threading overhead
* for individual objects. */
static const int OBJECTS_PER_TASK = 32;
@@ -551,7 +586,7 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
[&](const blocked_range<size_t> &r) {
for (size_t i = r.begin(); i != r.end(); i++) {
Object *ob = state.scene->objects[i];
- device_update_object_transform(&state, ob);
+ device_update_object_transform(&state, ob, update_all);
}
});
@@ -559,7 +594,7 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
return;
}
- dscene->objects.copy_to_device();
+ dscene->objects.copy_to_device_if_modified();
if (state.need_motion == Scene::MOTION_PASS) {
dscene->object_motion_pass.copy_to_device();
}
@@ -569,6 +604,10 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
dscene->data.bvh.have_motion = state.have_motion;
dscene->data.bvh.have_curves = state.have_curves;
+
+ dscene->objects.clear_modified();
+ dscene->object_motion_pass.clear_modified();
+ dscene->object_motion.clear_modified();
}
void ObjectManager::device_update(Device *device,
@@ -576,12 +615,28 @@ void ObjectManager::device_update(Device *device,
Scene *scene,
Progress &progress)
{
- if (!need_update)
+ if (!need_update())
return;
+ if (update_flags & (OBJECT_ADDED | OBJECT_REMOVED)) {
+ dscene->objects.tag_realloc();
+ dscene->object_motion_pass.tag_realloc();
+ dscene->object_motion.tag_realloc();
+ dscene->object_flag.tag_realloc();
+ dscene->object_volume_step.tag_realloc();
+ }
+
+ if (update_flags & HOLDOUT_MODIFIED) {
+ dscene->object_flag.tag_modified();
+ }
+
+ if (update_flags & PARTICLE_MODIFIED) {
+ dscene->objects.tag_modified();
+ }
+
VLOG(1) << "Total " << scene->objects.size() << " objects.";
- device_free(device, dscene);
+ device_free(device, dscene, false);
if (scene->objects.size() == 0)
return;
@@ -597,6 +652,16 @@ void ObjectManager::device_update(Device *device,
int index = 0;
foreach (Object *object, scene->objects) {
object->index = index++;
+
+ /* this is a bit too broad, however a bigger refactor might be needed to properly separate
+ * update each type of data (transform, flags, etc.) */
+ if (object->is_modified()) {
+ dscene->objects.tag_modified();
+ dscene->object_motion_pass.tag_modified();
+ dscene->object_motion.tag_modified();
+ dscene->object_flag.tag_modified();
+ dscene->object_volume_step.tag_modified();
+ }
}
}
@@ -638,7 +703,7 @@ void ObjectManager::device_update(Device *device,
void ObjectManager::device_update_flags(
Device *, DeviceScene *dscene, Scene *scene, Progress & /*progress*/, bool bounds_valid)
{
- if (!need_update && !need_flags_update)
+ if (!need_update() && !need_flags_update)
return;
scoped_callback_timer timer([scene](double time) {
@@ -647,7 +712,7 @@ void ObjectManager::device_update_flags(
}
});
- need_update = false;
+ update_flags = UPDATE_NONE;
need_flags_update = false;
if (scene->objects.size() == 0)
@@ -717,6 +782,9 @@ void ObjectManager::device_update_flags(
/* Copy object flag. */
dscene->object_flag.copy_to_device();
dscene->object_volume_step.copy_to_device();
+
+ dscene->object_flag.clear_modified();
+ dscene->object_volume_step.clear_modified();
}
void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene)
@@ -764,13 +832,13 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
}
}
-void ObjectManager::device_free(Device *, DeviceScene *dscene)
+void ObjectManager::device_free(Device *, DeviceScene *dscene, bool force_free)
{
- dscene->objects.free();
- dscene->object_motion_pass.free();
- dscene->object_motion.free();
- dscene->object_flag.free();
- dscene->object_volume_step.free();
+ dscene->objects.free_if_need_realloc(force_free);
+ dscene->object_motion_pass.free_if_need_realloc(force_free);
+ dscene->object_motion.free_if_need_realloc(force_free);
+ dscene->object_flag.free_if_need_realloc(force_free);
+ dscene->object_volume_step.free_if_need_realloc(force_free);
}
void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress)
@@ -841,11 +909,21 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P
}
}
-void ObjectManager::tag_update(Scene *scene)
+void ObjectManager::tag_update(Scene *scene, uint32_t flag)
+{
+ update_flags |= flag;
+
+ /* avoid infinite loops if the geometry manager tagged us for an update */
+ if ((flag & GEOMETRY_MANAGER) == 0) {
+ scene->geometry_manager->tag_update(scene, GeometryManager::OBJECT_MANAGER);
+ }
+
+ scene->light_manager->tag_update(scene, LightManager::OBJECT_MANAGER);
+}
+
+bool ObjectManager::need_update() const
{
- need_update = true;
- scene->geometry_manager->need_update = true;
- scene->light_manager->need_update = true;
+ return update_flags != UPDATE_NONE;
}
string ObjectManager::get_cryptomatte_objects(Scene *scene)
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index 76c9c30abb0..cf1b9ca510a 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -122,8 +122,24 @@ class Object : public Node {
/* Object Manager */
class ObjectManager {
+ uint32_t update_flags;
+
public:
- bool need_update;
+ enum : uint32_t {
+ PARTICLE_MODIFIED = (1 << 0),
+ GEOMETRY_MANAGER = (1 << 1),
+ MOTION_BLUR_MODIFIED = (1 << 2),
+ OBJECT_ADDED = (1 << 3),
+ OBJECT_REMOVED = (1 << 4),
+ OBJECT_MODIFIED = (1 << 5),
+ HOLDOUT_MODIFIED = (1 << 6),
+
+ /* tag everything in the manager for an update */
+ UPDATE_ALL = ~0u,
+
+ UPDATE_NONE = 0u,
+ };
+
bool need_flags_update;
ObjectManager();
@@ -139,9 +155,11 @@ class ObjectManager {
bool bounds_valid = true);
void device_update_mesh_offsets(Device *device, DeviceScene *dscene, Scene *scene);
- void device_free(Device *device, DeviceScene *dscene);
+ void device_free(Device *device, DeviceScene *dscene, bool force_free);
- void tag_update(Scene *scene);
+ void tag_update(Scene *scene, uint32_t flag);
+
+ bool need_update() const;
void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress);
@@ -149,7 +167,9 @@ class ObjectManager {
string get_cryptomatte_assets(Scene *scene);
protected:
- void device_update_object_transform(UpdateObjectTransformState *state, Object *ob);
+ void device_update_object_transform(UpdateObjectTransformState *state,
+ Object *ob,
+ bool update_all);
void device_update_object_transform_task(UpdateObjectTransformState *state);
bool device_update_object_transform_pop_work(UpdateObjectTransformState *state,
int *start_index,
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 35b62746f1b..889636fe0f3 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -96,7 +96,7 @@ void OSLShaderManager::device_update(Device *device,
Scene *scene,
Progress &progress)
{
- if (!need_update)
+ if (!need_update())
return;
scoped_callback_timer timer([scene](double time) {
@@ -132,7 +132,7 @@ void OSLShaderManager::device_update(Device *device,
compiler.compile(og, shader);
if (shader->get_use_mis() && shader->has_surface_emission)
- scene->light_manager->need_update = true;
+ scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
}
/* setup shader engine */
@@ -147,7 +147,7 @@ void OSLShaderManager::device_update(Device *device,
foreach (Shader *shader, scene->shaders)
shader->clear_modified();
- need_update = false;
+ update_flags = UPDATE_NONE;
/* add special builtin texture types */
services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO));
diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp
index faad731d413..0e168050281 100644
--- a/intern/cycles/render/particles.cpp
+++ b/intern/cycles/render/particles.cpp
@@ -46,14 +46,14 @@ ParticleSystem::~ParticleSystem()
void ParticleSystem::tag_update(Scene *scene)
{
- scene->particle_system_manager->need_update = true;
+ scene->particle_system_manager->tag_update(scene);
}
/* Particle System Manager */
ParticleSystemManager::ParticleSystemManager()
{
- need_update = true;
+ need_update_ = true;
}
ParticleSystemManager::~ParticleSystemManager()
@@ -109,7 +109,7 @@ void ParticleSystemManager::device_update(Device *device,
Scene *scene,
Progress &progress)
{
- if (!need_update)
+ if (!need_update())
return;
scoped_callback_timer timer([scene](double time) {
@@ -128,7 +128,7 @@ void ParticleSystemManager::device_update(Device *device,
if (progress.get_cancel())
return;
- need_update = false;
+ need_update_ = false;
}
void ParticleSystemManager::device_free(Device *, DeviceScene *dscene)
@@ -138,7 +138,12 @@ void ParticleSystemManager::device_free(Device *, DeviceScene *dscene)
void ParticleSystemManager::tag_update(Scene * /*scene*/)
{
- need_update = true;
+ need_update_ = true;
+}
+
+bool ParticleSystemManager::need_update() const
+{
+ return need_update_;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/particles.h b/intern/cycles/render/particles.h
index 0b0408184fe..8b59756f148 100644
--- a/intern/cycles/render/particles.h
+++ b/intern/cycles/render/particles.h
@@ -57,9 +57,9 @@ class ParticleSystem : public Node {
/* ParticleSystem Manager */
class ParticleSystemManager {
- public:
- bool need_update;
+ bool need_update_;
+ public:
ParticleSystemManager();
~ParticleSystemManager();
@@ -71,6 +71,8 @@ class ParticleSystemManager {
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);
+
+ bool need_update() const;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/procedural.cpp b/intern/cycles/render/procedural.cpp
new file mode 100644
index 00000000000..1307a35dcf2
--- /dev/null
+++ b/intern/cycles/render/procedural.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "procedural.h"
+
+#include "render/scene.h"
+#include "render/stats.h"
+
+#include "util/util_foreach.h"
+#include "util/util_progress.h"
+
+CCL_NAMESPACE_BEGIN
+
+NODE_ABSTRACT_DEFINE(Procedural)
+{
+ NodeType *type = NodeType::add("procedural_base", NULL);
+ return type;
+}
+
+Procedural::Procedural(const NodeType *type) : Node(type)
+{
+}
+
+Procedural::~Procedural()
+{
+}
+
+ProceduralManager::ProceduralManager()
+{
+ need_update_ = true;
+}
+
+ProceduralManager::~ProceduralManager()
+{
+}
+
+void ProceduralManager::update(Scene *scene, Progress &progress)
+{
+ if (!need_update()) {
+ return;
+ }
+
+ progress.set_status("Updating Procedurals");
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->procedurals.times.add_entry({"update", time});
+ }
+ });
+
+ foreach (Procedural *procedural, scene->procedurals) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ procedural->generate(scene, progress);
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ need_update_ = false;
+}
+
+void ProceduralManager::tag_update()
+{
+ need_update_ = true;
+}
+
+bool ProceduralManager::need_update() const
+{
+ return need_update_;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/procedural.h b/intern/cycles/render/procedural.h
new file mode 100644
index 00000000000..985b8d69979
--- /dev/null
+++ b/intern/cycles/render/procedural.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "graph/node.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Progress;
+class Scene;
+
+/* A Procedural is a Node which can create other Nodes before rendering starts.
+ *
+ * The Procedural is supposed to be the owner of any nodes that it creates. It can also create
+ * Nodes directly in the Scene (through Scene.create_node), it should still be set as the owner of
+ * those Nodes.
+ */
+class Procedural : public Node, public NodeOwner {
+ public:
+ NODE_ABSTRACT_DECLARE
+
+ explicit Procedural(const NodeType *type);
+ virtual ~Procedural();
+
+ /* Called each time the ProceduralManager is tagged for an update, this function is the entry
+ * point for the data generated by this Procedural. */
+ virtual void generate(Scene *scene, Progress &progress) = 0;
+
+ /* Create a node and set this Procedural as the owner. */
+ template<typename T> T *create_node()
+ {
+ T *node = new T();
+ node->set_owner(this);
+ return node;
+ }
+
+ /* Delete a Node created and owned by this Procedural. */
+ template<typename T> void delete_node(T *node)
+ {
+ assert(node->get_owner() == this);
+ delete node;
+ }
+};
+
+class ProceduralManager {
+ bool need_update_;
+
+ public:
+ ProceduralManager();
+ ~ProceduralManager();
+
+ void update(Scene *scene, Progress &progress);
+
+ void tag_update();
+
+ bool need_update() const;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index b7720b7aa99..6bb25677965 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -18,6 +18,7 @@
#include "bvh/bvh.h"
#include "device/device.h"
+#include "render/alembic.h"
#include "render/background.h"
#include "render/bake.h"
#include "render/camera.h"
@@ -29,6 +30,7 @@
#include "render/object.h"
#include "render/osl.h"
#include "render/particles.h"
+#include "render/procedural.h"
#include "render/scene.h"
#include "render/session.h"
#include "render/shader.h"
@@ -114,6 +116,7 @@ Scene::Scene(const SceneParams &params_, Device *device)
image_manager = new ImageManager(device->info);
particle_system_manager = new ParticleSystemManager();
bake_manager = new BakeManager();
+ procedural_manager = new ProceduralManager();
kernels_loaded = false;
/* TODO(sergey): Check if it's indeed optimal value for the split kernel. */
@@ -142,6 +145,9 @@ void Scene::free_memory(bool final)
foreach (Shader *s, shaders)
delete s;
+ /* delete procedurals before other types as they may hold pointers to those types */
+ foreach (Procedural *p, procedurals)
+ delete p;
foreach (Geometry *g, geometry)
delete g;
foreach (Object *o, objects)
@@ -156,15 +162,16 @@ void Scene::free_memory(bool final)
objects.clear();
lights.clear();
particle_systems.clear();
+ procedurals.clear();
if (device) {
camera->device_free(device, &dscene, this);
film->device_free(device, &dscene, this);
background->device_free(device, &dscene);
- integrator->device_free(device, &dscene);
+ integrator->device_free(device, &dscene, true);
- object_manager->device_free(device, &dscene);
- geometry_manager->device_free(device, &dscene);
+ object_manager->device_free(device, &dscene, true);
+ geometry_manager->device_free(device, &dscene, true);
shader_manager->device_free(device, &dscene, this);
light_manager->device_free(device, &dscene);
@@ -195,6 +202,7 @@ void Scene::free_memory(bool final)
delete image_manager;
delete bake_manager;
delete update_stats;
+ delete procedural_manager;
}
}
@@ -236,6 +244,11 @@ void Scene::device_update(Device *device_, Progress &progress)
if (progress.get_cancel() || device->have_error())
return;
+ procedural_manager->update(this, progress);
+
+ if (progress.get_cancel())
+ return;
+
progress.set_status("Updating Background");
background->device_update(device, &dscene, this);
@@ -386,11 +399,12 @@ bool Scene::need_update()
bool Scene::need_data_update()
{
- return (background->is_modified() || image_manager->need_update || object_manager->need_update ||
- geometry_manager->need_update || light_manager->need_update ||
- lookup_tables->need_update || integrator->is_modified() || shader_manager->need_update ||
- particle_system_manager->need_update || bake_manager->need_update ||
- film->is_modified());
+ return (background->is_modified() || image_manager->need_update() ||
+ object_manager->need_update() || geometry_manager->need_update() ||
+ light_manager->need_update() || lookup_tables->need_update() ||
+ integrator->is_modified() || shader_manager->need_update() ||
+ particle_system_manager->need_update() || bake_manager->need_update() ||
+ film->is_modified() || procedural_manager->need_update());
}
bool Scene::need_reset()
@@ -407,12 +421,15 @@ void Scene::reset()
camera->tag_modified();
dicing_camera->tag_modified();
film->tag_modified();
+ background->tag_modified();
+
background->tag_update(this);
- integrator->tag_update(this);
- object_manager->tag_update(this);
- geometry_manager->tag_update(this);
- light_manager->tag_update(this);
+ integrator->tag_update(this, Integrator::UPDATE_ALL);
+ object_manager->tag_update(this, ObjectManager::UPDATE_ALL);
+ geometry_manager->tag_update(this, GeometryManager::UPDATE_ALL);
+ light_manager->tag_update(this, LightManager::UPDATE_ALL);
particle_system_manager->tag_update(this);
+ procedural_manager->tag_update();
}
void Scene::device_free()
@@ -596,7 +613,7 @@ template<> Light *Scene::create_node<Light>()
Light *node = new Light();
node->set_owner(this);
lights.push_back(node);
- light_manager->tag_update(this);
+ light_manager->tag_update(this, LightManager::LIGHT_ADDED);
return node;
}
@@ -605,7 +622,7 @@ template<> Mesh *Scene::create_node<Mesh>()
Mesh *node = new Mesh();
node->set_owner(this);
geometry.push_back(node);
- geometry_manager->tag_update(this);
+ geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
return node;
}
@@ -614,7 +631,7 @@ template<> Hair *Scene::create_node<Hair>()
Hair *node = new Hair();
node->set_owner(this);
geometry.push_back(node);
- geometry_manager->tag_update(this);
+ geometry_manager->tag_update(this, GeometryManager::HAIR_ADDED);
return node;
}
@@ -623,7 +640,7 @@ template<> Volume *Scene::create_node<Volume>()
Volume *node = new Volume();
node->set_owner(this);
geometry.push_back(node);
- geometry_manager->tag_update(this);
+ geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
return node;
}
@@ -632,7 +649,7 @@ template<> Object *Scene::create_node<Object>()
Object *node = new Object();
node->set_owner(this);
objects.push_back(node);
- object_manager->tag_update(this);
+ object_manager->tag_update(this, ObjectManager::OBJECT_ADDED);
return node;
}
@@ -650,10 +667,23 @@ template<> Shader *Scene::create_node<Shader>()
Shader *node = new Shader();
node->set_owner(this);
shaders.push_back(node);
- shader_manager->need_update = true;
+ shader_manager->tag_update(this, ShaderManager::SHADER_ADDED);
return node;
}
+template<> AlembicProcedural *Scene::create_node<AlembicProcedural>()
+{
+#ifdef WITH_ALEMBIC
+ AlembicProcedural *node = new AlembicProcedural();
+ node->set_owner(this);
+ procedurals.push_back(node);
+ procedural_manager->tag_update();
+ return node;
+#else
+ return nullptr;
+#endif
+}
+
template<typename T> void delete_node_from_array(vector<T> &nodes, T node)
{
for (size_t i = 0; i < nodes.size(); ++i) {
@@ -664,43 +694,52 @@ template<typename T> void delete_node_from_array(vector<T> &nodes, T node)
}
nodes.resize(nodes.size() - 1);
+
delete node;
}
template<> void Scene::delete_node_impl(Light *node)
{
delete_node_from_array(lights, node);
- light_manager->tag_update(this);
+ light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
}
template<> void Scene::delete_node_impl(Mesh *node)
{
delete_node_from_array(geometry, static_cast<Geometry *>(node));
- geometry_manager->tag_update(this);
+ geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
}
template<> void Scene::delete_node_impl(Hair *node)
{
delete_node_from_array(geometry, static_cast<Geometry *>(node));
- geometry_manager->tag_update(this);
+ geometry_manager->tag_update(this, GeometryManager::HAIR_REMOVED);
}
template<> void Scene::delete_node_impl(Volume *node)
{
delete_node_from_array(geometry, static_cast<Geometry *>(node));
- geometry_manager->tag_update(this);
+ geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
}
template<> void Scene::delete_node_impl(Geometry *node)
{
+ uint flag;
+ if (node->is_hair()) {
+ flag = GeometryManager::HAIR_REMOVED;
+ }
+ else {
+ flag = GeometryManager::MESH_REMOVED;
+ }
+
delete_node_from_array(geometry, node);
- geometry_manager->tag_update(this);
+ geometry_manager->tag_update(this, flag);
}
template<> void Scene::delete_node_impl(Object *node)
{
delete_node_from_array(objects, node);
- object_manager->tag_update(this);
+ object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
}
template<> void Scene::delete_node_impl(ParticleSystem *node)
@@ -714,6 +753,21 @@ template<> void Scene::delete_node_impl(Shader * /*node*/)
/* don't delete unused shaders, not supported */
}
+template<> void Scene::delete_node_impl(Procedural *node)
+{
+ delete_node_from_array(procedurals, node);
+ procedural_manager->tag_update();
+}
+
+template<> void Scene::delete_node_impl(AlembicProcedural *node)
+{
+#ifdef WITH_ALEMBIC
+ delete_node_impl(static_cast<Procedural *>(node));
+#else
+ (void)node;
+#endif
+}
+
template<typename T>
static void remove_nodes_in_set(const set<T *> &nodes_set,
vector<T *> &nodes_array,
@@ -742,19 +796,19 @@ static void remove_nodes_in_set(const set<T *> &nodes_set,
template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner)
{
remove_nodes_in_set(nodes, lights, owner);
- light_manager->tag_update(this);
+ light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
}
template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner)
{
remove_nodes_in_set(nodes, geometry, owner);
- geometry_manager->tag_update(this);
+ geometry_manager->tag_update(this, GeometryManager::GEOMETRY_REMOVED);
}
template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner)
{
remove_nodes_in_set(nodes, objects, owner);
- object_manager->tag_update(this);
+ object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
}
template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner)
@@ -768,4 +822,10 @@ template<> void Scene::delete_nodes(const set<Shader *> & /*nodes*/, const NodeO
/* don't delete unused shaders, not supported */
}
+template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner)
+{
+ remove_nodes_in_set(nodes, procedurals, owner);
+ procedural_manager->tag_update();
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 27e9a131bbd..7595817226c 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -36,6 +36,7 @@
CCL_NAMESPACE_BEGIN
+class AlembicProcedural;
class AttributeRequestSet;
class Background;
class BVH;
@@ -53,6 +54,8 @@ class Object;
class ObjectManager;
class ParticleSystemManager;
class ParticleSystem;
+class Procedural;
+class ProceduralManager;
class CurveSystemManager;
class Shader;
class ShaderManager;
@@ -236,6 +239,7 @@ class Scene : public NodeOwner {
vector<Light *> lights;
vector<ParticleSystem *> particle_systems;
vector<Pass> passes;
+ vector<Procedural *> procedurals;
/* data managers */
ImageManager *image_manager;
@@ -245,6 +249,7 @@ class Scene : public NodeOwner {
ObjectManager *object_manager;
ParticleSystemManager *particle_system_manager;
BakeManager *bake_manager;
+ ProceduralManager *procedural_manager;
/* default shaders */
Shader *default_surface;
@@ -379,6 +384,8 @@ template<> ParticleSystem *Scene::create_node<ParticleSystem>();
template<> Shader *Scene::create_node<Shader>();
+template<> AlembicProcedural *Scene::create_node<AlembicProcedural>();
+
template<> void Scene::delete_node_impl(Light *node);
template<> void Scene::delete_node_impl(Mesh *node);
@@ -395,6 +402,10 @@ template<> void Scene::delete_node_impl(ParticleSystem *node);
template<> void Scene::delete_node_impl(Shader *node);
+template<> void Scene::delete_node_impl(Procedural *node);
+
+template<> void Scene::delete_node_impl(AlembicProcedural *node);
+
template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner);
template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner);
@@ -405,6 +416,8 @@ template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const No
template<> void Scene::delete_nodes(const set<Shader *> &nodes, const NodeOwner *owner);
+template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner);
+
CCL_NAMESPACE_END
#endif /* __SCENE_H__ */
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 7a30ecb24f7..3c601e18126 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -1040,13 +1040,7 @@ bool Session::update_scene()
BakeManager *bake_manager = scene->bake_manager;
if (integrator->get_sampling_pattern() != SAMPLING_PATTERN_SOBOL || bake_manager->get_baking()) {
- int aa_samples = tile_manager.num_samples;
-
- integrator->set_aa_samples(aa_samples);
-
- if (integrator->is_modified()) {
- integrator->tag_update(scene);
- }
+ integrator->set_aa_samples(tile_manager.num_samples);
}
bool kernel_switch_needed = false;
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index 7e06b427e4d..332599be708 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -16,6 +16,7 @@
#include "device/device.h"
+#include "render/alembic.h"
#include "render/background.h"
#include "render/camera.h"
#include "render/colorspace.h"
@@ -218,7 +219,9 @@ Shader::Shader() : Node(node_type)
id = -1;
used = false;
- need_update_geometry = true;
+ need_update_uvs = true;
+ need_update_attribute = true;
+ need_update_displacement = true;
}
Shader::~Shader()
@@ -291,7 +294,7 @@ void Shader::set_graph(ShaderGraph *graph_)
const char *new_hash = (graph_) ? graph_->displacement_hash.c_str() : "";
if (strcmp(old_hash, new_hash) != 0) {
- need_update_geometry = true;
+ need_update_displacement = true;
}
}
@@ -308,13 +311,14 @@ void Shader::tag_update(Scene *scene)
{
/* update tag */
tag_modified();
- scene->shader_manager->need_update = true;
+
+ scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
/* if the shader previously was emissive, update light distribution,
* if the new shader is emissive, a light manager update tag will be
* done in the shader manager device update. */
if (use_mis && has_surface_emission)
- scene->light_manager->need_update = true;
+ scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
/* Special handle of background MIS light for now: for some reason it
* has use_mis set to false. We are quite close to release now, so
@@ -323,7 +327,7 @@ void Shader::tag_update(Scene *scene)
if (this == scene->background->get_shader(scene)) {
scene->light_manager->need_update_background = true;
if (scene->light_manager->has_background_light(scene)) {
- scene->light_manager->need_update = true;
+ scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
}
}
@@ -352,17 +356,18 @@ void Shader::tag_update(Scene *scene)
attributes.add(ATTR_STD_POSITION_UNDISPLACED);
}
if (displacement_method_is_modified()) {
- need_update_geometry = true;
- scene->geometry_manager->need_update = true;
+ need_update_displacement = true;
+ scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_DISPLACEMENT_MODIFIED);
scene->object_manager->need_flags_update = true;
}
}
/* compare if the attributes changed, mesh manager will check
- * need_update_geometry, update the relevant meshes and clear it. */
+ * need_update_attribute, update the relevant meshes and clear it. */
if (attributes.modified(prev_attributes)) {
- need_update_geometry = true;
- scene->geometry_manager->need_update = true;
+ need_update_attribute = true;
+ scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_ATTRIBUTE_MODIFIED);
+ scene->procedural_manager->tag_update();
}
if (has_volume != prev_has_volume || volume_step_rate != prev_volume_step_rate) {
@@ -378,15 +383,20 @@ void Shader::tag_used(Scene *scene)
* recompiled because it was skipped for compilation before */
if (!used) {
tag_modified();
- scene->shader_manager->need_update = true;
+ scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
}
}
+bool Shader::need_update_geometry() const
+{
+ return need_update_uvs || need_update_attribute || need_update_displacement;
+}
+
/* Shader Manager */
ShaderManager::ShaderManager()
{
- need_update = true;
+ update_flags = UPDATE_ALL;
beckmann_table_offset = TABLE_OFFSET_INVALID;
xyz_to_r = make_float3(3.2404542f, -1.5371385f, -0.4985314f);
@@ -484,7 +494,7 @@ int ShaderManager::get_shader_id(Shader *shader, bool smooth)
void ShaderManager::update_shaders_used(Scene *scene)
{
- if (!need_update) {
+ if (!need_update()) {
return;
}
@@ -504,6 +514,21 @@ void ShaderManager::update_shaders_used(Scene *scene)
if (scene->background->get_shader())
scene->background->get_shader()->used = true;
+#ifdef WITH_ALEMBIC
+ foreach (Procedural *procedural, scene->procedurals) {
+ AlembicProcedural *abc_proc = static_cast<AlembicProcedural *>(procedural);
+
+ foreach (Node *abc_node, abc_proc->get_objects()) {
+ AlembicObject *abc_object = static_cast<AlembicObject *>(abc_node);
+
+ foreach (Node *node, abc_object->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+ shader->used = true;
+ }
+ }
+ }
+#endif
+
foreach (Geometry *geom, scene->geometry)
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
@@ -793,4 +818,15 @@ string ShaderManager::get_cryptomatte_materials(Scene *scene)
return manifest;
}
+void ShaderManager::tag_update(Scene * /*scene*/, uint32_t /*flag*/)
+{
+ /* update everything for now */
+ update_flags = ShaderManager::UPDATE_ALL;
+}
+
+bool ShaderManager::need_update() const
+{
+ return update_flags != UPDATE_NONE;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h
index de19048d8e1..4375ef9e978 100644
--- a/intern/cycles/render/shader.h
+++ b/intern/cycles/render/shader.h
@@ -100,7 +100,9 @@ class Shader : public Node {
float prev_volume_step_rate;
/* synchronization */
- bool need_update_geometry;
+ bool need_update_uvs;
+ bool need_update_attribute;
+ bool need_update_displacement;
/* If the shader has only volume components, the surface is assumed to
* be transparent.
@@ -152,6 +154,8 @@ class Shader : public Node {
void set_graph(ShaderGraph *graph);
void tag_update(Scene *scene);
void tag_used(Scene *scene);
+
+ bool need_update_geometry() const;
};
/* Shader Manager virtual base class
@@ -161,7 +165,16 @@ class Shader : public Node {
class ShaderManager {
public:
- bool need_update;
+ enum : uint32_t {
+ SHADER_ADDED = (1 << 0),
+ SHADER_MODIFIED = (1 << 2),
+ INTEGRATOR_MODIFIED = (1 << 3),
+
+ /* tag everything in the manager for an update */
+ UPDATE_ALL = ~0u,
+
+ UPDATE_NONE = 0u,
+ };
static ShaderManager *create(int shadingsystem);
virtual ~ShaderManager();
@@ -204,9 +217,15 @@ class ShaderManager {
string get_cryptomatte_materials(Scene *scene);
+ void tag_update(Scene *scene, uint32_t flag);
+
+ bool need_update() const;
+
protected:
ShaderManager();
+ uint32_t update_flags;
+
typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap;
AttributeIDMap unique_attribute_id;
diff --git a/intern/cycles/render/stats.cpp b/intern/cycles/render/stats.cpp
index 1a840a906a5..2c6273842e2 100644
--- a/intern/cycles/render/stats.cpp
+++ b/intern/cycles/render/stats.cpp
@@ -375,6 +375,7 @@ string SceneUpdateStats::full_report()
result += "Particles:\n" + particles.full_report(1);
result += "SVM:\n" + svm.full_report(1);
result += "Tables:\n" + tables.full_report(1);
+ result += "Procedurals:\n" + procedurals.full_report(1);
return result;
}
@@ -394,6 +395,7 @@ void SceneUpdateStats::clear()
scene.times.clear();
svm.times.clear();
tables.times.clear();
+ procedurals.times.clear();
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/stats.h b/intern/cycles/render/stats.h
index a6be27db4c2..93d029bba61 100644
--- a/intern/cycles/render/stats.h
+++ b/intern/cycles/render/stats.h
@@ -219,6 +219,7 @@ class SceneUpdateStats {
UpdateTimeStats scene;
UpdateTimeStats svm;
UpdateTimeStats tables;
+ UpdateTimeStats procedurals;
string full_report();
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index 6f5a03124f2..fce604234f1 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -74,7 +74,7 @@ void SVMShaderManager::device_update(Device *device,
Scene *scene,
Progress &progress)
{
- if (!need_update)
+ if (!need_update())
return;
scoped_callback_timer timer([scene](double time) {
@@ -125,7 +125,7 @@ void SVMShaderManager::device_update(Device *device,
shader->clear_modified();
if (shader->get_use_mis() && shader->has_surface_emission) {
- scene->light_manager->need_update = true;
+ scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
}
/* Update the global jump table.
@@ -159,7 +159,7 @@ void SVMShaderManager::device_update(Device *device,
device_update_common(device, dscene, scene, progress);
- need_update = false;
+ update_flags = UPDATE_NONE;
VLOG(1) << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
<< " seconds.";
diff --git a/intern/cycles/render/tables.cpp b/intern/cycles/render/tables.cpp
index b581537c852..a0813400b1c 100644
--- a/intern/cycles/render/tables.cpp
+++ b/intern/cycles/render/tables.cpp
@@ -28,7 +28,7 @@ CCL_NAMESPACE_BEGIN
LookupTables::LookupTables()
{
- need_update = true;
+ need_update_ = true;
}
LookupTables::~LookupTables()
@@ -38,7 +38,7 @@ LookupTables::~LookupTables()
void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene)
{
- if (!need_update)
+ if (!need_update())
return;
scoped_callback_timer timer([scene](double time) {
@@ -52,7 +52,7 @@ void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene)
if (lookup_tables.size() > 0)
dscene->lookup_table.copy_to_device();
- need_update = false;
+ need_update_ = false;
}
void LookupTables::device_free(Device *, DeviceScene *dscene)
@@ -60,6 +60,11 @@ void LookupTables::device_free(Device *, DeviceScene *dscene)
dscene->lookup_table.free();
}
+bool LookupTables::need_update() const
+{
+ return need_update_;
+}
+
static size_t round_up_to_multiple(size_t size, size_t chunk)
{
return ((size + chunk - 1) / chunk) * chunk;
@@ -69,7 +74,7 @@ size_t LookupTables::add_table(DeviceScene *dscene, vector<float> &data)
{
assert(data.size() > 0);
- need_update = true;
+ need_update_ = true;
Table new_table;
new_table.offset = 0;
@@ -107,7 +112,7 @@ void LookupTables::remove_table(size_t *offset)
return;
}
- need_update = true;
+ need_update_ = true;
list<Table>::iterator table;
diff --git a/intern/cycles/render/tables.h b/intern/cycles/render/tables.h
index e912d9c01f4..de538e2af78 100644
--- a/intern/cycles/render/tables.h
+++ b/intern/cycles/render/tables.h
@@ -30,13 +30,14 @@ enum { TABLE_CHUNK_SIZE = 256 };
enum { TABLE_OFFSET_INVALID = -1 };
class LookupTables {
+ bool need_update_;
+
public:
struct Table {
size_t offset;
size_t size;
};
- bool need_update;
list<Table> lookup_tables;
LookupTables();
@@ -45,6 +46,8 @@ class LookupTables {
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene);
+ bool need_update() const;
+
size_t add_table(DeviceScene *dscene, vector<float> &data);
void remove_table(size_t *offset);
};
diff --git a/intern/cycles/util/util_array.h b/intern/cycles/util/util_array.h
index ea481787018..73f7d6cf7f8 100644
--- a/intern/cycles/util/util_array.h
+++ b/intern/cycles/util/util_array.h
@@ -131,6 +131,14 @@ template<typename T, size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES> class arra
}
}
+ void set_data(T *ptr_, size_t datasize)
+ {
+ clear();
+ data_ = ptr_;
+ datasize_ = datasize;
+ capacity_ = datasize;
+ }
+
T *steal_pointer()
{
T *ptr = data_;
diff --git a/intern/ghost/intern/GHOST_DropTargetX11.h b/intern/ghost/intern/GHOST_DropTargetX11.h
index 69f6fec7ac1..7d777270317 100644
--- a/intern/ghost/intern/GHOST_DropTargetX11.h
+++ b/intern/ghost/intern/GHOST_DropTargetX11.h
@@ -109,7 +109,7 @@ class GHOST_DropTargetX11 {
/* class holding internal stiff of xdnd library */
static DndClass m_dndClass;
- /* list of supported types to eb draggeg into */
+ /* list of supported types to be dragged into */
static Atom *m_dndTypes;
/* list of supported dran'n'drop actions */
diff --git a/intern/guardedalloc/CMakeLists.txt b/intern/guardedalloc/CMakeLists.txt
index 0d46e81cd87..b47565b8ef9 100644
--- a/intern/guardedalloc/CMakeLists.txt
+++ b/intern/guardedalloc/CMakeLists.txt
@@ -49,12 +49,6 @@ set(LIB
)
if(WIN32 AND NOT UNIX)
- list(APPEND SRC
- intern/mmap_win.c
-
- mmap_win.h
- )
-
list(APPEND INC_SYS
${PTHREADS_INC}
)
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index a0174e30aff..62f28c9e97e 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -122,7 +122,7 @@ extern void *(*MEM_calloc_arrayN)(size_t len,
/**
* Allocate a block of memory of size len, with tag name str. The
* name must be a static, because only a pointer to it is stored !
- * */
+ */
extern void *(*MEM_mallocN)(size_t len, const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
ATTR_ALLOC_SIZE(1) ATTR_NONNULL(2);
@@ -130,7 +130,7 @@ extern void *(*MEM_mallocN)(size_t len, const char *str) /* ATTR_MALLOC */ ATTR_
* Allocate a block of memory of size (len * size), with tag name str,
* aborting in case of integer overflow to prevent vulnerabilities. The
* name must be a static, because only a pointer to it is stored !
- * */
+ */
extern void *(*MEM_malloc_arrayN)(size_t len,
size_t size,
const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
@@ -139,7 +139,7 @@ extern void *(*MEM_malloc_arrayN)(size_t len,
/**
* Allocate an aligned block of memory of size len, with tag name str. The
* name must be a static, because only a pointer to it is stored !
- * */
+ */
extern void *(*MEM_mallocN_aligned)(size_t len,
size_t alignment,
const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
diff --git a/intern/guardedalloc/intern/mmap_win.c b/intern/guardedalloc/intern/mmap_win.c
deleted file mode 100644
index a02a0f88fa9..00000000000
--- a/intern/guardedalloc/intern/mmap_win.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup MEM
- */
-
-#ifdef WIN32
-
-# include <errno.h>
-# include <io.h>
-# include <stdio.h>
-# include <sys/types.h>
-# include <windows.h>
-
-# include "mmap_win.h"
-
-# ifndef FILE_MAP_EXECUTE
-// not defined in earlier versions of the Platform SDK (before February 2003)
-# define FILE_MAP_EXECUTE 0x0020
-# endif
-
-/* copied from BLI_utildefines.h, ugh */
-# ifdef __GNUC__
-# define UNUSED(x) UNUSED_##x __attribute__((__unused__))
-# else
-# define UNUSED(x) x
-# endif
-
-/* --------------------------------------------------------------------- */
-/* local storage definitions */
-/* --------------------------------------------------------------------- */
-/* all memory mapped chunks are put in linked lists */
-typedef struct mmapLink {
- struct mmapLink *next, *prev;
-} mmapLink;
-
-typedef struct mmapListBase {
- void *first, *last;
-} mmapListBase;
-
-typedef struct MemMap {
- struct MemMap *next, *prev;
- void *mmap;
- HANDLE fhandle;
- HANDLE maphandle;
-} MemMap;
-
-/* --------------------------------------------------------------------- */
-/* local functions */
-/* --------------------------------------------------------------------- */
-
-static void mmap_addtail(volatile mmapListBase *listbase, void *vlink);
-static void mmap_remlink(volatile mmapListBase *listbase, void *vlink);
-static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr);
-
-static int mmap_get_prot_flags(int flags);
-static int mmap_get_access_flags(int flags);
-
-/* --------------------------------------------------------------------- */
-/* vars */
-/* --------------------------------------------------------------------- */
-volatile static struct mmapListBase _mmapbase;
-volatile static struct mmapListBase *mmapbase = &_mmapbase;
-
-/* --------------------------------------------------------------------- */
-/* implementation */
-/* --------------------------------------------------------------------- */
-
-/* mmap for windows */
-void *mmap(void *UNUSED(start), size_t len, int prot, int flags, int fd, off_t offset)
-{
- HANDLE fhandle = INVALID_HANDLE_VALUE;
- HANDLE maphandle;
- int prot_flags = mmap_get_prot_flags(prot);
- int access_flags = mmap_get_access_flags(prot);
- MemMap *mm = NULL;
- void *ptr = NULL;
-
- if (flags & MAP_FIXED) {
- return MAP_FAILED;
- }
-
-# if 0
- if (fd == -1) {
- _set_errno(EBADF);
- return MAP_FAILED;
- }
-# endif
-
- if (fd != -1) {
- fhandle = (HANDLE)_get_osfhandle(fd);
- }
- if (fhandle == INVALID_HANDLE_VALUE) {
- if (!(flags & MAP_ANONYMOUS)) {
- errno = EBADF;
- return MAP_FAILED;
- }
- }
- else {
- if (!DuplicateHandle(GetCurrentProcess(),
- fhandle,
- GetCurrentProcess(),
- &fhandle,
- 0,
- FALSE,
- DUPLICATE_SAME_ACCESS)) {
- return MAP_FAILED;
- }
- }
-
- /* Split 64 bit size into low and high bits. */
- DWORD len_bits_high = len >> 32;
- DWORD len_bits_low = len & 0xFFFFFFFF;
-
- maphandle = CreateFileMapping(fhandle, NULL, prot_flags, len_bits_high, len_bits_low, NULL);
- if (maphandle == 0) {
- errno = EBADF;
- return MAP_FAILED;
- }
-
- ptr = MapViewOfFile(maphandle, access_flags, 0, offset, 0);
- if (ptr == NULL) {
- DWORD dwLastErr = GetLastError();
- if (dwLastErr == ERROR_MAPPED_ALIGNMENT) {
- errno = EINVAL;
- }
- else {
- errno = EACCES;
- }
- CloseHandle(maphandle);
- return MAP_FAILED;
- }
-
- mm = (MemMap *)malloc(sizeof(MemMap));
- if (!mm) {
- errno = ENOMEM;
- }
- mm->fhandle = fhandle;
- mm->maphandle = maphandle;
- mm->mmap = ptr;
- mmap_addtail(mmapbase, mm);
-
- return ptr;
-}
-
-/* munmap for windows */
-intptr_t munmap(void *ptr, size_t UNUSED(size))
-{
- MemMap *mm = mmap_findlink(mmapbase, ptr);
- if (!mm) {
- errno = EINVAL;
- return -1;
- }
- UnmapViewOfFile(mm->mmap);
- CloseHandle(mm->maphandle);
- CloseHandle(mm->fhandle);
- mmap_remlink(mmapbase, mm);
- free(mm);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-/* local functions */
-/* --------------------------------------------------------------------- */
-
-static void mmap_addtail(volatile mmapListBase *listbase, void *vlink)
-{
- struct mmapLink *link = vlink;
-
- if (link == NULL) {
- return;
- }
- if (listbase == NULL) {
- return;
- }
-
- link->next = 0;
- link->prev = listbase->last;
-
- if (listbase->last) {
- ((struct mmapLink *)listbase->last)->next = link;
- }
- if (listbase->first == NULL) {
- listbase->first = link;
- }
- listbase->last = link;
-}
-
-static void mmap_remlink(volatile mmapListBase *listbase, void *vlink)
-{
- struct mmapLink *link = vlink;
-
- if (link == NULL) {
- return;
- }
- if (listbase == NULL) {
- return;
- }
- if (link->next) {
- link->next->prev = link->prev;
- }
- if (link->prev) {
- link->prev->next = link->next;
- }
-
- if (listbase->last == link) {
- listbase->last = link->prev;
- }
- if (listbase->first == link) {
- listbase->first = link->next;
- }
-}
-
-static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr)
-{
- MemMap *mm;
-
- if (ptr == NULL) {
- return NULL;
- }
- if (listbase == NULL) {
- return NULL;
- }
-
- mm = (MemMap *)listbase->first;
- while (mm) {
- if (mm->mmap == ptr) {
- return mm;
- }
- mm = mm->next;
- }
- return NULL;
-}
-
-static int mmap_get_prot_flags(int flags)
-{
- int prot = PAGE_NOACCESS;
-
- if ((flags & PROT_READ) == PROT_READ) {
- if ((flags & PROT_WRITE) == PROT_WRITE) {
- prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
- }
- else {
- prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_READONLY;
- }
- }
- else if ((flags & PROT_WRITE) == PROT_WRITE) {
- prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_WRITECOPY;
- }
- else if ((flags & PROT_EXEC) == PROT_EXEC) {
- prot = PAGE_EXECUTE_READ;
- }
- return prot;
-}
-
-static int mmap_get_access_flags(int flags)
-{
- int access = 0;
-
- if ((flags & PROT_READ) == PROT_READ) {
- if ((flags & PROT_WRITE) == PROT_WRITE) {
- access = FILE_MAP_WRITE;
- }
- else {
- access = (flags & PROT_EXEC) ? FILE_MAP_EXECUTE : FILE_MAP_READ;
- }
- }
- else if ((flags & PROT_WRITE) == PROT_WRITE) {
- access = FILE_MAP_COPY;
- }
- else if ((flags & PROT_EXEC) == PROT_EXEC) {
- access = FILE_MAP_EXECUTE;
- }
- return access;
-}
-
-#endif // WIN32
diff --git a/intern/guardedalloc/mmap_win.h b/intern/guardedalloc/mmap_win.h
deleted file mode 100644
index c0cbaa0e512..00000000000
--- a/intern/guardedalloc/mmap_win.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup MEM
- */
-
-#ifndef __MMAP_WIN_H__
-#define __MMAP_WIN_H__
-
-#define PROT_NONE 0
-#define PROT_READ 1
-#define PROT_WRITE 2
-#define PROT_EXEC 4
-
-#define MAP_FILE 0
-#define MAP_SHARED 1
-#define MAP_PRIVATE 2
-#define MAP_TYPE 0xF
-#define MAP_FIXED 0x10
-#define MAP_ANONYMOUS 0x20
-#define MAP_ANON MAP_ANONYMOUS
-
-#define MAP_FAILED ((void *)-1)
-
-/* needed for uintptr_t, exception, dont use BLI anywhere else in MEM_* */
-#include "../../source/blender/blenlib/BLI_sys_types.h"
-
-#include <sys/types.h>
-
-void *mmap(void *start, size_t len, int prot, int flags, int fd, off_t offset);
-intptr_t munmap(void *ptr, size_t size);
-
-#endif
diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png
index 858709833fb..babb3e30c6d 100644
--- a/release/datafiles/splash.png
+++ b/release/datafiles/splash.png
Binary files differ
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c
index b448a230da8..2265e70df39 100644
--- a/release/datafiles/userdef/userdef_default.c
+++ b/release/datafiles/userdef/userdef_default.c
@@ -119,6 +119,7 @@ const UserDef U_default = {
.gizmo_flag = USER_GIZMO_DRAW,
.gizmo_size = 75,
+ .gizmo_size_navigate_v3d = 80,
.edit_studio_light = 0,
.lookdev_sphere_size = 150,
.vbotimeout = 120,
diff --git a/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py b/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py
index ebc5370a7af..ef398d5e08f 100644
--- a/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py
+++ b/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py
@@ -74,8 +74,6 @@ def generate(context, space_type, use_fallback_keys=True, use_reset=True):
if tap_reset_tool not in items_all_id:
use_tap_reset = False
- from bl_operators.wm import use_toolbar_release_hack
-
# Pie-menu style release to activate.
use_release_confirm = use_reset
@@ -437,7 +435,7 @@ def generate(context, space_type, use_fallback_keys=True, use_reset=True):
kmi = keymap.keymap_items.new(
"wm.tool_set_by_id",
- value='PRESS' if use_toolbar_release_hack else 'DOUBLE_CLICK',
+ value='DOUBLE_CLICK',
**kmi_toolbar_args_available,
)
kmi.properties.name = tap_reset_tool
@@ -451,15 +449,6 @@ def generate(context, space_type, use_fallback_keys=True, use_reset=True):
)
kmi.properties.skip_depressed = True
- if use_toolbar_release_hack:
- # ... or pass through to let the toolbar know we're released.
- # Let the operator know we're released.
- kmi = keymap.keymap_items.new(
- "wm.tool_set_by_id",
- type=kmi_toolbar_type,
- value='RELEASE',
- any=True,
- )
wm.keyconfigs.update()
return keymap
diff --git a/release/scripts/presets/keyconfig/blender_27x.py b/release/scripts/presets/keyconfig/blender_27x.py
index efb013b9216..2a7f0b07fa6 100644
--- a/release/scripts/presets/keyconfig/blender_27x.py
+++ b/release/scripts/presets/keyconfig/blender_27x.py
@@ -1,3 +1,28 @@
+#
+# Notes on this key-map:
+#
+# This uses Blender's key-map, running with `legacy=True`.
+#
+# The intention of this key-map is to match Blender 2.7x which had many more key-map items available.
+#
+# There are some differences with the original Blender 2.7x key-map.
+# There is no intention to change these are they are not considered significant
+# enough to make a 1:1 match with the previous Blender version.
+#
+# These include:
+#
+# 3D View
+# =======
+#
+# - Border Render (`Shift-B` -> `Ctrl-B`)
+# Both `Shift-B` and `Ctrl-B` were used.
+#
+# Time Line/Animation Views
+# =========================
+#
+# - Start Frame/End Frame (`S/E` -> `Ctrl-Home/Ctrl-End`)
+#
+
import os
import bpy
from bpy.props import (
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index ee46742fbd0..2ee20e08589 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -33,11 +33,6 @@ from bpy.props import (
)
from bpy.app.translations import pgettext_iface as iface_
-# FIXME, we need a way to detect key repeat events.
-# unfortunately checking event previous values isn't reliable.
-use_toolbar_release_hack = True
-
-
rna_path_prop = StringProperty(
name="Context Attributes",
description="RNA context string",
@@ -1698,18 +1693,6 @@ class WM_OT_tool_set_by_id(Operator):
space_type: rna_space_type_prop
- if use_toolbar_release_hack:
- def invoke(self, context, event):
- # Hack :S
- if not self.properties.is_property_set("name"):
- WM_OT_toolbar._key_held = False
- return {'PASS_THROUGH'}
- elif (WM_OT_toolbar._key_held == event.type) and (event.value != 'RELEASE'):
- return {'PASS_THROUGH'}
- WM_OT_toolbar._key_held = None
-
- return self.execute(context)
-
def execute(self, context):
from bl_ui.space_toolsystem_common import (
activate_by_id,
@@ -1801,13 +1784,6 @@ class WM_OT_toolbar(Operator):
def poll(cls, context):
return context.space_data is not None
- if use_toolbar_release_hack:
- _key_held = None
-
- def invoke(self, context, event):
- WM_OT_toolbar._key_held = event.type
- return self.execute(context)
-
@staticmethod
def keymap_from_toolbar(context, space_type, use_fallback_keys=True, use_reset=True):
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py
index 351d4928ddf..9db6eedb04c 100644
--- a/release/scripts/startup/bl_ui/properties_data_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py
@@ -23,6 +23,7 @@ from rna_prop_ui import PropertyPanel
from bl_ui.properties_grease_pencil_common import (
GreasePencilLayerMasksPanel,
+ GreasePencilLayerTransformPanel,
GreasePencilLayerAdjustmentsPanel,
GreasePencilLayerRelationsPanel,
GreasePencilLayerDisplayPanel,
@@ -90,8 +91,10 @@ class GPENCIL_MT_layer_context_menu(Menu):
layout = self.layout
ob = context.object
gpd = ob.data
+ gpl = gpd.layers.active
- layout.operator("gpencil.layer_duplicate", icon='DUPLICATE')
+ layout.operator("gpencil.layer_duplicate", text="Duplicate", icon='DUPLICATE').mode='ALL'
+ layout.operator("gpencil.layer_duplicate", text="Duplicate Empty Keyframes").mode='EMPTY'
layout.separator()
@@ -103,6 +106,7 @@ class GPENCIL_MT_layer_context_menu(Menu):
layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All")
layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="Unlock All")
layout.prop(gpd, "use_autolock_layers", text="Autolock Inactive Layers")
+ layout.prop(gpl, "lock_material")
layout.separator()
@@ -188,6 +192,12 @@ class DATA_PT_gpencil_layer_masks(LayerDataButtonsPanel, GreasePencilLayerMasksP
bl_options = {'DEFAULT_CLOSED'}
+class DATA_PT_gpencil_layer_transform(LayerDataButtonsPanel, GreasePencilLayerTransformPanel, Panel):
+ bl_label = "Transform"
+ bl_parent_id = 'DATA_PT_gpencil_layers'
+ bl_options = {'DEFAULT_CLOSED'}
+
+
class DATA_PT_gpencil_layer_adjustments(LayerDataButtonsPanel, GreasePencilLayerAdjustmentsPanel, Panel):
bl_label = "Adjustments"
bl_parent_id = 'DATA_PT_gpencil_layers'
@@ -424,6 +434,7 @@ classes = (
DATA_PT_gpencil_onion_skinning_custom_colors,
DATA_PT_gpencil_onion_skinning_display,
DATA_PT_gpencil_layer_masks,
+ DATA_PT_gpencil_layer_transform,
DATA_PT_gpencil_layer_adjustments,
DATA_PT_gpencil_layer_relations,
DATA_PT_gpencil_layer_display,
diff --git a/release/scripts/startup/bl_ui/properties_data_volume.py b/release/scripts/startup/bl_ui/properties_data_volume.py
index d4f108dcf24..e7bf9adb876 100644
--- a/release/scripts/startup/bl_ui/properties_data_volume.py
+++ b/release/scripts/startup/bl_ui/properties_data_volume.py
@@ -63,7 +63,7 @@ class DATA_PT_volume_file(DataButtonsPanel, Panel):
layout.prop(volume, "filepath", text="")
- if len(volume.filepath):
+ if volume.filepath:
layout.use_property_split = True
layout.use_property_decorate = False
@@ -76,7 +76,7 @@ class DATA_PT_volume_file(DataButtonsPanel, Panel):
col.prop(volume, "sequence_mode", text="Mode")
error_msg = volume.grids.error_message
- if len(error_msg):
+ if error_msg:
layout.separator()
col = layout.column(align=True)
col.label(text="Failed to load volume:")
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 8b404c4a306..67905192fe8 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -727,12 +727,32 @@ class GreasePencilSimplifyPanel:
col.prop(rd, "simplify_gpencil_antialiasing")
+class GreasePencilLayerTransformPanel:
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ob = context.object
+ gpd = ob.data
+ gpl = gpd.layers.active
+ layout.active = not gpl.lock
+
+ row = layout.row(align=True)
+ row.prop(gpl, "location")
+
+ row = layout.row(align=True)
+ row.prop(gpl, "rotation")
+
+ row = layout.row(align=True)
+ row.prop(gpl, "scale")
+
+
class GreasePencilLayerAdjustmentsPanel:
def draw(self, context):
layout = self.layout
layout.use_property_split = True
- scene = context.scene
ob = context.object
gpd = ob.data
@@ -750,15 +770,6 @@ class GreasePencilLayerAdjustmentsPanel:
col = layout.row(align=True)
col.prop(gpl, "line_change", text="Stroke Thickness")
- col = layout.row(align=True)
- col.prop(gpl, "pass_index")
-
- col = layout.row(align=True)
- col.prop_search(gpl, "viewlayer_render", scene, "view_layers", text="View Layer")
-
- col = layout.row(align=True)
- col.prop(gpl, "lock_material")
-
class GPENCIL_UL_masks(UIList):
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
@@ -826,6 +837,7 @@ class GreasePencilLayerRelationsPanel:
layout.use_property_split = True
layout.use_property_decorate = False
+ scene = context.scene
ob = context.object
gpd = ob.data
gpl = gpd.layers.active
@@ -839,6 +851,14 @@ class GreasePencilLayerRelationsPanel:
if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
col.prop_search(gpl, "parent_bone", parent.data, "bones", text="Bone")
+ layout.separator()
+
+ col = layout.row(align=True)
+ col.prop(gpl, "pass_index")
+
+ col = layout.row(align=True)
+ col.prop_search(gpl, "viewlayer_render", scene, "view_layers", text="View Layer")
+
class GreasePencilLayerDisplayPanel:
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index 9d74a9c9fea..96920af1c7e 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -502,7 +502,9 @@ class CLIP_PT_tools_tracking(CLIP_PT_tracking_panel, Panel):
col = layout.column(align=True)
row = col.row(align=True)
row.label(text="Merge:")
- row.operator("clip.join_tracks", text="Join Tracks")
+ sub = row.column()
+ sub.operator("clip.join_tracks", text="Join Tracks")
+ sub.operator("clip.average_tracks", text="Average Tracks")
class CLIP_PT_tools_plane_tracking(CLIP_PT_tracking_panel, Panel):
@@ -1482,6 +1484,7 @@ class CLIP_MT_track(Menu):
layout.separator()
layout.operator("clip.join_tracks")
+ layout.operator("clip.average_tracks")
layout.separator()
@@ -1608,6 +1611,7 @@ class CLIP_MT_tracking_context_menu(Menu):
layout.separator()
layout.operator("clip.join_tracks")
+ layout.operator("clip.average_tracks")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 0c222e8c023..aa98e4292f4 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -27,6 +27,7 @@ from bpy.types import (
from bl_ui.properties_grease_pencil_common import (
GreasePencilLayerMasksPanel,
+ GreasePencilLayerTransformPanel,
GreasePencilLayerAdjustmentsPanel,
GreasePencilLayerRelationsPanel,
GreasePencilLayerDisplayPanel,
@@ -726,6 +727,12 @@ class DOPESHEET_PT_gpencil_layer_masks(LayersDopeSheetPanel, GreasePencilLayerMa
bl_options = {'DEFAULT_CLOSED'}
+class DOPESHEET_PT_gpencil_layer_transform(LayersDopeSheetPanel, GreasePencilLayerTransformPanel, Panel):
+ bl_label = "Transform"
+ bl_parent_id = 'DOPESHEET_PT_gpencil_mode'
+ bl_options = {'DEFAULT_CLOSED'}
+
+
class DOPESHEET_PT_gpencil_layer_adjustments(LayersDopeSheetPanel, GreasePencilLayerAdjustmentsPanel, Panel):
bl_label = "Adjustments"
bl_parent_id = 'DOPESHEET_PT_gpencil_mode'
@@ -762,6 +769,7 @@ classes = (
DOPESHEET_PT_filters,
DOPESHEET_PT_gpencil_mode,
DOPESHEET_PT_gpencil_layer_masks,
+ DOPESHEET_PT_gpencil_layer_transform,
DOPESHEET_PT_gpencil_layer_adjustments,
DOPESHEET_PT_gpencil_layer_relations,
DOPESHEET_PT_gpencil_layer_display,
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index e6af83b61f4..a9934850acd 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -678,16 +678,8 @@ class NODE_UL_interface_sockets(bpy.types.UIList):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
row = layout.row(align=True)
- # inputs get icon on the left
- if not socket.is_output:
- row.template_node_socket(color=color)
-
+ row.template_node_socket(color=color)
row.prop(socket, "name", text="", emboss=False, icon_value=icon)
-
- # outputs get icon on the right
- if socket.is_output:
- row.template_node_socket(color=color)
-
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.template_node_socket(color=color)
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 4b30266a5fe..a0b5355e64d 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -691,6 +691,9 @@ class USERPREF_PT_viewport_display(ViewportPanel, CenterAlignMixIn, Panel):
col.prop(view, "mini_axis_size", text="Size")
col.prop(view, "mini_axis_brightness", text="Brightness")
+ if view.mini_axis_type == 'GIZMO':
+ col.prop(view, "gizmo_size_navigate_v3d", text="Size")
+
class USERPREF_PT_viewport_quality(ViewportPanel, CenterAlignMixIn, Panel):
bl_label = "Quality"
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 3ed50a8c0a3..ebb6280a42f 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2236,11 +2236,6 @@ class VIEW3D_MT_object_relations(Menu):
layout.operator_menu_enum("object.make_local", "type", text="Make Local...")
layout.menu("VIEW3D_MT_make_single_user")
- layout.separator()
-
- layout.operator("object.data_transfer")
- layout.operator("object.datalayout_transfer")
-
class VIEW3D_MT_object(Menu):
bl_context = "objectmode"
@@ -2274,7 +2269,7 @@ class VIEW3D_MT_object(Menu):
layout.menu("VIEW3D_MT_object_relations")
layout.menu("VIEW3D_MT_object_constraints")
layout.menu("VIEW3D_MT_object_track")
- layout.menu("VIEW3D_MT_make_links", text="Make Links")
+ layout.menu("VIEW3D_MT_make_links")
layout.separator()
@@ -2292,16 +2287,7 @@ class VIEW3D_MT_object(Menu):
layout.separator()
- ob = context.active_object
- if ob and ob.type == 'GPENCIL' and context.gpencil_data:
- layout.operator_menu_enum("gpencil.convert", "type", text="Convert To")
- else:
- layout.operator_menu_enum("object.convert", "target")
-
- # Potrace lib dependency
- if bpy.app.build_options.potrace:
- layout.separator()
- layout.operator("gpencil.trace_image")
+ layout.menu("VIEW3D_MT_object_convert")
layout.separator()
@@ -2397,37 +2383,25 @@ class VIEW3D_MT_object_context_menu(Menu):
'''
# If something is selected
- if obj is not None and obj.type in {'MESH', 'CURVE', 'SURFACE'}:
- layout.operator("object.shade_smooth", text="Shade Smooth")
- layout.operator("object.shade_flat", text="Shade Flat")
-
- layout.separator()
+ # Individual object types.
if obj is None:
pass
- elif obj.type == 'MESH':
- layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
-
- layout.operator_context = 'INVOKE_DEFAULT'
- # If more than one object is selected
- if selected_objects_len > 1:
- layout.operator("object.join")
-
- layout.separator()
elif obj.type == 'CAMERA':
layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator("view3d.object_as_camera", text="Set Active Camera")
+
if obj.data.type == 'PERSP':
- props = layout.operator("wm.context_modal_mouse", text="Camera Lens Angle")
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Focal Length")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.lens"
props.input_scale = 0.1
if obj.data.lens_unit == 'MILLIMETERS':
- props.header_text = "Camera Lens Angle: %.1fmm"
+ props.header_text = "Camera Focal Length: %.1fmm"
else:
- props.header_text = "Camera Lens Angle: %.1f\u00B0"
+ props.header_text = "Camera Focal Length: %.1f\u00B0"
else:
props = layout.operator("wm.context_modal_mouse", text="Camera Lens Scale")
@@ -2440,88 +2414,83 @@ class VIEW3D_MT_object_context_menu(Menu):
if view and view.camera == obj and view.region_3d.view_perspective == 'CAMERA':
props = layout.operator("ui.eyedropper_depth", text="DOF Distance (Pick)")
else:
- props = layout.operator("wm.context_modal_mouse", text="DOF Distance")
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Focus Distance")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.dof.focus_distance"
props.input_scale = 0.02
- props.header_text = "DOF Distance: %.3f"
+ props.header_text = "Focus Distance: %.3f"
layout.separator()
elif obj.type in {'CURVE', 'FONT'}:
layout.operator_context = 'INVOKE_REGION_WIN'
- props = layout.operator("wm.context_modal_mouse", text="Extrude Size")
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Extrusion")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.extrude"
props.input_scale = 0.01
- props.header_text = "Extrude Size: %.3f"
+ props.header_text = "Extrude: %.3f"
- props = layout.operator("wm.context_modal_mouse", text="Width Size")
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Offset")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.offset"
props.input_scale = 0.01
- props.header_text = "Width Size: %.3f"
-
- layout.separator()
-
- layout.operator("object.convert", text="Convert to Mesh").target = 'MESH'
- layout.operator("object.convert", text="Convert to Grease Pencil").target = 'GPENCIL'
- layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
-
- layout.separator()
-
- elif obj.type == 'GPENCIL':
- layout.operator("gpencil.convert", text="Convert to Path").type = 'PATH'
- layout.operator("gpencil.convert", text="Convert to Bezier Curve").type = 'CURVE'
- layout.operator("gpencil.convert", text="Convert to Polygon Curve").type = 'POLY'
-
- layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
+ props.header_text = "Offset: %.3f"
layout.separator()
elif obj.type == 'EMPTY':
layout.operator_context = 'INVOKE_REGION_WIN'
- props = layout.operator("wm.context_modal_mouse", text="Empty Draw Size")
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Empty Display Size")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "empty_display_size"
props.input_scale = 0.01
- props.header_text = "Empty Draw Size: %.3f"
+ props.header_text = "Empty Display Size: %.3f"
layout.separator()
+ if obj.empty_display_type == 'IMAGE':
+ layout.operator("gpencil.trace_image")
+
+ layout.separator()
+
elif obj.type == 'LIGHT':
light = obj.data
layout.operator_context = 'INVOKE_REGION_WIN'
- props = layout.operator("wm.context_modal_mouse", text="Power")
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Light Power")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.energy"
props.input_scale = 1.0
props.header_text = "Light Power: %.3f"
if light.type == 'AREA':
- props = layout.operator("wm.context_modal_mouse", text="Size X")
- props.data_path_iter = "selected_editable_objects"
- props.data_path_item = "data.size"
- props.header_text = "Light Size X: %.3f"
-
if light.shape in {'RECTANGLE', 'ELLIPSE'}:
- props = layout.operator("wm.context_modal_mouse", text="Size Y")
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Area Light X Size")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.size"
+ props.header_text = "Light Size X: %.3f"
+
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Area Light Y Size")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.size_y"
props.header_text = "Light Size Y: %.3f"
+ else:
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Area Light Size")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.size"
+ props.header_text = "Light Size: %.3f"
elif light.type in {'SPOT', 'POINT'}:
- props = layout.operator("wm.context_modal_mouse", text="Radius")
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Light Radius")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.shadow_soft_size"
props.header_text = "Light Radius: %.3f"
elif light.type == 'SUN':
- props = layout.operator("wm.context_modal_mouse", text="Angle")
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Sun Light Angle")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.angle"
props.header_text = "Light Angle: %.3f"
@@ -2529,13 +2498,13 @@ class VIEW3D_MT_object_context_menu(Menu):
if light.type == 'SPOT':
layout.separator()
- props = layout.operator("wm.context_modal_mouse", text="Spot Size")
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Spot Light Size")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.spot_size"
props.input_scale = 0.01
props.header_text = "Spot Size: %.2f"
- props = layout.operator("wm.context_modal_mouse", text="Spot Blend")
+ props = layout.operator("wm.context_modal_mouse", text="Adjust Spot Light Blend")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.spot_blend"
props.input_scale = -0.01
@@ -2543,6 +2512,35 @@ class VIEW3D_MT_object_context_menu(Menu):
layout.separator()
+ # Shared among some object types.
+ if obj is not None:
+ if obj.type in {'MESH', 'CURVE', 'SURFACE'}:
+ layout.operator("object.shade_smooth", text="Shade Smooth")
+ layout.operator("object.shade_flat", text="Shade Flat")
+
+ layout.separator()
+
+ if obj.type in {'MESH', 'CURVE', 'SURFACE', 'ARMATURE', 'GPENCIL'}:
+ if selected_objects_len > 1:
+ layout.operator("object.join")
+
+ if obj.type in {'MESH', 'CURVE', 'SURFACE', 'POINTCLOUD', 'META', 'FONT'}:
+ layout.operator_menu_enum("object.convert", "target")
+
+ if obj.type == 'GPENCIL':
+ layout.operator_menu_enum("gpencil.convert", "type", text="Convert To")
+
+ if (
+ obj.type in {'MESH', 'CURVE', 'SURFACE', 'GPENCIL', 'LATTICE', 'ARMATURE', 'META'} or
+ (obj.type == 'EMPTY' and obj.instance_collection is not None)
+ ):
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
+ layout.operator_context = 'INVOKE_DEFAULT'
+
+ layout.separator()
+
+ # Shared among all object types
layout.operator("view3d.copybuffer", text="Copy Objects", icon='COPYDOWN')
layout.operator("view3d.pastebuffer", text="Paste Objects", icon='PASTEDOWN')
@@ -2787,8 +2785,25 @@ class VIEW3D_MT_make_single_user(Menu):
props.object = props.obdata = props.material = False
+class VIEW3D_MT_object_convert(Menu):
+ bl_label = "Convert"
+
+ def draw(self, context):
+ layout = self.layout
+ ob = context.active_object
+
+ if ob and ob.type == 'GPENCIL' and context.gpencil_data:
+ layout.operator_enum("gpencil.convert", "type")
+ else:
+ layout.operator_enum("object.convert", "target")
+
+ # Potrace lib dependency.
+ if bpy.app.build_options.potrace:
+ layout.operator("gpencil.trace_image", icon='OUTLINER_OB_GREASEPENCIL')
+
+
class VIEW3D_MT_make_links(Menu):
- bl_label = "Make Links"
+ bl_label = "Link/Transfer Data"
def draw(self, _context):
layout = self.layout
@@ -2796,10 +2811,10 @@ class VIEW3D_MT_make_links(Menu):
if len(bpy.data.scenes) > 10:
layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("object.make_links_scene", text="Objects to Scene...", icon='OUTLINER_OB_EMPTY')
+ layout.operator("object.make_links_scene", text="Link Objects to Scene...", icon='OUTLINER_OB_EMPTY')
else:
layout.operator_context = 'EXEC_REGION_WIN'
- layout.operator_menu_enum("object.make_links_scene", "scene", text="Objects to Scene")
+ layout.operator_menu_enum("object.make_links_scene", "scene", text="Link Objects to Scene")
layout.separator()
@@ -2807,7 +2822,12 @@ class VIEW3D_MT_make_links(Menu):
layout.operator_enum("object.make_links_data", "type") # inline
- layout.operator("object.join_uvs") # stupid place to add this!
+ layout.operator("object.join_uvs", text="Copy UV Maps")
+
+ layout.separator()
+
+ layout.operator("object.data_transfer")
+ layout.operator("object.datalayout_transfer")
class VIEW3D_MT_brush_paint_modes(Menu):
@@ -7529,6 +7549,7 @@ classes = (
VIEW3D_MT_object_rigid_body,
VIEW3D_MT_object_clear,
VIEW3D_MT_object_context_menu,
+ VIEW3D_MT_object_convert,
VIEW3D_MT_object_shading,
VIEW3D_MT_object_apply,
VIEW3D_MT_object_relations,
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 577f9678a62..7c718ee8155 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -352,10 +352,13 @@ class VIEW3D_PT_tools_particlemode(Panel, View3DPaintPanel):
layout.row().prop(brush, "puff_mode", expand=True)
layout.prop(brush, "use_puff_volume")
elif tool == 'COMB':
- layout.prop(settings, "use_emitter_deflect", text="Deflect Emitter")
- col = layout.column()
- col.active = settings.use_emitter_deflect
- col.prop(settings, "emitter_distance", text="Distance")
+ col = layout.column(align=False, heading="Deflect Emitter")
+ row = col.row(align=True)
+ sub = row.row(align=True)
+ sub.prop(settings, "use_emitter_deflect", text="")
+ sub = sub.row(align=True)
+ sub.active = settings.use_emitter_deflect
+ sub.prop(settings, "emitter_distance", text="")
# TODO, move to space_view3d.py
@@ -1231,14 +1234,20 @@ class VIEW3D_PT_tools_particlemode_options(View3DPanel, Panel):
col = layout.column(align=True)
col.active = pe.is_editable
- col.prop(ob.data, "use_mirror_x")
- if pe.tool == 'ADD':
- col.prop(ob.data, "use_mirror_topology")
- col.separator()
- col.prop(pe, "use_preserve_length", text="Preserve Strand Lengths")
- col.prop(pe, "use_preserve_root", text="Preserve Root Positions")
+
if not pe.is_hair:
col.prop(pe, "use_auto_velocity", text="Auto-Velocity")
+ col.separator()
+
+ sub = col.column(align=True, heading="Mirror")
+ sub.prop(ob.data, "use_mirror_x")
+ if pe.tool == 'ADD':
+ sub.prop(ob.data, "use_mirror_topology")
+ col.separator()
+
+ sub = col.column(align=True, heading="Preserve")
+ sub.prop(pe, "use_preserve_length", text="Strand Lengths")
+ sub.prop(pe, "use_preserve_root", text="Root Positions")
class VIEW3D_PT_tools_particlemode_options_shapecut(View3DPanel, Panel):
@@ -1282,10 +1291,13 @@ class VIEW3D_PT_tools_particlemode_options_display(View3DPanel, Panel):
else:
if pe.type == 'PARTICLES':
col.prop(pe, "show_particles", text="Particles")
- col.prop(pe, "use_fade_time")
- sub = col.row(align=True)
+ col = layout.column(align=False, heading="Fade Time")
+ row = col.row(align=True)
+ sub = row.row(align=True)
+ sub.prop(pe, "use_fade_time", text="")
+ sub = sub.row(align=True)
sub.active = pe.use_fade_time
- sub.prop(pe, "fade_frames", slider=True)
+ sub.prop(pe, "fade_frames", slider=True, text="")
# ********** grease pencil object tool panels ****************
@@ -1435,7 +1447,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel):
row.prop(gp_settings, "fill_layer_mode", text="Layers")
col.separator()
- col.prop(gp_settings, "fill_factor", text="Resolution")
+ col.prop(gp_settings, "fill_factor")
if gp_settings.fill_draw_mode != 'STROKE':
col = layout.column(align=False, heading="Ignore Transparent")
col.use_property_decorate = False
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 7abc62a69e3..56f0b5c0ba4 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -489,6 +489,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeMix"),
NodeItem("GeometryNodeAttributeColorRamp"),
NodeItem("GeometryNodeAttributeVectorMath"),
+ NodeItem("GeometryNodeAttributeSampleTexture"),
]),
GeometryNodeCategory("GEO_COLOR", "Color", items=[
NodeItem("ShaderNodeValToRGB"),
@@ -520,6 +521,9 @@ geometry_node_categories = [
NodeItem("GeometryNodeRotatePoints"),
NodeItem("GeometryNodeAlignRotationToVector"),
]),
+ GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
+ NodeItem("GeometryNodePointsToVolume"),
+ ]),
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
NodeItem("ShaderNodeMapRange"),
NodeItem("ShaderNodeClamp"),
diff --git a/release/windows/batch/blender_debug_gpu.cmd b/release/windows/batch/blender_debug_gpu.cmd
index 46d126ab621..53d7863ec70 100644
--- a/release/windows/batch/blender_debug_gpu.cmd
+++ b/release/windows/batch/blender_debug_gpu.cmd
@@ -12,5 +12,5 @@ mkdir "%temp%\blender\debug_logs" > NUL 2>&1
echo.
echo Starting blender and waiting for it to exit....
set PYTHONPATH=
-"%~dp0\blender" --debug --debug-gpu --python-expr "import bpy; bpy.ops.wm.sysinfo(filepath=r'%temp%\blender\debug_logs\blender_system_info.txt')" > "%temp%\blender\debug_logs\blender_debug_output.txt" 2>&1 < %0
+"%~dp0\blender" --debug --debug-gpu --debug-cycles --python-expr "import bpy; bpy.ops.wm.sysinfo(filepath=r'%temp%\blender\debug_logs\blender_system_info.txt')" > "%temp%\blender\debug_logs\blender_debug_output.txt" 2>&1 < %0
explorer "%temp%\blender\debug_logs" \ No newline at end of file
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 8d904bd6019..2fce4bfc5b8 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -212,8 +212,7 @@ struct NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
struct ListBase *cache,
struct PointerRNA *ptr,
struct AnimData *adt,
- const struct AnimationEvalContext *anim_eval_context,
- const bool flush_to_original);
+ const struct AnimationEvalContext *anim_eval_context);
bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
struct PointerRNA *prop_ptr,
struct PropertyRNA *prop,
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index abcf8ed1c54..bca96aac665 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -24,6 +24,7 @@
#include "BKE_attribute.h"
#include "BLI_color.hh"
+#include "BLI_float2.hh"
#include "BLI_float3.hh"
namespace blender::bke {
@@ -301,11 +302,13 @@ template<typename T> class TypedWriteAttribute {
using BooleanReadAttribute = TypedReadAttribute<bool>;
using FloatReadAttribute = TypedReadAttribute<float>;
+using Float2ReadAttribute = TypedReadAttribute<float2>;
using Float3ReadAttribute = TypedReadAttribute<float3>;
using Int32ReadAttribute = TypedReadAttribute<int>;
using Color4fReadAttribute = TypedReadAttribute<Color4f>;
using BooleanWriteAttribute = TypedWriteAttribute<bool>;
using FloatWriteAttribute = TypedWriteAttribute<float>;
+using Float2WriteAttribute = TypedWriteAttribute<float2>;
using Float3WriteAttribute = TypedWriteAttribute<float3>;
using Int32WriteAttribute = TypedWriteAttribute<int>;
using Color4fWriteAttribute = TypedWriteAttribute<Color4f>;
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh
new file mode 100644
index 00000000000..b8bb2048d9d
--- /dev/null
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -0,0 +1,94 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_color.hh"
+#include "BLI_float2.hh"
+#include "BLI_float3.hh"
+#include "DNA_customdata_types.h"
+
+namespace blender::attribute_math {
+
+/**
+ * Utility function that simplifies calling a templated function based on a custom data type.
+ */
+template<typename Func>
+void convert_to_static_type(const CustomDataType data_type, const Func &func)
+{
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ func(float());
+ break;
+ case CD_PROP_FLOAT2:
+ func(float2());
+ break;
+ case CD_PROP_FLOAT3:
+ func(float3());
+ break;
+ case CD_PROP_INT32:
+ func(int());
+ break;
+ case CD_PROP_BOOL:
+ func(bool());
+ break;
+ case CD_PROP_COLOR:
+ func(Color4f());
+ break;
+ default:
+ BLI_assert(false);
+ break;
+ }
+}
+
+/* Interpolate between three values. */
+template<typename T> T mix3(const float3 &weights, const T &v0, const T &v1, const T &v2);
+
+template<> inline bool mix3(const float3 &weights, const bool &v0, const bool &v1, const bool &v2)
+{
+ return (weights.x * v0 + weights.y * v1 + weights.z * v2) >= 0.5f;
+}
+
+template<> inline int mix3(const float3 &weights, const int &v0, const int &v1, const int &v2)
+{
+ return static_cast<int>(weights.x * v0 + weights.y * v1 + weights.z * v2);
+}
+
+template<>
+inline float mix3(const float3 &weights, const float &v0, const float &v1, const float &v2)
+{
+ return weights.x * v0 + weights.y * v1 + weights.z * v2;
+}
+
+template<>
+inline float2 mix3(const float3 &weights, const float2 &v0, const float2 &v1, const float2 &v2)
+{
+ return weights.x * v0 + weights.y * v1 + weights.z * v2;
+}
+
+template<>
+inline float3 mix3(const float3 &weights, const float3 &v0, const float3 &v1, const float3 &v2)
+{
+ return weights.x * v0 + weights.y * v1 + weights.z * v2;
+}
+
+template<>
+inline Color4f mix3(const float3 &weights, const Color4f &v0, const Color4f &v1, const Color4f &v2)
+{
+ Color4f result;
+ interp_v4_v4v4v4(result, v0, v1, v2, weights);
+ return result;
+}
+
+} // namespace blender::attribute_math
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 4ee96d1ab8d..6b76e69a7a6 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -31,15 +31,15 @@ extern "C" {
*/
/* Blender major and minor version. */
-#define BLENDER_VERSION 292
+#define BLENDER_VERSION 293
/* Blender patch version for bugfix releases. */
#define BLENDER_VERSION_PATCH 0
/** Blender release cycle stage: alpha/beta/rc/release. */
-#define BLENDER_VERSION_CYCLE beta
+#define BLENDER_VERSION_CYCLE alpha
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 14
+#define BLENDER_FILE_SUBVERSION 5
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 31739465afd..2bed1a36ed7 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -37,6 +37,7 @@ struct Collection;
struct Mesh;
struct Object;
struct PointCloud;
+struct Volume;
/* Each geometry component has a specific type. The type determines what kind of data the component
* stores. Functions modifying a geometry will usually just modify a subset of the component types.
@@ -45,6 +46,7 @@ enum class GeometryComponentType {
Mesh = 0,
PointCloud = 1,
Instances = 2,
+ Volume = 3,
};
enum class GeometryOwnershipType {
@@ -320,10 +322,13 @@ struct GeometrySet {
bool has_mesh() const;
bool has_pointcloud() const;
bool has_instances() const;
+ bool has_volume() const;
const Mesh *get_mesh_for_read() const;
const PointCloud *get_pointcloud_for_read() const;
+ const Volume *get_volume_for_read() const;
Mesh *get_mesh_for_write();
PointCloud *get_pointcloud_for_write();
+ Volume *get_volume_for_write();
/* Utility methods for replacement. */
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
@@ -449,3 +454,25 @@ class InstancesComponent : public GeometryComponent {
static constexpr inline GeometryComponentType static_type = GeometryComponentType::Instances;
};
+
+/** A geometry component that stores volume grids. */
+class VolumeComponent : public GeometryComponent {
+ private:
+ Volume *volume_ = nullptr;
+ GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned;
+
+ public:
+ VolumeComponent();
+ ~VolumeComponent();
+ GeometryComponent *copy() const override;
+
+ void clear();
+ bool has_volume() const;
+ void replace(Volume *volume, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ Volume *release();
+
+ const Volume *get_for_read() const;
+ Volume *get_for_write();
+
+ static constexpr inline GeometryComponentType static_type = GeometryComponentType::Volume;
+};
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 5e16c9c979c..aed97d4708f 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -147,21 +147,18 @@ enum {
G_DEBUG_DEPSGRAPH = (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_EVAL | G_DEBUG_DEPSGRAPH_TAG |
G_DEBUG_DEPSGRAPH_TIME | G_DEBUG_DEPSGRAPH_UUID),
G_DEBUG_SIMDATA = (1 << 15), /* sim debug data display */
- G_DEBUG_GPU_MEM = (1 << 16), /* gpu memory in status bar */
- G_DEBUG_GPU = (1 << 17), /* gpu debug */
- G_DEBUG_IO = (1 << 18), /* IO Debugging (for Collada, ...)*/
- G_DEBUG_GPU_SHADERS = (1 << 19), /* GLSL shaders */
- G_DEBUG_GPU_FORCE_WORKAROUNDS = (1 << 20), /* force gpu workarounds bypassing detections. */
- G_DEBUG_XR = (1 << 21), /* XR/OpenXR messages */
- G_DEBUG_XR_TIME = (1 << 22), /* XR/OpenXR timing messages */
-
- G_DEBUG_GHOST = (1 << 23), /* Debug GHOST module. */
+ G_DEBUG_GPU = (1 << 16), /* gpu debug */
+ G_DEBUG_IO = (1 << 17), /* IO Debugging (for Collada, ...)*/
+ G_DEBUG_GPU_FORCE_WORKAROUNDS = (1 << 18), /* force gpu workarounds bypassing detections. */
+ G_DEBUG_XR = (1 << 19), /* XR/OpenXR messages */
+ G_DEBUG_XR_TIME = (1 << 20), /* XR/OpenXR timing messages */
+
+ G_DEBUG_GHOST = (1 << 21), /* Debug GHOST module. */
};
#define G_DEBUG_ALL \
(G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS | \
- G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH | G_DEBUG_GPU_MEM | G_DEBUG_IO | G_DEBUG_GPU_SHADERS | \
- G_DEBUG_GHOST)
+ G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH | G_DEBUG_IO | G_DEBUG_GHOST)
/** #Global.fileflags */
enum {
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index df5711f5120..b7fad9c891a 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -109,8 +109,11 @@ struct bGPDframe *BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
struct bGPDlayer *BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[]);
-struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
-struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
+struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src,
+ const bool dup_strokes);
+struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src,
+ const bool dup_frames,
+ const bool dup_strokes);
void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
struct bGPDcurve *BKE_gpencil_stroke_curve_duplicate(struct bGPDcurve *gpc_src);
struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src,
@@ -280,12 +283,12 @@ void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig
const struct bGPDframe *gpf_eval);
void BKE_gpencil_update_orig_pointers(const struct Object *ob_orig, const struct Object *ob_eval);
-void BKE_gpencil_parent_matrix_get(const struct Depsgraph *depsgraph,
- struct Object *obact,
- struct bGPDlayer *gpl,
- float diff_mat[4][4]);
+void BKE_gpencil_layer_transform_matrix_get(const struct Depsgraph *depsgraph,
+ struct Object *obact,
+ struct bGPDlayer *gpl,
+ float diff_mat[4][4]);
-void BKE_gpencil_update_layer_parent(const struct Depsgraph *depsgraph, struct Object *ob);
+void BKE_gpencil_update_layer_transforms(const struct Depsgraph *depsgraph, struct Object *ob);
int BKE_gpencil_material_find_index_by_name_prefix(struct Object *ob, const char *name_prefix);
diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index 1298e3c2bbf..edfc96f3059 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -106,6 +106,8 @@ typedef void (*IDTypeBlendReadUndoPreserve)(struct BlendLibReader *reader,
struct ID *id_new,
struct ID *id_old);
+typedef void (*IDTypeLibOverrideApplyPost)(struct ID *id_dst, struct ID *id_src);
+
typedef struct IDTypeInfo {
/* ********** General IDType data. ********** */
@@ -207,6 +209,13 @@ typedef struct IDTypeInfo {
* \note Called from #setup_app_data when undoing or redoing a memfile step.
*/
IDTypeBlendReadUndoPreserve blend_read_undo_preserve;
+
+ /**
+ * Called after library override operations have been applied.
+ *
+ * \note Currently needed for some update operation on point caches.
+ */
+ IDTypeLibOverrideApplyPost lib_override_apply_post;
} IDTypeInfo;
/* ********** Declaration of each IDTypeInfo. ********** */
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index c9a9c26e222..5fd451dc986 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -65,15 +65,6 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
struct ID *reference_id,
const bool do_tagged_remap);
bool BKE_lib_override_library_create_from_tag(struct Main *bmain);
-void BKE_lib_override_library_dependencies_tag(struct Main *bmain,
- struct ID *id_root,
- const uint tag,
- const bool do_create_main_relashionships);
-void BKE_lib_override_library_override_group_tag(struct Main *bmain,
- struct ID *id_root,
- const uint tag,
- const uint missing_tag,
- const bool do_create_main_relashionships);
bool BKE_lib_override_library_create(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 8106607572b..0768423fc5f 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -60,22 +60,52 @@ typedef struct BlendThumbnail {
} BlendThumbnail;
/* Structs caching relations between data-blocks in a given Main. */
+typedef struct MainIDRelationsEntryItem {
+ struct MainIDRelationsEntryItem *next;
+
+ union {
+ /* For `from_ids` list, a user of the hashed ID. */
+ struct ID *from;
+ /* For `to_ids` list, an ID used by the hashed ID. */
+ struct ID **to;
+ } id_pointer;
+ /* Session uuid of the `id_pointer`. */
+ uint session_uuid;
+
+ int usage_flag; /* Using IDWALK_ enums, defined in BKE_lib_query.h */
+} MainIDRelationsEntryItem;
+
typedef struct MainIDRelationsEntry {
- struct MainIDRelationsEntry *next;
- /* WARNING! for user_to_used,
- * that pointer is really an ID** one, but for used_to_user, it’s only an ID* one! */
- struct ID **id_pointer;
- int usage_flag; /* Using IDWALK_ enums, in BKE_lib_query.h */
+ /* Linked list of IDs using that ID. */
+ struct MainIDRelationsEntryItem *from_ids;
+ /* Linked list of IDs used by that ID. */
+ struct MainIDRelationsEntryItem *to_ids;
+
+ /* Session uuid of the ID matching that entry. */
+ uint session_uuid;
+
+ /* Runtime tags, users should ensure those are reset after usage. */
+ uint tags;
} MainIDRelationsEntry;
+/* MainIDRelationsEntry.tags */
+typedef enum MainIDRelationsEntryTags {
+ /* Generic tag marking the entry as to be processed. */
+ MAINIDRELATIONS_ENTRY_TAGS_DOIT = 1 << 0,
+ /* Generic tag marking the entry as processed. */
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = 1 << 1,
+} MainIDRelationsEntryTags;
+
typedef struct MainIDRelations {
- struct GHash *id_user_to_used;
- struct GHash *id_used_to_user;
+ /* Mapping from an ID pointer to all of its parents (IDs using it) and children (IDs it uses).
+ * Values are `MainIDRelationsEntry` pointers. */
+ struct GHash *relations_from_pointers;
+ /* Note: we could add more mappings when needed (e.g. from session uuid?). */
short flag;
/* Private... */
- struct BLI_mempool *entry_pool;
+ struct BLI_mempool *entry_items_pool;
} MainIDRelations;
enum {
@@ -172,7 +202,6 @@ void BKE_main_unlock(struct Main *bmain);
void BKE_main_relations_create(struct Main *bmain, const short flag);
void BKE_main_relations_free(struct Main *bmain);
-void BKE_main_relations_ID_remove(struct Main *bmain, struct ID *id);
struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 79bc00766fd..4912d634471 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -463,8 +463,8 @@ void ntreeSetOutput(struct bNodeTree *ntree);
void ntreeFreeCache(struct bNodeTree *ntree);
-bool ntreeNodeExists(struct bNodeTree *ntree, struct bNode *testnode);
-bool ntreeOutputExists(struct bNode *node, struct bNodeSocket *testsock);
+bool ntreeNodeExists(const struct bNodeTree *ntree, const struct bNode *testnode);
+bool ntreeOutputExists(const struct bNode *node, const struct bNodeSocket *testsock);
void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable);
struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree);
void ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree);
@@ -501,7 +501,7 @@ struct bNodeSocket *ntreeInsertSocketInterfaceFromSocket(struct bNodeTree *ntree
struct bNodeSocket *from_sock);
void ntreeRemoveSocketInterface(struct bNodeTree *ntree, struct bNodeSocket *sock);
-struct StructRNA *ntreeInterfaceTypeGet(struct bNodeTree *ntree, int create);
+struct StructRNA *ntreeInterfaceTypeGet(struct bNodeTree *ntree, bool create);
void ntreeInterfaceTypeFree(struct bNodeTree *ntree);
void ntreeInterfaceTypeUpdate(struct bNodeTree *ntree);
@@ -624,12 +624,12 @@ struct bNodeLink *nodeAddLink(struct bNodeTree *ntree,
struct bNodeSocket *tosock);
void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link);
void nodeRemSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock);
-bool nodeLinkIsHidden(struct bNodeLink *link);
+bool nodeLinkIsHidden(const struct bNodeLink *link);
void nodeInternalRelink(struct bNodeTree *ntree, struct bNode *node);
-void nodeToView(struct bNode *node, float x, float y, float *rx, float *ry);
-void nodeFromView(struct bNode *node, float x, float y, float *rx, float *ry);
-bool nodeAttachNodeCheck(struct bNode *node, struct bNode *parent);
+void nodeToView(const struct bNode *node, float x, float y, float *rx, float *ry);
+void nodeFromView(const struct bNode *node, float x, float y, float *rx, float *ry);
+bool nodeAttachNodeCheck(const struct bNode *node, const struct bNode *parent);
void nodeAttachNode(struct bNode *node, struct bNode *parent);
void nodeDetachNode(struct bNode *node);
@@ -661,9 +661,9 @@ void nodeChainIterBackwards(const bNodeTree *ntree,
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
- struct bNodeSocket *from,
- struct bNodeSocket *to);
-int nodeCountSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock);
+ const struct bNodeSocket *from,
+ const struct bNodeSocket *to);
+int nodeCountSocketLinks(const struct bNodeTree *ntree, const struct bNodeSocket *sock);
void nodeSetSelected(struct bNode *node, bool select);
void nodeSetActive(struct bNodeTree *ntree, struct bNode *node);
@@ -678,14 +678,14 @@ void nodeUpdate(struct bNodeTree *ntree, struct bNode *node);
bool nodeUpdateID(struct bNodeTree *ntree, struct ID *id);
void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
-int nodeSocketIsHidden(struct bNodeSocket *sock);
+int nodeSocketIsHidden(const struct bNodeSocket *sock);
void ntreeTagUsedSockets(struct bNodeTree *ntree);
void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available);
-int nodeSocketLinkLimit(struct bNodeSocket *sock);
+int nodeSocketLinkLimit(const struct bNodeSocket *sock);
/* Node Clipboard */
-void BKE_node_clipboard_init(struct bNodeTree *ntree);
+void BKE_node_clipboard_init(const struct bNodeTree *ntree);
void BKE_node_clipboard_clear(void);
void BKE_node_clipboard_free(void);
bool BKE_node_clipboard_validate(void);
@@ -706,8 +706,8 @@ extern const bNodeInstanceKey NODE_INSTANCE_KEY_BASE;
extern const bNodeInstanceKey NODE_INSTANCE_KEY_NONE;
bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key,
- struct bNodeTree *ntree,
- struct bNode *node);
+ const struct bNodeTree *ntree,
+ const struct bNode *node);
bNodeInstanceHash *BKE_node_instance_hash_new(const char *info);
void BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp);
@@ -767,7 +767,7 @@ BLI_INLINE bool BKE_node_instance_hash_iterator_done(bNodeInstanceHashIterator *
/* Node Previews */
-int BKE_node_preview_used(struct bNode *node);
+bool BKE_node_preview_used(const struct bNode *node);
bNodePreview *BKE_node_preview_verify(
struct bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create);
bNodePreview *BKE_node_preview_copy(struct bNodePreview *preview);
@@ -1361,6 +1361,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_ALIGN_ROTATION_TO_VECTOR 1018
#define GEO_NODE_POINT_TRANSLATE 1019
#define GEO_NODE_POINT_SCALE 1020
+#define GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE 1021
+#define GEO_NODE_POINTS_TO_VOLUME 1022
/** \} */
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 7b5df98d148..2fc0caf1a2c 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -67,6 +67,13 @@ struct wmWindowManager;
#define BKE_ST_MAXNAME 64
+typedef struct wmSpaceTypeListenerParams {
+ struct wmWindow *window;
+ struct ScrArea *area;
+ struct wmNotifier *notifier;
+ const struct Scene *scene;
+} wmSpaceTypeListenerParams;
+
typedef struct SpaceType {
struct SpaceType *next, *prev;
@@ -85,10 +92,7 @@ typedef struct SpaceType {
/* exit is called when the area is hidden or removed */
void (*exit)(struct wmWindowManager *wm, struct ScrArea *area);
/* Listeners can react to bContext changes */
- void (*listener)(struct wmWindow *win,
- struct ScrArea *area,
- struct wmNotifier *wmn,
- struct Scene *scene);
+ void (*listener)(const wmSpaceTypeListenerParams *params);
/* called when the mouse moves out of the area */
void (*deactivate)(struct ScrArea *area);
@@ -134,6 +138,24 @@ typedef struct SpaceType {
/* region types are also defined using spacetypes_init, via a callback */
+typedef struct wmRegionListenerParams {
+ struct wmWindow *window;
+ struct ScrArea *area; /* Can be NULL when the region is not part of an area. */
+ struct ARegion *region;
+ struct wmNotifier *notifier;
+ const struct Scene *scene;
+} wmRegionListenerParams;
+
+typedef struct wmRegionMessageSubscribeParams {
+ const struct bContext *context;
+ struct wmMsgBus *message_bus;
+ struct WorkSpace *workspace;
+ struct Scene *scene;
+ struct bScreen *screen;
+ struct ScrArea *area;
+ struct ARegion *region;
+} wmRegionMessageSubscribeParams;
+
typedef struct ARegionType {
struct ARegionType *next, *prev;
@@ -158,19 +180,9 @@ typedef struct ARegionType {
/* snap the size of the region (can be NULL for no snapping). */
int (*snap_size)(const struct ARegion *region, int size, int axis);
/* contextual changes should be handled here */
- void (*listener)(struct wmWindow *win,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmNotifier *wmn,
- const struct Scene *scene);
+ void (*listener)(const wmRegionListenerParams *params);
/* Optional callback to generate subscriptions. */
- void (*message_subscribe)(const struct bContext *C,
- struct WorkSpace *workspace,
- struct Scene *scene,
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus);
+ void (*message_subscribe)(const wmRegionMessageSubscribeParams *params);
void (*free)(struct ARegion *);
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 4dbc22ae18f..c2544c06514 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -89,6 +89,23 @@ struct MovieTrackingTrack *BKE_tracking_track_duplicate(struct MovieTrackingTrac
void BKE_tracking_track_unique_name(struct ListBase *tracksbase, struct MovieTrackingTrack *track);
void BKE_tracking_track_free(struct MovieTrackingTrack *track);
+void BKE_tracking_track_first_last_frame_get(const struct MovieTrackingTrack *track,
+ int *r_first_frame,
+ int *r_last_frame);
+
+void BKE_tracking_tracks_first_last_frame_minmax(/*const*/ struct MovieTrackingTrack **tracks,
+ const int num_tracks,
+ int *r_first_frame,
+ int *r_last_frame);
+
+int BKE_tracking_count_selected_tracks_in_list(const struct ListBase *tracks_list);
+int BKE_tracking_count_selected_tracks_in_active_object(/*const*/ struct MovieTracking *tracking);
+
+/* Get array of selected tracks from the current active object in the tracking structure.
+ * If nothing is selected then the result is nullptr and `r_num_tracks` is set to 0. */
+struct MovieTrackingTrack **BKE_tracking_selected_tracks_in_active_object(
+ struct MovieTracking *tracking, int *r_num_tracks);
+
void BKE_tracking_track_flag_set(struct MovieTrackingTrack *track, int area, int flag);
void BKE_tracking_track_flag_clear(struct MovieTrackingTrack *track, int area, int flag);
@@ -96,10 +113,15 @@ bool BKE_tracking_track_has_marker_at_frame(struct MovieTrackingTrack *track, in
bool BKE_tracking_track_has_enabled_marker_at_frame(struct MovieTrackingTrack *track, int framenr);
void BKE_tracking_track_path_clear(struct MovieTrackingTrack *track, int ref_frame, int action);
+
void BKE_tracking_tracks_join(struct MovieTracking *tracking,
struct MovieTrackingTrack *dst_track,
struct MovieTrackingTrack *src_track);
+void BKE_tracking_tracks_average(struct MovieTrackingTrack *dst_track,
+ /*const*/ struct MovieTrackingTrack **src_tracks,
+ const int num_src_tracks);
+
struct MovieTrackingTrack *BKE_tracking_track_get_named(struct MovieTracking *tracking,
struct MovieTrackingObject *object,
const char *name);
@@ -139,6 +161,17 @@ struct MovieTrackingMarker *BKE_tracking_marker_get_exact(struct MovieTrackingTr
struct MovieTrackingMarker *BKE_tracking_marker_ensure(struct MovieTrackingTrack *track,
int framenr);
+/* Get marker position, possibly interpolating interpolating gap between keyframed/tracked markers.
+ *
+ * The result marker frame number is set to the requested frame number. Its flags are 0 if the
+ * marker is interpolated, and is set to original marker flag if there were no interpolation
+ * involved.
+ *
+ * Returns truth if the result is usable. */
+bool BKE_tracking_marker_get_interpolated(struct MovieTrackingTrack *track,
+ const int framenr,
+ struct MovieTrackingMarker *r_marker);
+
void BKE_tracking_marker_pattern_minmax(const struct MovieTrackingMarker *marker,
float min[2],
float max[2]);
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h
index 12c37ec56e0..53626dbeb1b 100644
--- a/source/blender/blenkernel/BKE_volume.h
+++ b/source/blender/blenkernel/BKE_volume.h
@@ -170,7 +170,7 @@ openvdb::GridBase::Ptr BKE_volume_grid_openvdb_for_write(const struct Volume *vo
struct VolumeGrid *grid,
const bool clear);
-VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase::Ptr &grid);
+VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase &grid);
template<typename OpType>
auto BKE_volume_grid_type_operation(const VolumeGridType grid_type, OpType &&op)
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 9aa2baef53c..20c57f4e15a 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -275,6 +275,7 @@ set(SRC
BKE_asset.h
BKE_attribute.h
BKE_attribute_access.hh
+ BKE_attribute_math.hh
BKE_autoexec.h
BKE_blender.h
BKE_blender_copybuffer.h
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index ccb077d6b82..db8fe75b6d1 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -298,6 +298,8 @@ IDTypeInfo IDType_ID_AC = {
.blend_read_expand = action_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/* ***************** Library data level operations on action ************** */
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 20956d6eb18..da874539232 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -362,6 +362,20 @@ void BKE_keyingsets_blend_read_expand(BlendExpander *expander, ListBase *list)
/* ***************************************** */
/* Evaluation Data-Setting Backend */
+static bool is_fcurve_evaluatable(FCurve *fcu)
+{
+ if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) {
+ return false;
+ }
+ if (fcu->grp != NULL && (fcu->grp->flag & AGRP_MUTED)) {
+ return false;
+ }
+ if (BKE_fcurve_is_empty(fcu)) {
+ return false;
+ }
+ return true;
+}
+
bool BKE_animsys_store_rna_setting(PointerRNA *ptr,
/* typically 'fcu->rna_path', 'fcu->array_index' */
const char *rna_path,
@@ -594,18 +608,11 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr,
{
/* Calculate then execute each curve. */
LISTBASE_FOREACH (FCurve *, fcu, list) {
- /* Check if this F-Curve doesn't belong to a muted group. */
- if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) {
- continue;
- }
- /* Check if this curve should be skipped. */
- if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) {
- continue;
- }
- /* Skip empty curves, as if muted. */
- if (BKE_fcurve_is_empty(fcu)) {
+
+ if (!is_fcurve_evaluatable(fcu)) {
continue;
}
+
PathResolvedRNA anim_rna;
if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, anim_eval_context);
@@ -979,6 +986,19 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list,
return nes;
}
+static NlaEvalStrip *nlastrips_ctime_get_strip_single(
+ ListBase *dst_list,
+ NlaStrip *single_strip,
+ const AnimationEvalContext *anim_eval_context,
+ const bool flush_to_original)
+{
+ ListBase single_tracks_list;
+ single_tracks_list.first = single_tracks_list.last = single_strip;
+
+ return nlastrips_ctime_get_strip(
+ dst_list, &single_tracks_list, -1, anim_eval_context, flush_to_original);
+}
+
/* ---------------------- */
/* Initialize a valid mask, allocating memory if necessary. */
@@ -1152,7 +1172,7 @@ static void nlaeval_snapshot_free_data(NlaEvalSnapshot *snapshot)
/* Free memory owned by this evaluation channel. */
static void nlaevalchan_free_data(NlaEvalChannel *nec)
{
- nlavalidmask_free(&nec->valid);
+ nlavalidmask_free(&nec->domain);
if (nec->blend_snapshot != NULL) {
nlaevalchan_snapshot_free(nec->blend_snapshot);
@@ -1353,7 +1373,7 @@ static NlaEvalChannel *nlaevalchan_verify_key(NlaEvalData *nlaeval,
nec->mix_mode = nlaevalchan_detect_mix_mode(key, length);
- nlavalidmask_init(&nec->valid, length);
+ nlavalidmask_init(&nec->domain, length);
nec->base_snapshot.channel = nec;
nec->base_snapshot.length = length;
@@ -1682,14 +1702,6 @@ static bool nlaeval_blend_value(NlaBlendData *blend,
return false;
}
- if (nec->mix_mode == NEC_MIX_QUATERNION) {
- /* For quaternion properties, always output all sub-channels. */
- BLI_bitmap_set_all(nec->valid.ptr, true, 4);
- }
- else {
- BLI_BITMAP_ENABLE(nec->valid.ptr, array_index);
- }
-
NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec);
float *p_value = &nec_snapshot->values[array_index];
@@ -1889,16 +1901,8 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr,
/* Evaluate all the F-Curves in the action,
* saving the relevant pointers to data that will need to be used. */
for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) {
- float value = 0.0f;
- /* check if this curve should be skipped */
- if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) {
- continue;
- }
- if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) {
- continue;
- }
- if (BKE_fcurve_is_empty(fcu)) {
+ if (!is_fcurve_evaluatable(fcu)) {
continue;
}
@@ -1906,7 +1910,7 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr,
* NOTE: we use the modified time here, since strip's F-Curve Modifiers
* are applied on top of this.
*/
- value = evaluate_fcurve(fcu, evaltime);
+ float value = evaluate_fcurve(fcu, evaltime);
/* apply strip's F-Curve Modifiers on this value
* NOTE: we apply the strip's original evaluation time not the modified one
@@ -2099,12 +2103,21 @@ void nladata_flush_channels(PointerRNA *ptr,
/* for each channel with accumulated values, write its value on the property it affects */
LISTBASE_FOREACH (NlaEvalChannel *, nec, &channels->channels) {
+ /**
+ * The bitmask is set for all channels touched by NLA due to the domain() function.
+ * Channels touched by current set of evaluated strips will have a snapshot channel directly
+ * from the evaluation snapshot.
+ *
+ * This function falls back to the default value if the snapshot channel doesn't exist.
+ * Thus channels, touched by NLA but not by the current set of evaluated strips, will be
+ * reset to default. If channel not touched by NLA then it's value is unchanged.
+ */
NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(snapshot, nec);
PathResolvedRNA rna = {nec->key.ptr, nec->key.prop, -1};
for (int i = 0; i < nec_snapshot->length; i++) {
- if (BLI_BITMAP_TEST(nec->valid.ptr, i)) {
+ if (BLI_BITMAP_TEST(nec->domain.ptr, i)) {
float value = nec_snapshot->values[i];
if (nec->is_array) {
rna.prop_index = i;
@@ -2131,13 +2144,7 @@ static void nla_eval_domain_action(PointerRNA *ptr,
LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
/* check if this curve should be skipped */
- if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) {
- continue;
- }
- if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) {
- continue;
- }
- if (BKE_fcurve_is_empty(fcu)) {
+ if (!is_fcurve_evaluatable(fcu)) {
continue;
}
@@ -2146,14 +2153,14 @@ static void nla_eval_domain_action(PointerRNA *ptr,
if (nec != NULL) {
/* For quaternion properties, enable all sub-channels. */
if (nec->mix_mode == NEC_MIX_QUATERNION) {
- BLI_bitmap_set_all(nec->valid.ptr, true, 4);
+ BLI_bitmap_set_all(nec->domain.ptr, true, 4);
continue;
}
int idx = nlaevalchan_validate_index(nec, fcu->array_index);
if (idx >= 0) {
- BLI_BITMAP_ENABLE(nec->valid.ptr, idx);
+ BLI_BITMAP_ENABLE(nec->domain.ptr, idx);
}
}
}
@@ -2212,190 +2219,345 @@ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels,
/* ---------------------- */
+/** Tweaked strip is evaluated differently from other strips. Adjacent strips are ignored
+ * and includes a workaround for when user is not editing in place. */
+static void animsys_create_tweak_strip(const AnimData *adt,
+ const bool keyframing_to_strip,
+ NlaStrip *r_tweak_strip)
+
+{
+ /* Copy active strip so we can modify how it evaluates without affecting user data. */
+ memcpy(r_tweak_strip, adt->actstrip, sizeof(NlaStrip));
+ r_tweak_strip->next = r_tweak_strip->prev = NULL;
+
+ /* If tweaked strip is syncing action length, then evaluate using action length. */
+ if (r_tweak_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH) {
+ BKE_nlastrip_recalculate_bounds_sync_action(r_tweak_strip);
+ }
+
+ /* Strips with a user-defined time curve don't get properly remapped for editing
+ * at the moment, so mapping them just for display may be confusing. */
+ const bool is_inplace_tweak = !(adt->flag & ADT_NLA_EDIT_NOMAP) &&
+ !(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME);
+
+ if (!is_inplace_tweak) {
+ /* Use Hold due to no proper remapping yet (the note above). */
+ r_tweak_strip->extendmode = NLASTRIP_EXTEND_HOLD;
+
+ /* Disable range. */
+ r_tweak_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
+ }
+
+ /** Controls whether able to keyframe outside range of tweaked strip. */
+ if (keyframing_to_strip) {
+ r_tweak_strip->extendmode = (is_inplace_tweak &&
+ !(r_tweak_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) ?
+ NLASTRIP_EXTEND_NOTHING :
+ NLASTRIP_EXTEND_HOLD;
+ }
+}
+
+/** Action track and strip are associated with the non-pushed action. */
+static void animsys_create_action_track_strip(const AnimData *adt,
+ const bool keyframing_to_strip,
+ NlaStrip *r_action_strip)
+{
+ memset(r_action_strip, 0, sizeof(NlaStrip));
+
+ bAction *action = adt->action;
+
+ if ((adt->flag & ADT_NLA_EDIT_ON)) {
+ action = adt->tmpact;
+ }
+
+ /* Set settings of dummy NLA strip from AnimData settings. */
+ r_action_strip->act = action;
+
+ /* Action range is calculated taking F-Modifiers into account
+ * (which making new strips doesn't do due to the troublesome nature of that). */
+ calc_action_range(r_action_strip->act, &r_action_strip->actstart, &r_action_strip->actend, 1);
+ r_action_strip->start = r_action_strip->actstart;
+ r_action_strip->end = (IS_EQF(r_action_strip->actstart, r_action_strip->actend)) ?
+ (r_action_strip->actstart + 1.0f) :
+ (r_action_strip->actend);
+
+ r_action_strip->blendmode = adt->act_blendmode;
+ r_action_strip->extendmode = adt->act_extendmode;
+ r_action_strip->influence = adt->act_influence;
+
+ /* NOTE: must set this, or else the default setting overrides,
+ * and this setting doesn't work. */
+ r_action_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
+
+ /* Unless extendmode is Nothing (might be useful for flattening NLA evaluation), disable range.
+ * Extendmode Nothing and Hold will behave as normal. Hold Forward will behave just like Hold.
+ */
+ if (r_action_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ r_action_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
+ }
+
+ const bool tweaking = (adt->flag & ADT_NLA_EDIT_ON) != 0;
+ const bool soloing = (adt->flag & ADT_NLA_SOLO_TRACK) != 0;
+ const bool actionstrip_evaluated = r_action_strip->act && !soloing && !tweaking;
+ if (!actionstrip_evaluated) {
+ r_action_strip->flag |= NLASTRIP_FLAG_MUTED;
+ }
+
+ /** If we're keyframing, then we must allow keyframing outside fcurve bounds. */
+ if (keyframing_to_strip) {
+ r_action_strip->extendmode = NLASTRIP_EXTEND_HOLD;
+ }
+}
+
+static bool is_nlatrack_evaluatable(const AnimData *adt, const NlaTrack *nlt)
+{
+ /* Skip disabled tracks unless it contains the tweaked strip. */
+ const bool contains_tweak_strip = (adt->flag & ADT_NLA_EDIT_ON) &&
+ (nlt->index == adt->act_track->index);
+ if ((nlt->flag & NLATRACK_DISABLED) && !contains_tweak_strip) {
+ return false;
+ }
+
+ /* Solo and muting are mutually exclusive. */
+ if (adt->flag & ADT_NLA_SOLO_TRACK) {
+ /* Skip if there is a solo track, but this isn't it. */
+ if ((nlt->flag & NLATRACK_SOLO) == 0) {
+ return false;
+ }
+ }
+ else {
+ /* Skip track if muted. */
+ if (nlt->flag & NLATRACK_MUTED) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/** Check for special case of non-pushed action being evaluated with no NLA influence (off and no
+ * strips evaluated) nor NLA interference (ensure NLA not soloing). */
+static bool is_action_track_evaluated_without_nla(const AnimData *adt,
+ const bool any_strip_evaluated)
+{
+ if (adt->action == NULL) {
+ return false;
+ }
+
+ if (any_strip_evaluated) {
+ return false;
+ }
+
+ /** NLA settings interference. */
+ if ((adt->flag & (ADT_NLA_SOLO_TRACK | ADT_NLA_EDIT_ON)) == 0) {
+ return false;
+ }
+
+ /** Allow action track to evaluate as if there isn't any NLA data. */
+ return true;
+}
+
/**
- * NLA Evaluation function - values are calculated and stored in temporary "NlaEvalChannels"
+ * XXX(Wayde Moss): #BKE_nlatrack_find_tweaked() exists within nla.c, but it doesn't appear to
+ * work as expected. From #animsys_evaluate_nla_for_flush(), it returns NULL in tweak mode. I'm not
+ * sure why. Preferably, it would be as simple as checking for `(adt->act_Track == nlt)` but that
+ * doesn't work either, neither does comparing indices.
*
+ * This function is a temporary work around. The first disabled track is always the tweaked track.
+ */
+static NlaTrack *nlatrack_find_tweaked(const AnimData *adt)
+{
+ NlaTrack *nlt;
+
+ if (adt == NULL) {
+ return NULL;
+ }
+
+ /* Since the track itself gets disabled, we want the first disabled. */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ if (nlt->flag & NLATRACK_DISABLED) {
+ return nlt;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * NLA Evaluation function - values are calculated and stored in temporary "NlaEvalChannels"
* \param[out] echannels: Evaluation channels with calculated values
- * \param[out] r_context: If not NULL,
- * data about the currently edited strip is stored here and excluded from value calculation.
- * \return false if NLA evaluation isn't actually applicable.
*/
-static bool animsys_evaluate_nla(NlaEvalData *echannels,
- PointerRNA *ptr,
- AnimData *adt,
- const AnimationEvalContext *anim_eval_context,
- const bool flush_to_original,
- NlaKeyframingContext *r_context)
+static bool animsys_evaluate_nla_for_flush(NlaEvalData *echannels,
+ PointerRNA *ptr,
+ const AnimData *adt,
+ const AnimationEvalContext *anim_eval_context,
+ const bool flush_to_original)
{
NlaTrack *nlt;
short track_index = 0;
bool has_strips = false;
-
ListBase estrips = {NULL, NULL};
NlaEvalStrip *nes;
- NlaStrip dummy_strip_buf;
- /* dummy strip for active action */
- NlaStrip *dummy_strip = r_context ? &r_context->strip : &dummy_strip_buf;
+ NlaStrip tweak_strip;
- memset(dummy_strip, 0, sizeof(*dummy_strip));
+ NlaTrack *tweaked_track = nlatrack_find_tweaked(adt);
- /* 1. get the stack of strips to evaluate at current time (influence calculated here) */
+ /* Get the stack of strips to evaluate at current time (influence calculated here). */
for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) {
- /* stop here if tweaking is on and this strip is the tweaking track
- * (it will be the first one that's 'disabled')... */
- if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED)) {
- break;
+
+ if (!is_nlatrack_evaluatable(adt, nlt)) {
+ continue;
}
- /* solo and muting are mutually exclusive... */
- if (adt->flag & ADT_NLA_SOLO_TRACK) {
- /* skip if there is a solo track, but this isn't it */
- if ((nlt->flag & NLATRACK_SOLO) == 0) {
- continue;
- }
- /* else - mute doesn't matter */
+ if (nlt->strips.first) {
+ has_strips = true;
+ }
+
+ /** Append strip to evaluate for this track. */
+ if (nlt == tweaked_track) {
+ /** Tweaked strip is evaluated differently. */
+ animsys_create_tweak_strip(adt, false, &tweak_strip);
+ nes = nlastrips_ctime_get_strip_single(
+ &estrips, &tweak_strip, anim_eval_context, flush_to_original);
}
else {
- /* no solo tracks - skip track if muted */
- if (nlt->flag & NLATRACK_MUTED) {
- continue;
- }
+ nes = nlastrips_ctime_get_strip(
+ &estrips, &nlt->strips, track_index, anim_eval_context, flush_to_original);
+ }
+ if (nes) {
+ nes->track = nlt;
+ }
+ }
+
+ if (is_action_track_evaluated_without_nla(adt, has_strips)) {
+ BLI_freelistN(&estrips);
+ return false;
+ }
+
+ NlaStrip action_strip = {0};
+ animsys_create_action_track_strip(adt, false, &action_strip);
+ nlastrips_ctime_get_strip_single(&estrips, &action_strip, anim_eval_context, flush_to_original);
+
+ /* Per strip, evaluate and accumulate on top of existing channels. */
+ for (nes = estrips.first; nes; nes = nes->next) {
+ nlastrip_evaluate(ptr,
+ echannels,
+ NULL,
+ nes,
+ &echannels->eval_snapshot,
+ anim_eval_context,
+ flush_to_original);
+ }
+
+ /* Free temporary evaluation data that's not used elsewhere. */
+ BLI_freelistN(&estrips);
+ return true;
+}
+
+/** Lower blended values are calculated and accumulated into r_context->lower_eval_data. */
+static void animsys_evaluate_nla_for_keyframing(PointerRNA *ptr,
+ const AnimData *adt,
+ const AnimationEvalContext *anim_eval_context,
+ NlaKeyframingContext *r_context)
+{
+ if (!r_context) {
+ return;
+ }
+
+ /* Early out. If NLA track is soloing and tweaked action isn't it, then don't allow keyframe
+ * insertion. */
+ if (adt->flag & ADT_NLA_SOLO_TRACK) {
+ if (!(adt->act_track && (adt->act_track->flag & NLATRACK_SOLO))) {
+ r_context->eval_strip = NULL;
+ return;
+ }
+ }
+
+ NlaTrack *nlt;
+ short track_index = 0;
+ bool has_strips = false;
+
+ ListBase lower_estrips = {NULL, NULL};
+ NlaEvalStrip *nes;
+
+ NlaTrack *tweaked_track = nlatrack_find_tweaked(adt);
+
+ /* Get the lower stack of strips to evaluate at current time (influence calculated here). */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) {
+
+ if (!is_nlatrack_evaluatable(adt, nlt)) {
+ continue;
+ }
+
+ /* Tweaked strip effect should not be stored in any snapshot. */
+ if (nlt == tweaked_track) {
+ break;
}
- /* if this track has strips (but maybe they won't be suitable), set has_strips
- * - used for mainly for still allowing normal action evaluation...
- */
if (nlt->strips.first) {
has_strips = true;
}
- /* otherwise, get strip to evaluate for this channel */
+ /* Get strip to evaluate for this channel. */
nes = nlastrips_ctime_get_strip(
- &estrips, &nlt->strips, track_index, anim_eval_context, flush_to_original);
+ &lower_estrips, &nlt->strips, track_index, anim_eval_context, false);
if (nes) {
nes->track = nlt;
}
}
- /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack
- * - only do this if we're not exclusively evaluating the 'solo' NLA-track
- * - however, if the 'solo' track houses the current 'tweaking' strip,
- * then we should allow this to play, otherwise nothing happens
+ /** Note: Although we early out, we can still keyframe to the non-pushed action since the
+ * keyframe remap function detects (r_context->strip.act == NULL) and will keyframe without
+ * remapping.
*/
- if ((adt->action) && ((adt->flag & ADT_NLA_SOLO_TRACK) == 0 || (adt->flag & ADT_NLA_EDIT_ON))) {
- /* if there are strips, evaluate action as per NLA rules */
- if ((has_strips) || (adt->actstrip)) {
- /* make dummy NLA strip, and add that to the stack */
- ListBase dummy_trackslist;
-
- dummy_trackslist.first = dummy_trackslist.last = dummy_strip;
-
- /* Strips with a user-defined time curve don't get properly remapped for editing
- * at the moment, so mapping them just for display may be confusing. */
- bool is_inplace_tweak = (nlt) && !(adt->flag & ADT_NLA_EDIT_NOMAP) &&
- !(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME);
-
- if (is_inplace_tweak) {
- /* edit active action in-place according to its active strip, so copy the data */
- memcpy(dummy_strip, adt->actstrip, sizeof(NlaStrip));
- /* Prevents nla eval from considering active strip's adj strips.
- * For user, this means entering tweak mode on a strip ignores evaluating adjacent strips
- * in the same track. */
- dummy_strip->next = dummy_strip->prev = NULL;
-
- /* If tweaked strip is syncing action length, then evaluate using action length. */
- if (dummy_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH) {
- BKE_nlastrip_recalculate_bounds_sync_action(dummy_strip);
- }
- }
- else {
- /* set settings of dummy NLA strip from AnimData settings */
- dummy_strip->act = adt->action;
-
- /* action range is calculated taking F-Modifiers into account
- * (which making new strips doesn't do due to the troublesome nature of that) */
- calc_action_range(dummy_strip->act, &dummy_strip->actstart, &dummy_strip->actend, 1);
- dummy_strip->start = dummy_strip->actstart;
- dummy_strip->end = (IS_EQF(dummy_strip->actstart, dummy_strip->actend)) ?
- (dummy_strip->actstart + 1.0f) :
- (dummy_strip->actend);
-
- /* Always use the blend mode of the strip in tweak mode, even if not in-place. */
- if (nlt && adt->actstrip) {
- dummy_strip->blendmode = adt->actstrip->blendmode;
- dummy_strip->extendmode = NLASTRIP_EXTEND_HOLD;
- }
- else {
- dummy_strip->blendmode = adt->act_blendmode;
- dummy_strip->extendmode = adt->act_extendmode;
- }
+ if (is_action_track_evaluated_without_nla(adt, has_strips)) {
+ BLI_freelistN(&lower_estrips);
+ return;
+ }
- /* Unless extend-mode is Nothing (might be useful for flattening NLA evaluation),
- * disable range. */
- if (dummy_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
- dummy_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
- }
+ /* Write r_context->eval_strip. */
+ if (adt->flag & ADT_NLA_EDIT_ON) {
- dummy_strip->influence = adt->act_influence;
+ NlaStrip *tweak_strip = &r_context->strip;
+ animsys_create_tweak_strip(adt, true, tweak_strip);
+ r_context->eval_strip = nlastrips_ctime_get_strip_single(
+ NULL, tweak_strip, anim_eval_context, false);
+ }
+ else {
- /* NOTE: must set this, or else the default setting overrides,
- * and this setting doesn't work. */
- dummy_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
- }
+ NlaStrip *action_strip = &r_context->strip;
+ animsys_create_action_track_strip(adt, true, action_strip);
+ r_context->eval_strip = nlastrips_ctime_get_strip_single(
+ NULL, action_strip, anim_eval_context, false);
+ }
- /* add this to our list of evaluation strips */
- if (r_context == NULL) {
- nlastrips_ctime_get_strip(
- &estrips, &dummy_trackslist, -1, anim_eval_context, flush_to_original);
- }
- /* If computing the context for keyframing, store data there instead of the list. */
- else {
- /* The extend mode here effectively controls
- * whether it is possible to key-frame beyond the ends.*/
- dummy_strip->extendmode = (is_inplace_tweak &&
- !(dummy_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) ?
- NLASTRIP_EXTEND_NOTHING :
- NLASTRIP_EXTEND_HOLD;
-
- r_context->eval_strip = nes = nlastrips_ctime_get_strip(
- NULL, &dummy_trackslist, -1, anim_eval_context, flush_to_original);
-
- /* These setting combinations require no data from strips below, so exit immediately. */
- if ((nes == NULL) ||
- (dummy_strip->blendmode == NLASTRIP_MODE_REPLACE && dummy_strip->influence == 1.0f)) {
- BLI_freelistN(&estrips);
- return true;
- }
- }
- }
- else {
- /* special case - evaluate as if there isn't any NLA data */
- BLI_freelistN(&estrips);
- return false;
- }
+ /* If NULL, then keyframing will fail. No need to do any more processing. */
+ if (!r_context->eval_strip) {
+ BLI_freelistN(&lower_estrips);
+ return;
}
- /* only continue if there are strips to evaluate */
- if (BLI_listbase_is_empty(&estrips)) {
- return true;
+ /* If tweak strip is full REPLACE, then lower strips not needed. */
+ if (r_context->strip.blendmode == NLASTRIP_MODE_REPLACE &&
+ IS_EQF(r_context->strip.influence, 1.0f)) {
+ BLI_freelistN(&lower_estrips);
+ return;
}
- /* 2. for each strip, evaluate then accumulate on top of existing channels,
- * but don't set values yet. */
- for (nes = estrips.first; nes; nes = nes->next) {
+ /* For each strip, evaluate then accumulate on top of existing channels. */
+ for (nes = lower_estrips.first; nes; nes = nes->next) {
nlastrip_evaluate(ptr,
- echannels,
+ &r_context->lower_eval_data,
NULL,
nes,
- &echannels->eval_snapshot,
+ &r_context->lower_eval_data.eval_snapshot,
anim_eval_context,
- flush_to_original);
+ false);
}
- /* 3. free temporary evaluation data that's not used elsewhere */
- BLI_freelistN(&estrips);
- return true;
+ /* Free temporary evaluation data that's not used elsewhere. */
+ BLI_freelistN(&lower_estrips);
}
/* NLA Evaluation function (mostly for use through do_animdata)
@@ -2412,7 +2574,7 @@ static void animsys_calculate_nla(PointerRNA *ptr,
nlaeval_init(&echannels);
/* evaluate the NLA stack, obtaining a set of values to flush */
- if (animsys_evaluate_nla(&echannels, ptr, adt, anim_eval_context, flush_to_original, NULL)) {
+ if (animsys_evaluate_nla_for_flush(&echannels, ptr, adt, anim_eval_context, flush_to_original)) {
/* reset any channels touched by currently inactive actions to default value */
animsys_evaluate_nla_domain(ptr, &echannels, adt);
@@ -2448,8 +2610,7 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
struct ListBase *cache,
struct PointerRNA *ptr,
struct AnimData *adt,
- const AnimationEvalContext *anim_eval_context,
- const bool flush_to_original)
+ const AnimationEvalContext *anim_eval_context)
{
/* No remapping needed if NLA is off or no action. */
if ((adt == NULL) || (adt->action == NULL) || (adt->nla_tracks.first == NULL) ||
@@ -2472,8 +2633,7 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
ctx->adt = adt;
nlaeval_init(&ctx->lower_eval_data);
- animsys_evaluate_nla(
- &ctx->lower_eval_data, ptr, adt, anim_eval_context, flush_to_original, ctx);
+ animsys_evaluate_nla_for_keyframing(ptr, adt, anim_eval_context, ctx);
BLI_assert(ELEM(ctx->strip.act, NULL, adt->action));
BLI_addtail(cache, ctx);
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 4c9fb4b191a..b8a0ed087e0 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -331,6 +331,8 @@ IDTypeInfo IDType_ID_AR = {
.blend_read_expand = armature_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/** \} */
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index e1e8d06b9ec..85dabe4490c 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -526,6 +526,10 @@ static ReadAttributePtr read_attribute_from_custom_data(const CustomData &custom
case CD_PROP_BOOL:
return std::make_unique<ArrayReadAttribute<bool>>(
domain, Span(static_cast<bool *>(layer.data), size));
+ case CD_MLOOPUV:
+ auto get_uv = [](const MLoopUV &uv) { return float2(uv.uv); };
+ return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, decltype(get_uv)>>(
+ domain, Span(static_cast<MLoopUV *>(layer.data), size), get_uv);
}
}
}
@@ -570,6 +574,12 @@ static WriteAttributePtr write_attribute_from_custom_data(
case CD_PROP_BOOL:
return std::make_unique<ArrayWriteAttribute<bool>>(
domain, MutableSpan(static_cast<bool *>(layer.data), size));
+ case CD_MLOOPUV:
+ auto get_uv = [](const MLoopUV &uv) { return float2(uv.uv); };
+ auto set_uv = [](MLoopUV &uv, const float2 value) { copy_v2_v2(uv.uv, value); };
+ return std::make_unique<
+ DerivedArrayWriteAttribute<MLoopUV, float2, decltype(get_uv), decltype(set_uv)>>(
+ domain, MutableSpan(static_cast<MLoopUV *>(layer.data), size), get_uv, set_uv);
}
}
}
@@ -597,8 +607,9 @@ static void get_custom_data_layer_attribute_names(const CustomData &custom_data,
Set<std::string> &r_names)
{
for (const CustomDataLayer &layer : blender::Span(custom_data.layers, custom_data.totlayer)) {
- if (component.attribute_domain_with_type_supported(domain,
- static_cast<CustomDataType>(layer.type))) {
+ const CustomDataType data_type = static_cast<CustomDataType>(layer.type);
+ if (component.attribute_domain_with_type_supported(domain, data_type) ||
+ ELEM(data_type, CD_MLOOPUV)) {
r_names.add(layer.name);
}
}
@@ -1327,7 +1338,7 @@ Set<std::string> MeshComponent::attribute_names() const
for (StringRef name : vertex_group_names_.keys()) {
names.add(name);
}
- get_custom_data_layer_attribute_names(mesh_->pdata, *this, ATTR_DOMAIN_CORNER, names);
+ get_custom_data_layer_attribute_names(mesh_->ldata, *this, ATTR_DOMAIN_CORNER, names);
get_custom_data_layer_attribute_names(mesh_->vdata, *this, ATTR_DOMAIN_POINT, names);
get_custom_data_layer_attribute_names(mesh_->edata, *this, ATTR_DOMAIN_EDGE, names);
get_custom_data_layer_attribute_names(mesh_->pdata, *this, ATTR_DOMAIN_POLYGON, names);
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 0855db1a943..49475c014cd 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -647,6 +647,10 @@ UserDef *BKE_blendfile_userdef_from_defaults(void)
BKE_studiolight_default(userdef->light_param, userdef->light_ambient);
BKE_preferences_asset_library_default_add(userdef);
+ /* Enable asset browser features by default for alpha testing.
+ * BLO_sanitize_experimental_features_userpref_blend() will disable it again for non-alpha
+ * builds. */
+ userdef->experimental.use_asset_browser = true;
return userdef;
}
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 762ced7dc5f..2ad0ac950d0 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -23,7 +23,7 @@
* - passing output paths to the visitor?, like render out.
* - passing sequence strips with many images.
* - passing directory paths - visitors don't know which path is a dir or a file.
- * */
+ */
#include <sys/stat.h>
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 9a954a89cad..28c8ae3e416 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -410,6 +410,8 @@ IDTypeInfo IDType_ID_BR = {
.blend_read_expand = brush_blend_read_expand,
.blend_read_undo_preserve = brush_undo_preserve,
+
+ .lib_override_apply_post = NULL,
};
static RNG *brush_rng;
@@ -978,7 +980,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->fill_leak = 3;
brush->gpencil_settings->fill_threshold = 0.1f;
brush->gpencil_settings->fill_simplylvl = 1;
- brush->gpencil_settings->fill_factor = 1;
+ brush->gpencil_settings->fill_factor = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->hardeness = 1.0f;
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index d6c31809a2e..1e2139522f1 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -142,6 +142,8 @@ IDTypeInfo IDType_ID_CF = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/* TODO: make this per cache file to avoid global locks. */
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 0ca22e34973..b0e3743add1 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -203,6 +203,8 @@ IDTypeInfo IDType_ID_CA = {
.blend_read_expand = camera_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/** \} */
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 58ce7227398..601ee57fc89 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -362,6 +362,8 @@ IDTypeInfo IDType_ID_GR = {
.blend_read_expand = collection_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/** \} */
@@ -1941,9 +1943,6 @@ static void scene_collections_build_array(Collection *collection, void *data)
static void scene_collections_array(Scene *scene, Collection ***collections_array, int *tot)
{
- Collection *collection;
- Collection **array;
-
*collections_array = NULL;
*tot = 0;
@@ -1951,7 +1950,7 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra
return;
}
- collection = scene->master_collection;
+ Collection *collection = scene->master_collection;
BLI_assert(collection != NULL);
scene_collection_callback(collection, scene_collections_count, tot);
@@ -1959,7 +1958,8 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra
return;
}
- *collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray");
+ Collection **array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray");
+ *collections_array = array;
scene_collection_callback(collection, scene_collections_build_array, &array);
}
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 65accc66084..6bc385ecd31 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -318,7 +318,7 @@ static eContextResult ctx_data_get(bContext *C, const char *member, bContextData
*
* Values in order of importance
* (0, -1, 1) - Where 1 is highest priority
- * */
+ */
if (done != 1 && recursion < 1 && C->wm.store) {
C->data.recursion = 1;
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index ebce28c4e23..5632ae28960 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -327,6 +327,8 @@ IDTypeInfo IDType_ID_CU = {
.blend_read_expand = curve_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
static int cu_isectLL(const float v1[3],
@@ -2373,7 +2375,7 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
* 0,1,2,3,4 --> 1,2,3,4,0
*
* this is why we compare last with second last
- * */
+ */
float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3];
BevPoint *bevp_first;
diff --git a/source/blender/blenkernel/intern/curve_deform.c b/source/blender/blenkernel/intern/curve_deform.c
index 4725be6d302..63da7c1dd11 100644
--- a/source/blender/blenkernel/intern/curve_deform.c
+++ b/source/blender/blenkernel/intern/curve_deform.c
@@ -233,7 +233,7 @@ static bool calc_curve_deform(
* Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell
*
* note: moved functions into quat_apply_track/vec_apply_track
- * */
+ */
copy_qt_qt(quat, new_quat);
copy_v3_v3(cent, co);
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index b0994fb683a..37e9c810123 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -212,9 +212,9 @@ static void layerFree_mdeformvert(void *data, int count, int size)
/* copy just zeros in this case */
static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, int count)
{
- int i, size = sizeof(void *);
+ const int size = sizeof(void *);
- for (i = 0; i < count; i++) {
+ for (int i = 0; i < count; i++) {
void **ptr = POINTER_OFFSET(dest, i * size);
*ptr = NULL;
}
@@ -253,15 +253,14 @@ static void layerInterp_mdeformvert(const void **sources,
MDeformVert *dvert = dest;
struct MDeformWeight_Link *dest_dwlink = NULL;
struct MDeformWeight_Link *node;
- int i, j, totweight;
/* build a list of unique def_nrs for dest */
- totweight = 0;
- for (i = 0; i < count; i++) {
+ int totweight = 0;
+ for (int i = 0; i < count; i++) {
const MDeformVert *source = sources[i];
float interp_weight = weights[i];
- for (j = 0; j < source->totweight; j++) {
+ for (int j = 0; j < source->totweight; j++) {
MDeformWeight *dw = &source->dw[j];
float weight = dw->weight * interp_weight;
@@ -311,7 +310,8 @@ static void layerInterp_mdeformvert(const void **sources,
if (totweight) {
dvert->totweight = totweight;
- for (i = 0, node = dest_dwlink; node; node = node->next, i++) {
+ int i = 0;
+ for (node = dest_dwlink; node; node = node->next, i++) {
if (node->dw.weight > 1.0f) {
node->dw.weight = 1.0f;
}
@@ -416,18 +416,16 @@ static void layerInterp_tface(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
MTFace *tf = dest;
- int i, j, k;
float uv[4][2] = {{0.0f}};
- const float *sub_weight;
- sub_weight = sub_weights;
- for (i = 0; i < count; i++) {
+ const float *sub_weight = sub_weights;
+ for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
const MTFace *src = sources[i];
- for (j = 0; j < 4; j++) {
+ for (int j = 0; j < 4; j++) {
if (sub_weights) {
- for (k = 0; k < 4; k++, sub_weight++) {
+ for (int k = 0; k < 4; k++, sub_weight++) {
madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * interp_weight);
}
}
@@ -446,9 +444,8 @@ static void layerSwap_tface(void *data, const int *corner_indices)
{
MTFace *tf = data;
float uv[4][2];
- int j;
- for (j = 0; j < 4; j++) {
+ for (int j = 0; j < 4; j++) {
const int source_index = corner_indices[j];
copy_v2_v2(uv[j], tf->uv[source_index]);
}
@@ -517,18 +514,16 @@ static void layerInterp_origspace_face(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
OrigSpaceFace *osf = dest;
- int i, j, k;
float uv[4][2] = {{0.0f}};
- const float *sub_weight;
- sub_weight = sub_weights;
- for (i = 0; i < count; i++) {
+ const float *sub_weight = sub_weights;
+ for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
const OrigSpaceFace *src = sources[i];
- for (j = 0; j < 4; j++) {
+ for (int j = 0; j < 4; j++) {
if (sub_weights) {
- for (k = 0; k < 4; k++, sub_weight++) {
+ for (int k = 0; k < 4; k++, sub_weight++) {
madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * interp_weight);
}
}
@@ -546,9 +541,8 @@ static void layerSwap_origspace_face(void *data, const int *corner_indices)
{
OrigSpaceFace *osf = data;
float uv[4][2];
- int j;
- for (j = 0; j < 4; j++) {
+ for (int j = 0; j < 4; j++) {
copy_v2_v2(uv[j], osf->uv[corner_indices[j]]);
}
memcpy(osf->uv, uv, sizeof(osf->uv));
@@ -567,13 +561,11 @@ static void layerDefault_origspace_face(void *data, int count)
static void layerSwap_mdisps(void *data, const int *ci)
{
MDisps *s = data;
- float(*d)[3] = NULL;
- int corners, cornersize, S;
if (s->disps) {
int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */
- corners = multires_mdisp_corners(s);
- cornersize = s->totdisp / corners;
+ int corners = multires_mdisp_corners(s);
+ int cornersize = s->totdisp / corners;
if (corners != nverts) {
/* happens when face changed vertex count in edit mode
@@ -585,9 +577,9 @@ static void layerSwap_mdisps(void *data, const int *ci)
return;
}
- d = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap");
+ float(*d)[3] = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap");
- for (S = 0; S < corners; S++) {
+ for (int S = 0; S < corners; S++) {
memcpy(d + cornersize * S, s->disps + cornersize * ci[S], sizeof(float[3]) * cornersize);
}
@@ -1128,9 +1120,8 @@ static void layerSwap_mcol(void *data, const int *corner_indices)
{
MCol *mcol = data;
MCol col[4];
- int j;
- for (j = 0; j < 4; j++) {
+ for (int j = 0; j < 4; j++) {
col[j] = mcol[corner_indices[j]];
}
@@ -2064,13 +2055,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
void CustomData_update_typemap(CustomData *data)
{
- int i, lasttype = -1;
+ int lasttype = -1;
- for (i = 0; i < CD_NUMTYPES; i++) {
+ for (int i = 0; i < CD_NUMTYPES; i++) {
data->typemap[i] = -1;
}
- for (i = 0; i < data->totlayer; i++) {
+ for (int i = 0; i < data->totlayer; i++) {
const int type = data->layers[i].type;
if (type != lasttype) {
data->typemap[type] = i;
@@ -2097,18 +2088,16 @@ bool CustomData_merge(const struct CustomData *source,
{
/*const LayerTypeInfo *typeInfo;*/
CustomDataLayer *layer, *newlayer;
- void *data;
- int i, type, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0,
- flag = 0;
+ int lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0;
int number = 0, maxnumber = -1;
bool changed = false;
- for (i = 0; i < source->totlayer; i++) {
+ for (int i = 0; i < source->totlayer; i++) {
layer = &source->layers[i];
/*typeInfo = layerType_getInfo(layer->type);*/ /*UNUSED*/
- type = layer->type;
- flag = layer->flag;
+ int type = layer->type;
+ int flag = layer->flag;
if (type != lasttype) {
number = 0;
@@ -2136,6 +2125,7 @@ bool CustomData_merge(const struct CustomData *source,
continue;
}
+ void *data;
switch (alloctype) {
case CD_ASSIGN:
case CD_REFERENCE:
@@ -2518,8 +2508,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
/* Passing a layer-data to copy from with an alloctype that won't copy is
* most likely a bug */
- BLI_assert(!layerdata || (alloctype == CD_ASSIGN) || (alloctype == CD_DUPLICATE) ||
- (alloctype == CD_REFERENCE));
+ BLI_assert(!layerdata || ELEM(alloctype, CD_ASSIGN, CD_DUPLICATE, CD_REFERENCE));
if (!typeInfo->defaultname && CustomData_has_layer(data, type)) {
return &data->layers[CustomData_get_layer_index(data, type)];
@@ -2616,10 +2605,9 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
void *CustomData_add_layer(
CustomData *data, int type, eCDAllocType alloctype, void *layerdata, int totelem)
{
- CustomDataLayer *layer;
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- layer = customData_add_layer__internal(
+ CustomDataLayer *layer = customData_add_layer__internal(
data, type, alloctype, layerdata, totelem, typeInfo->defaultname);
CustomData_update_typemap(data);
@@ -2638,9 +2626,8 @@ void *CustomData_add_layer_named(CustomData *data,
int totelem,
const char *name)
{
- CustomDataLayer *layer;
-
- layer = customData_add_layer__internal(data, type, alloctype, layerdata, totelem, name);
+ CustomDataLayer *layer = customData_add_layer__internal(
+ data, type, alloctype, layerdata, totelem, name);
CustomData_update_typemap(data);
if (layer) {
@@ -2828,12 +2815,10 @@ bool CustomData_is_referenced_layer(struct CustomData *data, int type)
void CustomData_free_temporary(CustomData *data, int totelem)
{
- CustomDataLayer *layer;
int i, j;
bool changed = false;
-
for (i = 0, j = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
+ CustomDataLayer *layer = &data->layers[i];
if (i != j) {
data->layers[j] = data->layers[i];
@@ -3681,10 +3666,8 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n)
{
- const LayerTypeInfo *typeInfo;
int offset = data->layers[n].offset;
-
- typeInfo = layerType_getInfo(data->layers[n].type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
if (typeInfo->set_default) {
typeInfo->set_default(POINTER_OFFSET(*block, offset), 1);
@@ -4050,7 +4033,6 @@ void CustomData_bmesh_interp(CustomData *data,
return;
}
- int i, j;
void *source_buf[SOURCE_BUF_SIZE];
const void **sources = (const void **)source_buf;
@@ -4071,11 +4053,11 @@ void CustomData_bmesh_interp(CustomData *data,
}
/* interpolates a layer at a time */
- for (i = 0; i < data->totlayer; i++) {
+ for (int i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (typeInfo->interp) {
- for (j = 0; j < count; j++) {
+ for (int j = 0; j < count; j++) {
sources[j] = POINTER_OFFSET(src_blocks[j], layer->offset);
}
CustomData_bmesh_interp_n(
@@ -4453,7 +4435,6 @@ bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, cons
void CustomData_layers__print(CustomData *data)
{
-
printf("{\n");
int i;
@@ -4508,10 +4489,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
{
CustomDataExternal *external = data->external;
CustomDataLayer *layer;
- CDataFile *cdf;
- CDataFileLayer *blay;
char filename[FILE_MAX];
- const LayerTypeInfo *typeInfo;
int update = 0;
if (!external) {
@@ -4520,7 +4498,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
for (int i = 0; i < data->totlayer; i++) {
layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
/* pass */
@@ -4539,7 +4517,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
customdata_external_filename(filename, id, external);
- cdf = cdf_create(CDF_TYPE_MESH);
+ CDataFile *cdf = cdf_create(CDF_TYPE_MESH);
if (!cdf_read_open(cdf, filename)) {
cdf_free(cdf);
CLOG_ERROR(&LOG, "Failed to read %s layer from %s.", layerType_getName(layer->type), filename);
@@ -4548,7 +4526,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
for (int i = 0; i < data->totlayer; i++) {
layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
/* pass */
@@ -4557,7 +4535,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
/* pass */
}
else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) {
- blay = cdf_layer_find(cdf, layer->type, layer->name);
+ CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name);
if (blay) {
if (cdf_read_layer(cdf, blay)) {
@@ -4584,10 +4562,6 @@ void CustomData_external_write(
CustomData *data, ID *id, CustomDataMask mask, int totelem, int free)
{
CustomDataExternal *external = data->external;
- CustomDataLayer *layer;
- CDataFile *cdf;
- CDataFileLayer *blay;
- const LayerTypeInfo *typeInfo;
int update = 0;
char filename[FILE_MAX];
@@ -4597,8 +4571,8 @@ void CustomData_external_write(
/* test if there is anything to write */
for (int i = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
+ CustomDataLayer *layer = &data->layers[i];
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
/* pass */
@@ -4616,11 +4590,11 @@ void CustomData_external_write(
CustomData_external_read(data, id, mask, totelem);
customdata_external_filename(filename, id, external);
- cdf = cdf_create(CDF_TYPE_MESH);
+ CDataFile *cdf = cdf_create(CDF_TYPE_MESH);
for (int i = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
+ CustomDataLayer *layer = &data->layers[i];
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->filesize) {
if (layer->flag & CD_FLAG_IN_MEMORY) {
@@ -4642,11 +4616,11 @@ void CustomData_external_write(
int i;
for (i = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
+ CustomDataLayer *layer = &data->layers[i];
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
- blay = cdf_layer_find(cdf, layer->type, layer->name);
+ CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name);
if (cdf_write_layer(cdf, blay)) {
if (typeInfo->write(cdf, layer->data, totelem)) {
@@ -4670,8 +4644,8 @@ void CustomData_external_write(
}
for (i = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
+ CustomDataLayer *layer = &data->layers[i];
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
if (free) {
@@ -4691,15 +4665,13 @@ void CustomData_external_add(
CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filename)
{
CustomDataExternal *external = data->external;
- CustomDataLayer *layer;
- int layer_index;
- layer_index = CustomData_get_active_layer_index(data, type);
+ int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
return;
}
- layer = &data->layers[layer_index];
+ CustomDataLayer *layer = &data->layers[layer_index];
if (layer->flag & CD_FLAG_EXTERNAL) {
return;
@@ -4823,8 +4795,6 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
cd_interp interp_cd = NULL;
cd_copy copy_cd = NULL;
- void *tmp_dst;
-
if (!sources) {
/* Not supported here, abort. */
return;
@@ -4841,7 +4811,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
copy_cd = type_info->copy;
}
- tmp_dst = MEM_mallocN(data_size, __func__);
+ void *tmp_dst = MEM_mallocN(data_size, __func__);
if (count > 1 && !interp_cd) {
if (data_flag) {
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 375792a02c2..58c050493c9 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -488,6 +488,7 @@ void BKE_displist_fill(ListBase *dispbase,
while (cont) {
int dl_flag_accum = 0;
+ int dl_rt_accum = 0;
cont = 0;
totvert = 0;
nextcol = 0;
@@ -535,6 +536,7 @@ void BKE_displist_fill(ListBase *dispbase,
}
}
dl_flag_accum |= dl->flag;
+ dl_rt_accum |= dl->rt;
}
}
@@ -544,6 +546,7 @@ void BKE_displist_fill(ListBase *dispbase,
dlnew = MEM_callocN(sizeof(DispList), "filldisplist");
dlnew->type = DL_INDEX3;
dlnew->flag = (dl_flag_accum & (DL_BACK_CURVE | DL_FRONT_CURVE));
+ dlnew->rt = (dl_rt_accum & CU_SMOOTH);
dlnew->col = colnr;
dlnew->nr = totvert;
dlnew->parts = tot;
@@ -1129,7 +1132,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
*
* The right solution would be to COW the Curve data block at the input of the modifier
* stack just like what the mesh modifier does.
- * */
+ */
modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
}
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index df1dbaa905f..25a0259abe3 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -176,6 +176,8 @@ IDTypeInfo IDType_ID_VF = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/***************************** VFont *******************************/
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index a47a3dbc872..dae0b757df0 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -19,6 +19,7 @@
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
#include "BKE_pointcloud.h"
+#include "BKE_volume.h"
#include "DNA_object_types.h"
@@ -52,6 +53,8 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ
return new PointCloudComponent();
case GeometryComponentType::Instances:
return new InstancesComponent();
+ case GeometryComponentType::Volume:
+ return new VolumeComponent();
}
BLI_assert(false);
return nullptr;
@@ -202,6 +205,13 @@ const PointCloud *GeometrySet::get_pointcloud_for_read() const
return (component == nullptr) ? nullptr : component->get_for_read();
}
+/* Returns a read-only volume or null. */
+const Volume *GeometrySet::get_volume_for_read() const
+{
+ const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
+ return (component == nullptr) ? nullptr : component->get_for_read();
+}
+
/* Returns true when the geometry set has a point cloud component that has a point cloud. */
bool GeometrySet::has_pointcloud() const
{
@@ -216,6 +226,13 @@ bool GeometrySet::has_instances() const
return component != nullptr && component->instances_amount() >= 1;
}
+/* Returns true when the geometry set has a volume component that has a volume. */
+bool GeometrySet::has_volume() const
+{
+ const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
+ return component != nullptr && component->has_volume();
+}
+
/* Create a new geometry set that only contains the given mesh. */
GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
@@ -263,6 +280,13 @@ PointCloud *GeometrySet::get_pointcloud_for_write()
return component.get_for_write();
}
+/* Returns a mutable volume or null. No ownership is transferred. */
+Volume *GeometrySet::get_volume_for_write()
+{
+ VolumeComponent &component = this->get_component_for_write<VolumeComponent>();
+ return component.get_for_write();
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -545,6 +569,85 @@ bool InstancesComponent::is_empty() const
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Volume Component
+ * \{ */
+
+VolumeComponent::VolumeComponent() : GeometryComponent(GeometryComponentType::Volume)
+{
+}
+
+VolumeComponent::~VolumeComponent()
+{
+ this->clear();
+}
+
+GeometryComponent *VolumeComponent::copy() const
+{
+ VolumeComponent *new_component = new VolumeComponent();
+ if (volume_ != nullptr) {
+ new_component->volume_ = BKE_volume_copy_for_eval(volume_, false);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ }
+ return new_component;
+}
+
+void VolumeComponent::clear()
+{
+ BLI_assert(this->is_mutable());
+ if (volume_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, volume_);
+ }
+ volume_ = nullptr;
+ }
+}
+
+bool VolumeComponent::has_volume() const
+{
+ return volume_ != nullptr;
+}
+
+/* Clear the component and replace it with the new volume. */
+void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ this->clear();
+ volume_ = volume;
+ ownership_ = ownership;
+}
+
+/* Return the volume and clear the component. The caller takes over responsibility for freeing the
+ * volume (if the component was responsible before). */
+Volume *VolumeComponent::release()
+{
+ BLI_assert(this->is_mutable());
+ Volume *volume = volume_;
+ volume_ = nullptr;
+ return volume;
+}
+
+/* Get the volume from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned volume should not be modified. No ownership is transferred. */
+const Volume *VolumeComponent::get_for_read() const
+{
+ return volume_;
+}
+
+/* Get the volume from this component. This method can only be used when the component is mutable,
+ * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */
+Volume *VolumeComponent::get_for_write()
+{
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ volume_ = BKE_volume_copy_for_eval(volume_, false);
+ ownership_ = GeometryOwnershipType::Owned;
+ }
+ return volume_;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name C API
* \{ */
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index f68a390db64..0c813c170ad 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -93,7 +93,33 @@ static void greasepencil_copy_data(Main *UNUSED(bmain),
/* make a copy of source layer and its data */
/* TODO here too could add unused flags... */
- bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src);
+ bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src, true, true);
+
+ /* Apply local layer transform to all frames. Calc the active frame is not enough
+ * because onion skin can use more frames. This is more slow but required here. */
+ if (gpl_dst->actframe != NULL) {
+ bool transfomed = ((!is_zero_v3(gpl_dst->location)) || (!is_zero_v3(gpl_dst->rotation)) ||
+ (!is_one_v3(gpl_dst->scale)));
+ if (transfomed) {
+ loc_eul_size_to_mat4(
+ gpl_dst->layer_mat, gpl_dst->location, gpl_dst->rotation, gpl_dst->scale);
+ bool do_onion = ((gpl_dst->onion_flag & GP_LAYER_ONIONSKIN) != 0);
+ bGPDframe *init_gpf = (do_onion) ? gpl_dst->frames.first : gpl_dst->actframe;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ mul_m4_v3(gpl_dst->layer_mat, &pt->x);
+ }
+ }
+ /* if not onion, exit loop. */
+ if (!do_onion) {
+ break;
+ }
+ }
+ }
+ }
BLI_addtail(&gpd_dst->layers, gpl_dst);
}
@@ -303,6 +329,8 @@ IDTypeInfo IDType_ID_GD = {
.blend_read_expand = greasepencil_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/* ************************************************** */
@@ -581,7 +609,7 @@ bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
}
/* Create a copy of the frame */
- new_frame = BKE_gpencil_frame_duplicate(gpl->actframe);
+ new_frame = BKE_gpencil_frame_duplicate(gpl->actframe, true);
/* Find frame to insert it before */
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
@@ -686,6 +714,14 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti
/* Enable always affected by scene lights. */
gpl->flag |= GP_LAYER_USE_LIGHTS;
+
+ /* Init transform. */
+ zero_v3(gpl->location);
+ zero_v3(gpl->rotation);
+ copy_v3_fl(gpl->scale, 1.0f);
+ loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
+ invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
+
/* make this one the active one */
if (setactive) {
BKE_gpencil_layer_active_set(gpd, gpl);
@@ -957,7 +993,7 @@ bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src,
* \param gpf_src: Source grease pencil frame
* \return Pointer to new frame
*/
-bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
+bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_strokes)
{
bGPDstroke *gps_dst = NULL;
bGPDframe *gpf_dst;
@@ -971,12 +1007,14 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
gpf_dst = MEM_dupallocN(gpf_src);
gpf_dst->prev = gpf_dst->next = NULL;
- /* copy strokes */
+ /* Copy strokes. */
BLI_listbase_clear(&gpf_dst->strokes);
- LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
- /* make copy of source stroke */
- gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
- BLI_addtail(&gpf_dst->strokes, gps_dst);
+ if (dup_strokes) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
+ /* make copy of source stroke */
+ gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+ }
}
/* return new frame */
@@ -1010,7 +1048,9 @@ void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_ds
* \param gpl_src: Source grease pencil layer
* \return Pointer to new layer
*/
-bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
+bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src,
+ const bool dup_frames,
+ const bool dup_strokes)
{
const bGPDframe *gpf_src;
bGPDframe *gpf_dst;
@@ -1035,14 +1075,16 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
/* copy frames */
BLI_listbase_clear(&gpl_dst->frames);
- for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
- /* make a copy of source frame */
- gpf_dst = BKE_gpencil_frame_duplicate(gpf_src);
- BLI_addtail(&gpl_dst->frames, gpf_dst);
-
- /* if source frame was the current layer's 'active' frame, reassign that too */
- if (gpf_src == gpl_dst->actframe) {
- gpl_dst->actframe = gpf_dst;
+ if (dup_frames) {
+ for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
+ /* make a copy of source frame */
+ gpf_dst = BKE_gpencil_frame_duplicate(gpf_src, dup_strokes);
+ BLI_addtail(&gpl_dst->frames, gpf_dst);
+
+ /* if source frame was the current layer's 'active' frame, reassign that too */
+ if (gpf_src == gpl_dst->actframe) {
+ gpl_dst->actframe = gpf_dst;
+ }
}
}
@@ -2519,7 +2561,7 @@ void BKE_gpencil_visible_stroke_iter(ViewLayer *view_layer,
int cfra)
{
bGPdata *gpd = (bGPdata *)ob->data;
- const bool is_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool is_multiedit = ((GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) && (!GPENCIL_PLAY_ON(gpd)));
const bool is_onion = do_onion && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0);
const bool is_drawing = (gpd->runtime.sbuffer_used > 0);
@@ -2541,6 +2583,11 @@ void BKE_gpencil_visible_stroke_iter(ViewLayer *view_layer,
continue;
}
+ /* If scale to 0 the layer must be invisible. */
+ if (is_zero_v3(gpl->scale)) {
+ continue;
+ }
+
/* Hide the layer if it's defined a view layer filter. This is used to
* generate renders, putting only selected GP layers for each View Layer.
* This is used only in final render and never in Viewport. */
@@ -2759,10 +2806,10 @@ void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_ev
* \param gpl: Grease pencil layer
* \param diff_mat: Result parent matrix
*/
-void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph,
- Object *obact,
- bGPDlayer *gpl,
- float diff_mat[4][4])
+void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph,
+ Object *obact,
+ bGPDlayer *gpl,
+ float diff_mat[4][4])
{
Object *ob_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obact) : obact;
Object *obparent = gpl->parent;
@@ -2771,11 +2818,10 @@ void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph,
/* if not layer parented, try with object parented */
if (obparent_eval == NULL) {
- if (ob_eval != NULL) {
- if (ob_eval->type == OB_GPENCIL) {
- copy_m4_m4(diff_mat, ob_eval->obmat);
- return;
- }
+ if ((ob_eval != NULL) && (ob_eval->type == OB_GPENCIL)) {
+ copy_m4_m4(diff_mat, ob_eval->obmat);
+ mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat);
+ return;
}
/* not gpencil object */
unit_m4(diff_mat);
@@ -2785,6 +2831,7 @@ void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph,
if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) {
mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
add_v3_v3(diff_mat[3], ob_eval->obmat[3]);
+ mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat);
return;
}
if (gpl->partype == PARBONE) {
@@ -2800,6 +2847,7 @@ void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph,
mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
add_v3_v3(diff_mat[3], ob_eval->obmat[3]);
}
+ mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat);
return;
}
@@ -2807,11 +2855,11 @@ void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph,
}
/**
- * Update parent matrix.
+ * Update parent matrix and local transforms.
* \param depsgraph: Depsgraph
* \param ob: Grease pencil object
*/
-void BKE_gpencil_update_layer_parent(const Depsgraph *depsgraph, Object *ob)
+void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob)
{
if (ob->type != OB_GPENCIL) {
return;
@@ -2820,31 +2868,50 @@ void BKE_gpencil_update_layer_parent(const Depsgraph *depsgraph, Object *ob)
bGPdata *gpd = (bGPdata *)ob->data;
float cur_mat[4][4];
+ bool changed = false;
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
- if ((gpl->parent != NULL) && (gpl->actframe != NULL)) {
- Object *ob_parent = DEG_get_evaluated_object(depsgraph, gpl->parent);
- /* calculate new matrix */
- if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) {
- copy_m4_m4(cur_mat, ob_parent->obmat);
- }
- else if (gpl->partype == PARBONE) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob_parent->pose, gpl->parsubstr);
- if (pchan != NULL) {
- copy_m4_m4(cur_mat, ob->imat);
- mul_m4_m4m4(cur_mat, ob_parent->obmat, pchan->pose_mat);
+ unit_m4(cur_mat);
+ if (gpl->actframe != NULL) {
+ if (gpl->parent != NULL) {
+ Object *ob_parent = DEG_get_evaluated_object(depsgraph, gpl->parent);
+ /* calculate new matrix */
+ if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) {
+ copy_m4_m4(cur_mat, ob_parent->obmat);
}
- else {
- unit_m4(cur_mat);
+ else if (gpl->partype == PARBONE) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob_parent->pose, gpl->parsubstr);
+ if (pchan != NULL) {
+ copy_m4_m4(cur_mat, ob->imat);
+ mul_m4_m4m4(cur_mat, ob_parent->obmat, pchan->pose_mat);
+ }
+ else {
+ unit_m4(cur_mat);
+ }
}
+ changed = !equals_m4m4(gpl->inverse, cur_mat);
+ }
+
+ /* Calc local layer transform. */
+ bool transfomed = ((!is_zero_v3(gpl->location)) || (!is_zero_v3(gpl->rotation)) ||
+ (!is_one_v3(gpl->scale)));
+ if (transfomed) {
+ loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
}
+
/* only redo if any change */
- if (!equals_m4m4(gpl->inverse, cur_mat)) {
+ if (changed || transfomed) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) {
bGPDspoint *pt;
int i;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- mul_m4_v3(gpl->inverse, &pt->x);
- mul_m4_v3(cur_mat, &pt->x);
+ if (changed) {
+ mul_m4_v3(gpl->inverse, &pt->x);
+ mul_m4_v3(cur_mat, &pt->x);
+ }
+
+ if (transfomed) {
+ mul_m4_v3(gpl->layer_mat, &pt->x);
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 1be2cba31b5..8b12e1b5fca 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -701,13 +701,18 @@ void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *o
Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
bGPdata *gpd_orig = (bGPdata *)ob_orig->data;
- /* Need check if some layer is parented. */
+ /* Need check if some layer is parented or transformed. */
bool do_parent = false;
+ bool do_transform = false;
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_orig->layers) {
if (gpl->parent != NULL) {
do_parent = true;
break;
}
+ if ((!is_zero_v3(gpl->location)) || (!is_zero_v3(gpl->rotation)) || (!is_one_v3(gpl->scale))) {
+ do_transform = true;
+ break;
+ }
}
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_eval);
@@ -715,7 +720,7 @@ void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *o
const bool do_modifiers = (bool)((!is_multiedit) && (!is_curve_edit) &&
(ob->greasepencil_modifiers.first != NULL) &&
(!GPENCIL_SIMPLIFY_MODIF(scene)));
- if ((!do_modifiers) && (!do_parent)) {
+ if ((!do_modifiers) && (!do_parent) && (!do_transform)) {
return;
}
DEG_debug_print_eval(depsgraph, __func__, gpd_eval->id.name, gpd_eval);
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c
index a44b054e366..f76e5a73478 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.c
@@ -197,6 +197,8 @@ IDTypeInfo IDType_ID_HA = {
.blend_read_expand = hair_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
static void hair_random(Hair *hair)
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index b0991f1d343..6b164e6bc50 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -92,11 +92,9 @@ IDProperty *IDP_NewIDPArray(const char *name)
IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag)
{
/* don't use MEM_dupallocN because this may be part of an array */
- IDProperty *narray, *tmp;
-
BLI_assert(array->type == IDP_IDPARRAY);
- narray = MEM_mallocN(sizeof(IDProperty), __func__);
+ IDProperty *narray = MEM_mallocN(sizeof(IDProperty), __func__);
*narray = *array;
narray->data.pointer = MEM_dupallocN(array->data.pointer);
@@ -107,7 +105,7 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag)
* then free it. this makes for more maintainable
* code than simply re-implementing the copy functions
* in this loop.*/
- tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag);
+ IDProperty *tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag);
memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
MEM_freeN(tmp);
}
@@ -131,15 +129,13 @@ static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
/* shallow copies item */
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
{
- IDProperty *old;
-
BLI_assert(prop->type == IDP_IDPARRAY);
if (index >= prop->len || index < 0) {
return;
}
- old = GETPROP(prop, index);
+ IDProperty *old = GETPROP(prop, index);
if (item != old) {
IDP_FreePropertyContent(old);
@@ -164,8 +160,6 @@ void IDP_AppendArray(IDProperty *prop, IDProperty *item)
void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
{
- int newsize;
-
BLI_assert(prop->type == IDP_IDPARRAY);
/* first check if the array buffer size has room */
@@ -200,7 +194,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
* system realloc().
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
*/
- newsize = newlen;
+ int newsize = newlen;
newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize);
prop->len = newlen;
@@ -218,9 +212,8 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
/* bigger */
IDProperty **array = newarr;
IDPropertyTemplate val;
- int a;
- for (a = prop->len; a < newlen; a++) {
+ for (int a = prop->len; a < newlen; a++) {
val.i = 0; /* silence MSVC warning about uninitialized var when debugging */
array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group");
}
@@ -228,9 +221,8 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
else {
/* smaller */
IDProperty **array = prop->data.pointer;
- int a;
- for (a = newlen; a < prop->len; a++) {
+ for (int a = newlen; a < prop->len; a++) {
IDP_FreeProperty(array[a]);
}
}
@@ -239,7 +231,6 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
/*this function works for strings too!*/
void IDP_ResizeArray(IDProperty *prop, int newlen)
{
- int newsize;
const bool is_grow = newlen >= prop->len;
/* first check if the array buffer size has room */
@@ -257,7 +248,7 @@ void IDP_ResizeArray(IDProperty *prop, int newlen)
* system realloc().
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
*/
- newsize = newlen;
+ int newsize = newlen;
newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
if (is_grow == false) {
@@ -362,10 +353,8 @@ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag)
{
- IDProperty *newp;
-
BLI_assert(prop->type == IDP_STRING);
- newp = idp_generic_copy(prop, flag);
+ IDProperty *newp = idp_generic_copy(prop, flag);
if (prop->data.pointer) {
newp->data.pointer = MEM_dupallocN(prop->data.pointer);
@@ -379,10 +368,8 @@ static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag)
void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
{
- int stlen;
-
BLI_assert(prop->type == IDP_STRING);
- stlen = (int)strlen(st);
+ int stlen = (int)strlen(st);
if (maxlen > 0 && maxlen < stlen) {
stlen = maxlen;
}
@@ -400,11 +387,9 @@ void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
void IDP_ConcatStringC(IDProperty *prop, const char *st)
{
- int newlen;
-
BLI_assert(prop->type == IDP_STRING);
- newlen = prop->len + (int)strlen(st);
+ int newlen = prop->len + (int)strlen(st);
/* we have to remember that prop->len includes the null byte for strings.
* so there's no need to add +1 to the resize function.*/
IDP_ResizeArray(prop, newlen);
@@ -413,13 +398,11 @@ void IDP_ConcatStringC(IDProperty *prop, const char *st)
void IDP_ConcatString(IDProperty *str1, IDProperty *append)
{
- int newlen;
-
BLI_assert(append->type == IDP_STRING);
/* since ->len for strings includes the NULL byte, we have to subtract one or
* we'll get an extra null byte after each concatenation operation.*/
- newlen = str1->len + append->len - 1;
+ int newlen = str1->len + append->len - 1;
IDP_ResizeArray(str1, newlen);
strcat(str1->data.pointer, append->data.pointer);
}
@@ -440,10 +423,8 @@ void IDP_FreeString(IDProperty *prop)
static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag)
{
- IDProperty *newp;
-
BLI_assert(prop->type == IDP_ID);
- newp = idp_generic_copy(prop, flag);
+ IDProperty *newp = idp_generic_copy(prop, flag);
newp->data.pointer = prop->data.pointer;
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
@@ -479,14 +460,12 @@ void IDP_AssignID(IDProperty *prop, ID *id, const int flag)
*/
static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
{
- IDProperty *newp, *link;
-
BLI_assert(prop->type == IDP_GROUP);
- newp = idp_generic_copy(prop, flag);
+ IDProperty *newp = idp_generic_copy(prop, flag);
newp->len = prop->len;
newp->subtype = prop->subtype;
- for (link = prop->data.group.first; link; link = link->next) {
+ LISTBASE_FOREACH (IDProperty *, link, &prop->data.group) {
BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag));
}
@@ -497,13 +476,11 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
* When values name and types match, copy the values, else ignore */
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
{
- IDProperty *other, *prop;
-
BLI_assert(dest->type == IDP_GROUP);
BLI_assert(src->type == IDP_GROUP);
- for (prop = src->data.group.first; prop; prop = prop->next) {
- other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name));
+ LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
+ IDProperty *other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name));
if (other && prop->type == other->type) {
switch (prop->type) {
case IDP_INT:
@@ -526,12 +503,9 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen)
{
- IDProperty *prop_dst, *prop_dst_next;
- const IDProperty *prop_src;
-
- for (prop_dst = dest->data.group.first; prop_dst; prop_dst = prop_dst_next) {
- prop_dst_next = prop_dst->next;
- if ((prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name))) {
+ LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &src->data.group) {
+ const IDProperty *prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name);
+ if (prop_src != NULL) {
/* check of we should replace? */
if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) ||
(do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) &&
@@ -554,12 +528,11 @@ void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_a
*/
void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
{
- IDProperty *loop, *prop;
-
BLI_assert(dest->type == IDP_GROUP);
BLI_assert(src->type == IDP_GROUP);
- for (prop = src->data.group.first; prop; prop = prop->next) {
+ LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
+ IDProperty *loop;
for (loop = dest->data.group.first; loop; loop = loop->next) {
if (STREQ(loop->name, prop->name)) {
BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop));
@@ -612,13 +585,11 @@ void IDP_MergeGroup_ex(IDProperty *dest,
const bool do_overwrite,
const int flag)
{
- IDProperty *prop;
-
BLI_assert(dest->type == IDP_GROUP);
BLI_assert(src->type == IDP_GROUP);
if (do_overwrite) {
- for (prop = src->data.group.first; prop; prop = prop->next) {
+ LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
if (prop->type == IDP_GROUP) {
IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
@@ -633,7 +604,7 @@ void IDP_MergeGroup_ex(IDProperty *dest,
}
}
else {
- for (prop = src->data.group.first; prop; prop = prop->next) {
+ LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
if (prop_exist != NULL) {
if (prop->type == IDP_GROUP) {
@@ -741,10 +712,9 @@ IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *nam
* direct data. */
static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
{
- IDProperty *loop;
-
BLI_assert(prop->type == IDP_GROUP);
- for (loop = prop->data.group.first; loop; loop = loop->next) {
+
+ LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
IDP_FreePropertyContent_ex(loop, do_id_user);
}
BLI_freelistN(&prop->data.group);
@@ -863,14 +833,12 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is
}
return false;
case IDP_GROUP: {
- IDProperty *link1, *link2;
-
if (is_strict && prop1->len != prop2->len) {
return false;
}
- for (link1 = prop1->data.group.first; link1; link1 = link1->next) {
- link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
+ LISTBASE_FOREACH (IDProperty *, link1, &prop1->data.group) {
+ IDProperty *link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
if (!IDP_EqualsProperties_ex(link1, link2, is_strict)) {
return false;
@@ -1158,11 +1126,10 @@ static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer)
/*REMEMBER to set totalen to len in the linking code!!*/
if (prop->data.pointer) {
const IDProperty *array = prop->data.pointer;
- int a;
BLO_write_struct_array(writer, IDProperty, prop->len, array);
- for (a = 0; a < prop->len; a++) {
+ for (int a = 0; a < prop->len; a++) {
IDP_WriteProperty_OnlyData(&array[a], writer);
}
}
@@ -1176,9 +1143,7 @@ static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer)
static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer)
{
- IDProperty *loop;
-
- for (loop = prop->data.group.first; loop; loop = loop->next) {
+ LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
IDP_BlendWrite(writer, loop);
}
}
@@ -1212,13 +1177,11 @@ static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader);
static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader)
{
- IDProperty *array;
-
/* since we didn't save the extra buffer, set totallen to len */
prop->totallen = prop->len;
BLO_read_data_address(reader, &prop->data.pointer);
- array = (IDProperty *)prop->data.pointer;
+ IDProperty *array = (IDProperty *)prop->data.pointer;
/* note!, idp-arrays didn't exist in 2.4x, so the pointer will be cleared
* there's not really anything we can do to correct this, at least don't crash */
@@ -1234,14 +1197,12 @@ static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader)
static void IDP_DirectLinkArray(IDProperty *prop, BlendDataReader *reader)
{
- IDProperty **array;
-
/* since we didn't save the extra buffer, set totallen to len */
prop->totallen = prop->len;
if (prop->subtype == IDP_GROUP) {
BLO_read_pointer_array(reader, &prop->data.pointer);
- array = prop->data.pointer;
+ IDProperty **array = prop->data.pointer;
for (int i = 0; i < prop->len; i++) {
IDP_DirectLinkProperty(array[i], reader);
@@ -1266,12 +1227,11 @@ static void IDP_DirectLinkString(IDProperty *prop, BlendDataReader *reader)
static void IDP_DirectLinkGroup(IDProperty *prop, BlendDataReader *reader)
{
ListBase *lb = &prop->data.group;
- IDProperty *loop;
BLO_read_list(reader, lb);
/*Link child id properties now*/
- for (loop = prop->data.group.first; loop; loop = loop->next) {
+ LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
IDP_DirectLinkProperty(loop, reader);
}
}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index ab57d14d2cf..10f15519ea4 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -338,6 +338,8 @@ IDTypeInfo IDType_ID_IM = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/* prototypes */
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 1ab6e61e20e..d43a0cb3813 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -200,6 +200,8 @@ IDTypeInfo IDType_ID_IP = {
.blend_read_expand = ipo_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/* *************************************************** */
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 433d64a5927..540337b84b3 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -223,6 +223,8 @@ IDTypeInfo IDType_ID_KE = {
.blend_read_expand = shapekey_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 74f78106be5..3d3ade1a529 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -205,6 +205,8 @@ IDTypeInfo IDType_ID_LT = {
.blend_read_expand = lattice_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
int BKE_lattice_index_from_uvw(Lattice *lt, const int u, const int v, const int w)
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 13f76b46570..54c2f5f5565 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -112,6 +112,8 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/* GS reads the memory pointed at in a specific ordering.
@@ -1793,32 +1795,31 @@ static void library_make_local_copying_check(ID *id,
return; /* Already checked, nothing else to do. */
}
- MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->id_used_to_user, id);
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->relations_from_pointers, id);
BLI_gset_insert(loop_tags, id);
- for (; entry != NULL; entry = entry->next) {
-
- /* Used_to_user stores ID pointer, not pointer to ID pointer. */
- ID *par_id = (ID *)entry->id_pointer;
-
+ for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL;
+ from_id_entry = from_id_entry->next) {
/* Our oh-so-beloved 'from' pointers... Those should always be ignored here, since the actual
* relation we want to check is in the other way around. */
- if (entry->usage_flag & IDWALK_CB_LOOPBACK) {
+ if (from_id_entry->usage_flag & IDWALK_CB_LOOPBACK) {
continue;
}
+ ID *from_id = from_id_entry->id_pointer.from;
+
/* Shape-keys are considered 'private' to their owner ID here, and never tagged
* (since they cannot be linked), so we have to switch effective parent to their owner.
*/
- if (GS(par_id->name) == ID_KE) {
- par_id = ((Key *)par_id)->from;
+ if (GS(from_id->name) == ID_KE) {
+ from_id = ((Key *)from_id)->from;
}
- if (par_id->lib == NULL) {
+ if (from_id->lib == NULL) {
/* Local user, early out to avoid some gset querying... */
continue;
}
- if (!BLI_gset_haskey(done_ids, par_id)) {
- if (BLI_gset_haskey(loop_tags, par_id)) {
+ if (!BLI_gset_haskey(done_ids, from_id)) {
+ if (BLI_gset_haskey(loop_tags, from_id)) {
/* We are in a 'dependency loop' of IDs, this does not say us anything, skip it.
* Note that this is the situation that can lead to archipelagoes of linked data-blocks
* (since all of them have non-local users, they would all be duplicated,
@@ -1827,10 +1828,10 @@ static void library_make_local_copying_check(ID *id,
continue;
}
/* Else, recursively check that user ID. */
- library_make_local_copying_check(par_id, loop_tags, id_relations, done_ids);
+ library_make_local_copying_check(from_id, loop_tags, id_relations, done_ids);
}
- if (par_id->tag & LIB_TAG_DOIT) {
+ if (from_id->tag & LIB_TAG_DOIT) {
/* This user will be fully local in future, so far so good,
* nothing to do here but check next user. */
}
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index e4094c48368..7ccf53546b8 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -368,23 +368,50 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain)
return success;
}
-static bool lib_override_hierarchy_recursive_tag(Main *bmain,
- ID *id,
- const uint tag,
- const uint missing_tag,
- Library *override_group_lib_reference)
+typedef struct LibOverrideGroupTagData {
+ ID *id_root;
+ uint tag;
+ uint missing_tag;
+} LibOverrideGroupTagData;
+
+static int lib_override_linked_group_tag_cb(LibraryIDLinkCallbackData *cb_data)
{
- void **entry_vp = BLI_ghash_lookup_p(bmain->relations->id_user_to_used, id);
- if (entry_vp == NULL) {
- /* Already processed. */
- return (id->tag & tag) != 0;
+ if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK)) {
+ return IDWALK_RET_STOP_RECURSION;
+ }
+
+ LibOverrideGroupTagData *data = cb_data->user_data;
+ const uint tag = data->tag;
+ const uint missing_tag = data->missing_tag;
+
+ ID *id_root = data->id_root;
+ Library *library_root = id_root->lib;
+ ID *id = *cb_data->id_pointer;
+ ID *id_owner = cb_data->id_owner;
+
+ BLI_assert(id_owner == cb_data->id_self);
+
+ if (ELEM(id, NULL, id_owner)) {
+ return IDWALK_RET_NOP;
+ }
+
+ BLI_assert(id_owner->lib == library_root);
+
+ if (*(uint *)&id->tag & (tag | missing_tag)) {
+ /* Already processed and tagged, nothing else to do here. */
+ return IDWALK_RET_STOP_RECURSION;
+ }
+
+ if (id->lib != library_root) {
+ /* We do not override data-blocks from other libraries, nor do we process them. */
+ return IDWALK_RET_STOP_RECURSION;
}
- /* Note: in case some reference ID is missing from linked data (and therefore its override uses
- * a placeholder as reference), use `missing_tag` instead of `tag` for this override. */
- if (override_group_lib_reference != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
- id->override_library->reference->lib == override_group_lib_reference) {
- if (id->override_library->reference->tag & LIB_TAG_MISSING) {
+ /* We tag all collections and objects for override. And we also tag all other data-blocks which
+ * would use one of those.
+ * Note: missing IDs (aka placeholders) are never overridden. */
+ if (ELEM(GS(id->name), ID_OB, ID_GR)) {
+ if ((id->tag & LIB_TAG_MISSING)) {
id->tag |= missing_tag;
}
else {
@@ -392,94 +419,103 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
}
}
+ return IDWALK_RET_NOP;
+}
+
+/* Tag all IDs in dependency relationships within an override hierarchy/group.
+ *
+ * Note: this is typically called to complete `lib_override_linked_group_tag()`.
+ * Note: BMain's relations mapping won't be valid anymore after that call.
+ */
+static bool lib_override_hierarchy_dependencies_recursive_tag(Main *bmain,
+ ID *id,
+ const uint tag,
+ const uint missing_tag)
+{
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
+ BLI_assert(entry != NULL);
+
+ if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
+ /* This ID has already been processed. */
+ return (*(uint *)&id->tag & tag) != 0;
+ }
/* This way we won't process again that ID, should we encounter it again through another
- * relationship hierarchy.
- * Note that this does not free any memory from relations, so we can still use the entries.
- */
- BKE_main_relations_ID_remove(bmain, id);
+ * relationship hierarchy. */
+ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
- for (MainIDRelationsEntry *entry = *entry_vp; entry != NULL; entry = entry->next) {
- if ((entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ to_id_entry = to_id_entry->next) {
+ if ((to_id_entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
/* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers) as
* actual dependencies. */
continue;
}
/* We only consider IDs from the same library. */
- if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) {
- if (lib_override_hierarchy_recursive_tag(
- bmain, *entry->id_pointer, tag, missing_tag, override_group_lib_reference) &&
- override_group_lib_reference == NULL) {
+ ID *to_id = *to_id_entry->id_pointer.to;
+ if (to_id != NULL && to_id->lib == id->lib) {
+ if (lib_override_hierarchy_dependencies_recursive_tag(bmain, to_id, tag, missing_tag)) {
id->tag |= tag;
}
}
}
- return (id->tag & tag) != 0;
+ return (*(uint *)&id->tag & tag) != 0;
}
-/**
- * Tag all IDs in given \a bmain that are being used by given \a id_root ID or its dependencies,
- * recursively.
- * It detects and tag only chains of dependencies marked at both ends by given tag.
+/* This will tag at least all 'boundary' linked IDs for a potential override group.
*
- * This will include all local IDs, and all IDs from the same library as the \a id_root.
+ * Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to
+ * complete tagging of all dependencies within the override group.
*
- * \param id_root: The root of the hierarchy of dependencies to be tagged.
- * \param do_create_main_relashionships: Whether main relations needs to be created or already
- * exist (in any case, they will be freed by this function).
+ * We currently only consider Collections and Objects (that are not used as bone shapes) as valid
+ * boundary IDs to define an override group.
*/
-void BKE_lib_override_library_dependencies_tag(Main *bmain,
- ID *id_root,
- const uint tag,
- const bool do_create_main_relashionships)
+static void lib_override_linked_group_tag(
+ Main *bmain, ID *id, const uint tag, const uint missing_tag, const bool create_bmain_relations)
{
- if (do_create_main_relashionships) {
+ if (create_bmain_relations) {
BKE_main_relations_create(bmain, 0);
}
- /* We tag all intermediary data-blocks in-between two overridden ones (e.g. if a shape-key
- * has a driver using an armature object's bone, we need to override the shape-key/obdata,
- * the objects using them, etc.) */
- lib_override_hierarchy_recursive_tag(bmain, id_root, tag, 0, NULL);
-
- BKE_main_relations_free(bmain);
-}
+ if (ELEM(GS(id->name), ID_OB, ID_GR)) {
+ LibOverrideGroupTagData data = {.id_root = id, .tag = tag, .missing_tag = missing_tag};
+ /* Tag all collections and objects. */
+ BKE_library_foreach_ID_link(
+ bmain, id, lib_override_linked_group_tag_cb, &data, IDWALK_READONLY | IDWALK_RECURSE);
-/**
- * Tag all IDs in given \a bmain that are part of the same \a id_root liboverride ID group.
- * That is, all other liboverride IDs (in)directly used by \a is_root one, and sharing the same
- * library for their reference IDs.
- *
- * \param id_root: The root of the hierarchy of liboverride dependencies to be tagged.
- * \param do_create_main_relashionships: Whether main relations needs to be created or already
- * exist (in any case, they will be freed by this function).
- */
-void BKE_lib_override_library_override_group_tag(Main *bmain,
- ID *id_root,
- const uint tag,
- const uint missing_tag,
- const bool do_create_main_relashionships)
-{
- if (do_create_main_relashionships) {
- BKE_main_relations_create(bmain, 0);
+ /* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitly
+ * override those. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & tag)) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ if (pchan->custom != NULL) {
+ pchan->custom->id.tag &= ~(tag | missing_tag);
+ }
+ }
+ }
+ }
}
- /* We tag all liboverride data-blocks from the same library as reference one,
- * being used by the root ID. */
- lib_override_hierarchy_recursive_tag(
- bmain, id_root, tag, missing_tag, id_root->override_library->reference->lib);
+ lib_override_hierarchy_dependencies_recursive_tag(bmain, id, tag, missing_tag);
- BKE_main_relations_free(bmain);
+ if (create_bmain_relations) {
+ BKE_main_relations_free(bmain);
+ }
}
-static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_data)
+static int lib_override_local_group_tag_cb(LibraryIDLinkCallbackData *cb_data)
{
- if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK)) {
+ if (cb_data->cb_flag &
+ (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
return IDWALK_RET_STOP_RECURSION;
}
- ID *id_root = cb_data->user_data;
- Library *library_root = id_root->lib;
+ LibOverrideGroupTagData *data = cb_data->user_data;
+ const uint tag = data->tag;
+ const uint missing_tag = data->missing_tag;
+
+ ID *id_root = data->id_root;
+ Library *library_reference_root = id_root->override_library->reference->lib;
ID *id = *cb_data->id_pointer;
ID *id_owner = cb_data->id_owner;
@@ -489,62 +525,69 @@ static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_da
return IDWALK_RET_NOP;
}
- BLI_assert(id->lib != NULL);
- BLI_assert(id_owner->lib == library_root);
-
- if (id->tag & LIB_TAG_DOIT) {
+ if (*(uint *)&id->tag & (tag | missing_tag)) {
/* Already processed and tagged, nothing else to do here. */
return IDWALK_RET_STOP_RECURSION;
}
- if (id->lib != library_root) {
+ if (!ID_IS_OVERRIDE_LIBRARY(id) || ID_IS_LINKED(id)) {
+ /* Fully local, or linked ID, those are never part of a local override group. */
+ return IDWALK_RET_STOP_RECURSION;
+ }
+
+ /* NOTE: Since we rejected embedded data too at the beginning of this function, id should only be
+ * a real override now.
+ *
+ * However, our usual trouble maker, Key, is not considered as an embedded ID currently, yet it
+ * is never a real override either. Enjoy. */
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ return IDWALK_RET_NOP;
+ }
+
+ if (id->override_library->reference->lib != library_reference_root) {
/* We do not override data-blocks from other libraries, nor do we process them. */
return IDWALK_RET_STOP_RECURSION;
}
- /* We tag all collections and objects for override. And we also tag all other data-blocks which
- * would use one of those.
- * Note: missing IDs (aka placeholders) are never overridden. */
- if (ELEM(GS(id->name), ID_OB, ID_GR) && !(id->tag & LIB_TAG_MISSING)) {
- id->tag |= LIB_TAG_DOIT;
+ if (id->override_library->reference->tag & LIB_TAG_MISSING) {
+ id->tag |= missing_tag;
+ }
+ else {
+ id->tag |= tag;
}
return IDWALK_RET_NOP;
}
+/* This will tag at least all 'boundary' linked IDs for a potential override group.
+ *
+ * Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to
+ * complete tagging of all dependencies within the override group.
+ *
+ * We currently only consider Collections and Objects (that are not used as bone shapes) as valid
+ * boundary IDs to define an override group.
+ */
+static void lib_override_local_group_tag(Main *bmain,
+ ID *id,
+ const uint tag,
+ const uint missing_tag)
+{
+ LibOverrideGroupTagData data = {.id_root = id, .tag = tag, .missing_tag = missing_tag};
+ /* Tag all local overrides in id_root's group. */
+ BKE_library_foreach_ID_link(
+ bmain, id, lib_override_local_group_tag_cb, &data, IDWALK_READONLY | IDWALK_RECURSE);
+}
+
static bool lib_override_library_create_do(Main *bmain, ID *id_root)
{
id_root->tag |= LIB_TAG_DOIT;
BKE_main_relations_create(bmain, 0);
- if (ELEM(GS(id_root->name), ID_OB, ID_GR)) {
- /* Tag all collections and objects. */
- BKE_library_foreach_ID_link(bmain,
- id_root,
- lib_override_library_make_tag_ids_cb,
- id_root,
- IDWALK_READONLY | IDWALK_RECURSE);
-
- /* Then, we remove (untag) bone shape objects, you shall never want to override those
- * (hopefully). */
- LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & LIB_TAG_DOIT)) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
- if (pchan->custom != NULL) {
- pchan->custom->id.tag &= ~LIB_TAG_DOIT;
- }
- }
- }
- }
- }
+ lib_override_linked_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING, false);
+ lib_override_hierarchy_dependencies_recursive_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING);
- /* Now tag all non-object/collection IDs 'in-between' two tagged ones, as those are part of an
- * override chain and therefore also need to be overridden.
- * One very common cases are e.g. drivers on geometry or materials of an overridden object, that
- * are using another overridden object as parameter. */
- /* Note that this call will also free the main relations data we created above. */
- BKE_lib_override_library_dependencies_tag(bmain, id_root, LIB_TAG_DOIT, false);
+ BKE_main_relations_free(bmain);
return BKE_lib_override_library_create_from_tag(bmain);
}
@@ -737,14 +780,14 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
- /* Tag all collections and objects, as well as other IDs using them. */
id_root->tag |= LIB_TAG_DOIT;
ID *id_root_reference = id_root->override_library->reference;
- /* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, and tag
- * linked reference ones to be overridden again. */
- BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING, true);
+ lib_override_local_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING);
+
+ lib_override_linked_group_tag(bmain, id_root_reference, LIB_TAG_DOIT, LIB_TAG_MISSING, true);
+ /* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides. */
GHash *linkedref_to_old_override = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
ID *id;
@@ -755,7 +798,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
* same linked ID in a same hierarchy. */
if (!BLI_ghash_haskey(linkedref_to_old_override, id->override_library->reference)) {
BLI_ghash_insert(linkedref_to_old_override, id->override_library->reference, id);
- id->override_library->reference->tag |= LIB_TAG_DOIT;
+ BLI_assert(id->override_library->reference->tag & LIB_TAG_DOIT);
}
}
}
@@ -765,7 +808,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
/* Note that this call also remaps all pointers of tagged IDs from old override IDs to new
* override IDs (including within the old overrides themselves, since those are tagged too
* above). */
- const bool success = lib_override_library_create_do(bmain, id_root_reference);
+ const bool success = BKE_lib_override_library_create_from_tag(bmain);
if (!success) {
return success;
@@ -828,6 +871,23 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
RNA_id_pointer_create(id_override_old, &rnaptr_src);
RNA_id_pointer_create(id_override_new, &rnaptr_dst);
+ /* We remove any operation tagged with `IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE`,
+ * that way the potentially new pointer will be properly kept, when old one is still valid
+ * too (typical case: assigning new ID to some usage, while old one remains used elsewhere
+ * in the override hierarchy). */
+ LISTBASE_FOREACH_MUTABLE (
+ IDOverrideLibraryProperty *, op, &id_override_new->override_library->properties) {
+ LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) {
+ lib_override_library_property_operation_clear(opop);
+ BLI_freelinkN(&op->operations, opop);
+ }
+ }
+ if (BLI_listbase_is_empty(&op->operations)) {
+ BKE_lib_override_library_property_delete(id_override_new->override_library, op);
+ }
+ }
+
RNA_struct_override_apply(
bmain, &rnaptr_dst, &rnaptr_src, NULL, id_override_new->override_library);
}
@@ -900,7 +960,7 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
id_root->tag |= LIB_TAG_DOIT;
/* Tag all library overrides in the chains of dependencies from the given root one. */
- BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_DOIT, true);
+ lib_override_local_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_DOIT);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
@@ -1619,31 +1679,37 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *i
return;
}
- void **entry_pp = BLI_ghash_lookup(bmain->relations->id_user_to_used, id_root);
- if (entry_pp == NULL) {
- /* Already processed. */
+ void **entry_vp = BLI_ghash_lookup_p(bmain->relations->relations_from_pointers, id_root);
+ if (entry_vp == NULL) {
+ /* This ID is not used by nor using any other ID. */
+ lib_override_library_id_reset_do(bmain, id_root);
+ return;
+ }
+
+ MainIDRelationsEntry *entry = *entry_vp;
+ if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
+ /* This ID has already been processed. */
return;
}
lib_override_library_id_reset_do(bmain, id_root);
/* This way we won't process again that ID, should we encounter it again through another
- * relationship hierarchy.
- * Note that this does not free any memory from relations, so we can still use the entries.
- */
- BKE_main_relations_ID_remove(bmain, id_root);
+ * relationship hierarchy. */
+ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
- for (MainIDRelationsEntry *entry = *entry_pp; entry != NULL; entry = entry->next) {
- if ((entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ to_id_entry = to_id_entry->next) {
+ if ((to_id_entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
/* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers) as
* actual dependencies. */
continue;
}
/* We only consider IDs from the same library. */
- if (entry->id_pointer != NULL) {
- ID *id_entry = *entry->id_pointer;
- if (id_entry->override_library != NULL) {
- lib_override_library_id_hierarchy_recursive_reset(bmain, id_entry);
+ if (*to_id_entry->id_pointer.to != NULL) {
+ ID *to_id = *to_id_entry->id_pointer.to;
+ if (to_id->override_library != NULL) {
+ lib_override_library_id_hierarchy_recursive_reset(bmain, to_id);
}
}
}
@@ -1922,7 +1988,9 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
ID *local)
{
if (ID_IS_OVERRIDE_LIBRARY_TEMPLATE(local) || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(local)) {
- /* This is actually purely local data with an override template, nothing to do here! */
+ /* This is actually purely local data with an override template, or one of those embedded IDs
+ * (root node trees, master collections or shapekeys) that cannot have their own override.
+ * Nothing to do here! */
return NULL;
}
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index e687e94073d..8be26fc8547 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -237,9 +237,12 @@ static void library_foreach_ID_link(Main *bmain,
* but we might as well use it (Main->relations is always assumed valid,
* it's responsibility of code creating it to free it,
* especially if/when it starts modifying Main database). */
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
- for (; entry != NULL; entry = entry->next) {
- BKE_lib_query_foreachid_process(&data, entry->id_pointer, entry->usage_flag);
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers,
+ id);
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ to_id_entry = to_id_entry->next) {
+ BKE_lib_query_foreachid_process(
+ &data, to_id_entry->id_pointer.to, to_id_entry->usage_flag);
}
continue;
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 6a560d51362..d2f1196d804 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -84,6 +84,8 @@ IDTypeInfo IDType_ID_LI = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c
index a47a0c043ff..4a2afb7f5e6 100644
--- a/source/blender/blenkernel/intern/light.c
+++ b/source/blender/blenkernel/intern/light.c
@@ -209,6 +209,8 @@ IDTypeInfo IDType_ID_LA = {
.blend_read_expand = light_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
Light *BKE_light_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 0553c070fdf..4ef3b8c3237 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -107,6 +107,8 @@ IDTypeInfo IDType_ID_LP = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
void BKE_lightprobe_type_set(LightProbe *probe, const short lightprobe_type)
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 8542959d4b0..283e2a94732 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -767,6 +767,8 @@ IDTypeInfo IDType_ID_LS = {
.blend_read_expand = linestyle_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
static const char *modifier_name[LS_MODIFIER_NUM] = {
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index 4b577ccec2c..4a7636926e6 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -211,35 +211,51 @@ void BKE_main_unlock(struct Main *bmain)
static int main_relations_create_idlink_cb(LibraryIDLinkCallbackData *cb_data)
{
- MainIDRelations *rel = cb_data->user_data;
+ MainIDRelations *bmain_relations = cb_data->user_data;
ID *id_self = cb_data->id_self;
ID **id_pointer = cb_data->id_pointer;
const int cb_flag = cb_data->cb_flag;
if (*id_pointer) {
- MainIDRelationsEntry *entry, **entry_p;
-
- entry = BLI_mempool_alloc(rel->entry_pool);
- if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) {
- entry->next = *entry_p;
- }
- else {
- entry->next = NULL;
+ MainIDRelationsEntry **entry_p;
+
+ /* Add `id_pointer` as child of `id_self`. */
+ {
+ if (!BLI_ghash_ensure_p(
+ bmain_relations->relations_from_pointers, id_self, (void ***)&entry_p)) {
+ *entry_p = MEM_callocN(sizeof(**entry_p), __func__);
+ (*entry_p)->session_uuid = id_self->session_uuid;
+ }
+ else {
+ BLI_assert((*entry_p)->session_uuid == id_self->session_uuid);
+ }
+ MainIDRelationsEntryItem *to_id_entry = BLI_mempool_alloc(bmain_relations->entry_items_pool);
+ to_id_entry->next = (*entry_p)->to_ids;
+ to_id_entry->id_pointer.to = id_pointer;
+ to_id_entry->session_uuid = (*id_pointer != NULL) ? (*id_pointer)->session_uuid :
+ MAIN_ID_SESSION_UUID_UNSET;
+ to_id_entry->usage_flag = cb_flag;
+ (*entry_p)->to_ids = to_id_entry;
}
- entry->id_pointer = id_pointer;
- entry->usage_flag = cb_flag;
- *entry_p = entry;
- entry = BLI_mempool_alloc(rel->entry_pool);
- if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) {
- entry->next = *entry_p;
- }
- else {
- entry->next = NULL;
+ /* Add `id_self` as parent of `id_pointer`. */
+ if (*id_pointer != NULL) {
+ if (!BLI_ghash_ensure_p(
+ bmain_relations->relations_from_pointers, *id_pointer, (void ***)&entry_p)) {
+ *entry_p = MEM_callocN(sizeof(**entry_p), __func__);
+ (*entry_p)->session_uuid = (*id_pointer)->session_uuid;
+ }
+ else {
+ BLI_assert((*entry_p)->session_uuid == (*id_pointer)->session_uuid);
+ }
+ MainIDRelationsEntryItem *from_id_entry = BLI_mempool_alloc(
+ bmain_relations->entry_items_pool);
+ from_id_entry->next = (*entry_p)->from_ids;
+ from_id_entry->id_pointer.from = id_self;
+ from_id_entry->session_uuid = id_self->session_uuid;
+ from_id_entry->usage_flag = cb_flag;
+ (*entry_p)->from_ids = from_id_entry;
}
- entry->id_pointer = (ID **)id_self;
- entry->usage_flag = cb_flag;
- *entry_p = entry;
}
return IDWALK_RET_NOP;
@@ -253,64 +269,47 @@ void BKE_main_relations_create(Main *bmain, const short flag)
}
bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__);
- bmain->relations->id_used_to_user = BLI_ghash_new(
- BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- bmain->relations->id_user_to_used = BLI_ghash_new(
+ bmain->relations->relations_from_pointers = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- bmain->relations->entry_pool = BLI_mempool_create(
- sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP);
+ bmain->relations->entry_items_pool = BLI_mempool_create(
+ sizeof(MainIDRelationsEntryItem), 128, 128, BLI_MEMPOOL_NOP);
+
+ bmain->relations->flag = flag;
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
const int idwalk_flag = IDWALK_READONLY |
((flag & MAINIDRELATIONS_INCLUDE_UI) != 0 ? IDWALK_INCLUDE_UI : 0);
+
+ /* Ensure all IDs do have an entry, even if they are not connected to any other. */
+ MainIDRelationsEntry **entry_p;
+ if (!BLI_ghash_ensure_p(bmain->relations->relations_from_pointers, id, (void ***)&entry_p)) {
+ *entry_p = MEM_callocN(sizeof(**entry_p), __func__);
+ (*entry_p)->session_uuid = id->session_uuid;
+ }
+ else {
+ BLI_assert((*entry_p)->session_uuid == id->session_uuid);
+ }
+
BKE_library_foreach_ID_link(
NULL, id, main_relations_create_idlink_cb, bmain->relations, idwalk_flag);
}
FOREACH_MAIN_ID_END;
-
- bmain->relations->flag = flag;
}
void BKE_main_relations_free(Main *bmain)
{
- if (bmain->relations) {
- if (bmain->relations->id_used_to_user) {
- BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL);
- }
- if (bmain->relations->id_user_to_used) {
- BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL);
+ if (bmain->relations != NULL) {
+ if (bmain->relations->relations_from_pointers != NULL) {
+ BLI_ghash_free(bmain->relations->relations_from_pointers, NULL, MEM_freeN);
}
- BLI_mempool_destroy(bmain->relations->entry_pool);
+ BLI_mempool_destroy(bmain->relations->entry_items_pool);
MEM_freeN(bmain->relations);
bmain->relations = NULL;
}
}
/**
- * Remove an ID from the relations (the two entries for that ID, not the ID from entries in other
- * IDs' relationships).
- *
- * Does not free any allocated memory.
- * Allows to use those relations as a way to mark an ID as already processed, without requiring any
- * additional tagging or GSet.
- * Obviously, relations should be freed after use then, since this will make them fully invalid.
- */
-void BKE_main_relations_ID_remove(Main *bmain, ID *id)
-{
- if (bmain->relations) {
- /* Note: we do not free the entries from the mempool, those will be dealt with when finally
- * freeing the whole relations. */
- if (bmain->relations->id_used_to_user) {
- BLI_ghash_remove(bmain->relations->id_used_to_user, id, NULL, NULL);
- }
- if (bmain->relations->id_user_to_used) {
- BLI_ghash_remove(bmain->relations->id_user_to_used, id, NULL, NULL);
- }
- }
-}
-
-/**
* Create a GSet storing all IDs present in given \a bmain, by their pointers.
*
* \param gset: If not NULL, given GSet will be extended with IDs from given \a bmain,
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 04fec1e57c4..83d9449934c 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -270,6 +270,8 @@ IDTypeInfo IDType_ID_MSK = {
.blend_read_expand = mask_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
static struct {
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index e892a3f4d53..70906065347 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -274,6 +274,8 @@ IDTypeInfo IDType_ID_MA = {
.blend_read_expand = material_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
void BKE_gpencil_material_attr_init(Material *ma)
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 65ec91c57cf..849c7ef57fb 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -204,6 +204,8 @@ IDTypeInfo IDType_ID_MB = {
.blend_read_expand = metaball_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/* Functions */
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 051c7e56ef9..1550401cc9c 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -263,7 +263,7 @@ static void build_bvh_spatial(PROCESS *process,
* BASED AT CODE (but mostly rewritten) :
* C code from the article
* "An Implicit Surface Polygonizer"
- * by Jules Bloomenthal, jbloom@beauty.gmu.edu
+ * by Jules Bloomenthal <jbloom@beauty.gmu.edu>
* in "Graphics Gems IV", Academic Press, 1994
*
* Authored by Jules Bloomenthal, Xerox PARC.
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 950885d2114..02588bf144e 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -364,6 +364,8 @@ IDTypeInfo IDType_ID_ME = {
.blend_read_expand = mesh_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
enum {
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index b872c91cc29..175caf85b49 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -362,6 +362,8 @@ IDTypeInfo IDType_ID_MC = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/*********************** movieclip buffer loaders *************************/
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 441da8b134a..45ac20ef154 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -781,7 +781,7 @@ static DerivedMesh *subsurf_dm_create_local(Scene *scene,
smd.levels = smd.renderLevels = lvl;
smd.quality = 3;
if (!is_plain_uv) {
- smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
+ smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
}
else {
smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE;
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 76885eadaae..247bfafc099 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -888,6 +888,8 @@ IDTypeInfo IDType_ID_NT = {
.blend_read_expand = ntree_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
@@ -2149,7 +2151,7 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
ntree->update |= NTREE_UPDATE_LINKS;
}
-bool nodeLinkIsHidden(bNodeLink *link)
+bool nodeLinkIsHidden(const bNodeLink *link)
{
return nodeSocketIsHidden(link->fromsock) || nodeSocketIsHidden(link->tosock);
}
@@ -2200,7 +2202,7 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
}
}
-void nodeToView(bNode *node, float x, float y, float *rx, float *ry)
+void nodeToView(const bNode *node, float x, float y, float *rx, float *ry)
{
if (node->parent) {
nodeToView(node->parent, x + node->locx, y + node->locy, rx, ry);
@@ -2211,7 +2213,7 @@ void nodeToView(bNode *node, float x, float y, float *rx, float *ry)
}
}
-void nodeFromView(bNode *node, float x, float y, float *rx, float *ry)
+void nodeFromView(const bNode *node, float x, float y, float *rx, float *ry)
{
if (node->parent) {
nodeFromView(node->parent, x, y, rx, ry);
@@ -2224,10 +2226,10 @@ void nodeFromView(bNode *node, float x, float y, float *rx, float *ry)
}
}
-bool nodeAttachNodeCheck(bNode *node, bNode *parent)
+bool nodeAttachNodeCheck(const bNode *node, const bNode *parent)
{
- for (bNode *parent_recurse = node; parent_recurse; parent_recurse = parent_recurse->parent) {
- if (parent_recurse == parent) {
+ for (const bNode *parent_iter = node; parent_iter; parent_iter = parent_iter->parent) {
+ if (parent_iter == parent) {
return true;
}
}
@@ -2317,8 +2319,6 @@ void nodePositionPropagate(bNode *node)
bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
{
- bNodeTree *ntree;
-
/* trees are created as local trees for compositor, material or texture nodes,
* node groups and other tree types are created as library data.
*/
@@ -2327,7 +2327,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
if (is_embedded) {
flag |= LIB_ID_CREATE_NO_MAIN;
}
- ntree = BKE_libblock_alloc(bmain, ID_NT, name, flag);
+ bNodeTree *ntree = BKE_libblock_alloc(bmain, ID_NT, name, flag);
if (is_embedded) {
ntree->id.flag |= LIB_EMBEDDED_DATA;
}
@@ -2362,7 +2362,7 @@ bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree)
* using BKE_node_preview_init_tree to set up previews for a whole node tree in advance.
* This should be left more to the individual node tree implementations.
*/
-int BKE_node_preview_used(bNode *node)
+bool BKE_node_preview_used(const bNode *node)
{
/* XXX check for closed nodes? */
return (node->typeinfo->flag & NODE_PREVIEW) != 0;
@@ -2959,9 +2959,9 @@ ID *BKE_node_tree_find_owner_ID(Main *bmain, struct bNodeTree *ntree)
return NULL;
}
-bool ntreeNodeExists(bNodeTree *ntree, bNode *testnode)
+bool ntreeNodeExists(const bNodeTree *ntree, const bNode *testnode)
{
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (const bNode *, node, &ntree->nodes) {
if (node == testnode) {
return true;
}
@@ -2969,9 +2969,9 @@ bool ntreeNodeExists(bNodeTree *ntree, bNode *testnode)
return false;
}
-bool ntreeOutputExists(bNode *node, bNodeSocket *testsock)
+bool ntreeOutputExists(const bNode *node, const bNodeSocket *testsock)
{
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ LISTBASE_FOREACH (const bNodeSocket *, sock, &node->outputs) {
if (sock == testsock) {
return true;
}
@@ -3246,7 +3246,7 @@ static void ntree_interface_type_create(bNodeTree *ntree)
}
}
-StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create)
+StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, bool create)
{
if (ntree->interface_type) {
/* strings are generated from base string + ID name, sizes are sufficient */
@@ -3333,7 +3333,7 @@ bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup)
return false;
}
-bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to)
+bNodeLink *nodeFindLink(bNodeTree *ntree, const bNodeSocket *from, const bNodeSocket *to)
{
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
if (link->fromsock == from && link->tosock == to) {
@@ -3346,10 +3346,10 @@ bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to)
return NULL;
}
-int nodeCountSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
+int nodeCountSocketLinks(const bNodeTree *ntree, const bNodeSocket *sock)
{
int tot = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ LISTBASE_FOREACH (const bNodeLink *, link, &ntree->links) {
if (link->fromsock == sock || link->tosock == sock) {
tot++;
}
@@ -3515,7 +3515,7 @@ void nodeSetActive(bNodeTree *ntree, bNode *node)
}
}
-int nodeSocketIsHidden(bNodeSocket *sock)
+int nodeSocketIsHidden(const bNodeSocket *sock)
{
return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0);
}
@@ -3530,7 +3530,7 @@ void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available)
}
}
-int nodeSocketLinkLimit(struct bNodeSocket *sock)
+int nodeSocketLinkLimit(const bNodeSocket *sock)
{
bNodeSocketType *stype = sock->typeinfo;
if (stype != NULL && stype->use_link_limits_of_type) {
@@ -3574,7 +3574,7 @@ typedef struct bNodeClipboard {
static bNodeClipboard node_clipboard = {{NULL}};
-void BKE_node_clipboard_init(struct bNodeTree *ntree)
+void BKE_node_clipboard_init(const struct bNodeTree *ntree)
{
node_clipboard.type = ntree->type;
}
@@ -3718,11 +3718,11 @@ static bNodeInstanceKey node_hash_int_str(bNodeInstanceKey hash, const char *str
return hash;
}
-bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, bNodeTree *ntree, bNode *node)
+bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key,
+ const bNodeTree *ntree,
+ const bNode *node)
{
- bNodeInstanceKey key;
-
- key = node_hash_int_str(parent_key, ntree->id.name + 2);
+ bNodeInstanceKey key = node_hash_int_str(parent_key, ntree->id.name + 2);
if (node) {
key = node_hash_int_str(key, node->name);
@@ -4749,6 +4749,8 @@ static void registerGeometryNodes(void)
register_node_type_geo_attribute_color_ramp();
register_node_type_geo_point_rotate();
register_node_type_geo_align_rotation_to_vector();
+ register_node_type_geo_sample_texture();
+ register_node_type_geo_points_to_volume();
}
static void registerFunctionNodes(void)
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 155508e9caa..381823754e9 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1118,6 +1118,20 @@ static void object_blend_read_expand(BlendExpander *expander, ID *id)
}
}
+static void object_lib_override_apply_post(ID *id_dst, ID *UNUSED(id_src))
+{
+ Object *object = (Object *)id_dst;
+
+ ListBase pidlist;
+ BKE_ptcache_ids_from_object(&pidlist, object, NULL, 0);
+ LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
+ LISTBASE_FOREACH (PointCache *, point_cache, pid->ptcaches) {
+ point_cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
+ }
+ }
+ BLI_freelistN(&pidlist);
+}
+
IDTypeInfo IDType_ID_OB = {
.id_code = ID_OB,
.id_filter = FILTER_ID_OB,
@@ -1141,6 +1155,8 @@ IDTypeInfo IDType_ID_OB = {
.blend_read_expand = object_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = object_lib_override_apply_post,
};
void BKE_object_workob_clear(Object *workob)
@@ -1506,11 +1522,11 @@ bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData
/**
* Copy the whole stack of modifiers from one object into another.
*
- * \warning **Does not** clear modifier stack and related data (particle systems, softbody,
+ * \warning **Does not** clear modifier stack and related data (particle systems, soft-body,
* etc.) in `ob_dst`, if needed calling code must do it.
*
- * @param do_copy_all If true, even modifiers that should not suport copying (like Hook one) will
- * be duplicated.
+ * \param do_copy_all: If true, even modifiers that should not support copying (like Hook one)
+ * will be duplicated.
*/
bool BKE_object_modifier_stack_copy(Object *ob_dst,
const Object *ob_src,
@@ -3527,9 +3543,6 @@ static void solve_parenting(
}
}
-/**
- * \note scene is the active scene while actual_scene is the scene the object resides in.
- */
static void object_where_is_calc_ex(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 1d79f871fa2..69442b7646c 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -225,7 +225,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
case OB_GPENCIL: {
BKE_gpencil_prepare_eval_data(depsgraph, scene, ob);
BKE_gpencil_modifiers_calc(depsgraph, scene, ob);
- BKE_gpencil_update_layer_parent(depsgraph, ob);
+ BKE_gpencil_update_layer_transforms(depsgraph, ob);
break;
}
case OB_HAIR:
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 1d62a1cce2a..d2f4d0702ed 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -140,7 +140,7 @@ static void compute_eigenstuff(struct OceanResult *ocr, float jxx, float jzz, fl
* instead of Complex.h
* in fftw.h "fftw_complex" typedefed as double[2]
* below you can see functions are needed to work with such complex numbers.
- * */
+ */
static void init_complex(fftw_complex cmpl, float real, float image)
{
cmpl[0] = real;
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 4eecf3a3a87..92dea0b4601 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -158,6 +158,8 @@ IDTypeInfo IDType_ID_PAL = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = palette_undo_preserve,
+
+ .lib_override_apply_post = NULL,
};
static void paint_curve_copy_data(Main *UNUSED(bmain),
@@ -221,6 +223,8 @@ IDTypeInfo IDType_ID_PC = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100};
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 335913c9b8e..ec3b6198d7c 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -511,6 +511,8 @@ IDTypeInfo IDType_ID_PA = {
.blend_read_expand = particle_settings_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT];
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 7bd14e80333..b9ff2a1179d 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -190,6 +190,8 @@ IDTypeInfo IDType_ID_PT = {
/* blend_read_expand */ pointcloud_blend_read_expand,
/* blend_read_undo_preserve */ nullptr,
+
+ /* lib_override_apply_post */ nullptr,
};
static void pointcloud_random(PointCloud *pointcloud)
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index b19b0e684b2..0ce5240b17d 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -1689,6 +1689,19 @@ static void scene_undo_preserve(BlendLibReader *reader, ID *id_new, ID *id_old)
}
}
+static void scene_lib_override_apply_post(ID *id_dst, ID *UNUSED(id_src))
+{
+ Scene *scene = (Scene *)id_dst;
+
+ if (scene->rigidbody_world != NULL) {
+ PTCacheID pid;
+ BKE_ptcache_id_from_rigidbody(&pid, NULL, scene->rigidbody_world);
+ LISTBASE_FOREACH (PointCache *, point_cache, pid.ptcaches) {
+ point_cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
+ }
+ }
+}
+
IDTypeInfo IDType_ID_SCE = {
.id_code = ID_SCE,
.id_filter = FILTER_ID_SCE,
@@ -1714,6 +1727,8 @@ IDTypeInfo IDType_ID_SCE = {
.blend_read_expand = scene_blend_read_expand,
.blend_read_undo_preserve = scene_undo_preserve,
+
+ .lib_override_apply_post = scene_lib_override_apply_post,
};
const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE";
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 52c41c9fd05..80a83aecea8 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -315,6 +315,8 @@ IDTypeInfo IDType_ID_SCR = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/* ************ Spacetype/regiontype handling ************** */
@@ -1599,8 +1601,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
BLO_read_list(reader, &snode->treepath);
snode->edittree = NULL;
- snode->iofsd = NULL;
- BLI_listbase_clear(&snode->linkdrag);
+ snode->runtime = NULL;
}
else if (sl->spacetype == SPACE_TEXT) {
SpaceText *st = (SpaceText *)sl;
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 14e6ce63023..4e0a08455e6 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -173,6 +173,8 @@ IDTypeInfo IDType_ID_SIM = {
/* blend_read_expand */ simulation_blend_read_expand,
/* blend_read_undo_preserve */ nullptr,
+
+ /* lib_override_apply_post */ nullptr,
};
void *BKE_simulation_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 78729fb9261..0c917434bd1 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -221,6 +221,8 @@ IDTypeInfo IDType_ID_SO = {
.blend_read_expand = sound_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
#ifdef WITH_AUDASPACE
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index fabf0bb8971..9caeaf05e6a 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -114,6 +114,8 @@ IDTypeInfo IDType_ID_SPK = {
.blend_read_expand = speaker_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
void *BKE_speaker_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 9ef2e818293..9bf215515f7 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -258,6 +258,8 @@ IDTypeInfo IDType_ID_TXT = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/** \} */
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 4c2e4a82acb..ce84bfcd95a 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -226,6 +226,8 @@ IDTypeInfo IDType_ID_TE = {
.blend_read_expand = texture_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/* Utils for all IDs using those texture slots. */
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index e5f9d59270e..d124922acd1 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -587,15 +587,15 @@ MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking,
{
const MovieTrackingSettings *settings = &tracking->settings;
+ MovieTrackingTrack *track = BKE_tracking_track_add_empty(tracking, tracksbase);
+ MovieTrackingMarker marker;
+
const float half_pattern_px = settings->default_pattern_size / 2.0f;
const float half_search_px = settings->default_search_size / 2.0f;
const float pattern_size[2] = {half_pattern_px / width, half_pattern_px / height};
const float search_size[2] = {half_search_px / width, half_search_px / height};
- MovieTrackingTrack *track = BKE_tracking_track_add_empty(tracking, tracksbase);
-
- MovieTrackingMarker marker;
memset(&marker, 0, sizeof(marker));
marker.pos[0] = x;
marker.pos[1] = y;
@@ -665,6 +665,86 @@ void BKE_tracking_track_free(MovieTrackingTrack *track)
}
}
+/* Get frame numbers of the very first and last markers.
+ * There is no check on whether the marker is enabled or not. */
+void BKE_tracking_track_first_last_frame_get(const MovieTrackingTrack *track,
+ int *r_first_frame,
+ int *r_last_frame)
+{
+ BLI_assert(track->markersnr > 0);
+ const int last_marker_index = track->markersnr - 1;
+ *r_first_frame = track->markers[0].framenr;
+ *r_last_frame = track->markers[last_marker_index].framenr;
+}
+
+/* Find the minimum starting frame and maximum ending frame within given set of
+ * tracks.
+ */
+void BKE_tracking_tracks_first_last_frame_minmax(/*const*/ MovieTrackingTrack **tracks,
+ const int num_tracks,
+ int *r_first_frame,
+ int *r_last_frame)
+{
+ *r_first_frame = INT_MAX;
+ *r_last_frame = INT_MIN;
+ for (int i = 0; i < num_tracks; ++i) {
+ const struct MovieTrackingTrack *track = tracks[i];
+ int track_first_frame, track_last_frame;
+ BKE_tracking_track_first_last_frame_get(track, &track_first_frame, &track_last_frame);
+ *r_first_frame = min_ii(*r_first_frame, track_first_frame);
+ *r_last_frame = max_ii(*r_last_frame, track_last_frame);
+ }
+}
+
+int BKE_tracking_count_selected_tracks_in_list(const ListBase *tracks_list)
+{
+ int num_selected_tracks = 0;
+ LISTBASE_FOREACH (const MovieTrackingTrack *, track, tracks_list) {
+ if (TRACK_SELECTED(track)) {
+ ++num_selected_tracks;
+ }
+ }
+ return num_selected_tracks;
+}
+
+int BKE_tracking_count_selected_tracks_in_active_object(/*const*/ MovieTracking *tracking)
+{
+ ListBase *tracks_list = BKE_tracking_get_active_tracks(tracking);
+ return BKE_tracking_count_selected_tracks_in_list(tracks_list);
+}
+
+MovieTrackingTrack **BKE_tracking_selected_tracks_in_active_object(MovieTracking *tracking,
+ int *r_num_tracks)
+{
+ *r_num_tracks = 0;
+
+ ListBase *tracks_list = BKE_tracking_get_active_tracks(tracking);
+ if (tracks_list == NULL) {
+ return NULL;
+ }
+
+ /* Initialize input. */
+ const int num_selected_tracks = BKE_tracking_count_selected_tracks_in_active_object(tracking);
+ if (num_selected_tracks == 0) {
+ return NULL;
+ }
+
+ MovieTrackingTrack **source_tracks = MEM_malloc_arrayN(
+ num_selected_tracks, sizeof(MovieTrackingTrack *), "selected tracks array");
+ int source_track_index = 0;
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, tracks_list) {
+ if (!TRACK_SELECTED(track)) {
+ continue;
+ }
+ source_tracks[source_track_index] = track;
+ ++source_track_index;
+ }
+
+ *r_num_tracks = num_selected_tracks;
+
+ return source_tracks;
+}
+
/* Set flag for all specified track's areas.
*
* area - which part of marker should be selected. see TRACK_AREA_* constants.
@@ -918,6 +998,124 @@ void BKE_tracking_tracks_join(MovieTracking *tracking,
BKE_tracking_dopesheet_tag_update(tracking);
}
+static void accumulate_marker(MovieTrackingMarker *dst_marker,
+ const MovieTrackingMarker *src_marker)
+{
+ BLI_assert(dst_marker->framenr == src_marker->framenr);
+
+ if (src_marker->flag & MARKER_DISABLED) {
+ return;
+ }
+
+ add_v2_v2(dst_marker->pos, src_marker->pos);
+ for (int corner = 0; corner < 4; ++corner) {
+ add_v2_v2(dst_marker->pattern_corners[corner], src_marker->pattern_corners[corner]);
+ }
+ add_v2_v2(dst_marker->search_min, src_marker->search_min);
+ add_v2_v2(dst_marker->search_max, src_marker->search_max);
+
+ BLI_assert(is_finite_v2(src_marker->search_min));
+ BLI_assert(is_finite_v2(src_marker->search_max));
+
+ dst_marker->flag &= ~MARKER_DISABLED;
+ if ((src_marker->flag & MARKER_TRACKED) == 0) {
+ dst_marker->flag &= ~MARKER_TRACKED;
+ }
+}
+
+static void multiply_marker(MovieTrackingMarker *marker, const float multiplier)
+{
+ mul_v2_fl(marker->pos, multiplier);
+ for (int corner = 0; corner < 4; ++corner) {
+ mul_v2_fl(marker->pattern_corners[corner], multiplier);
+ }
+ mul_v2_fl(marker->search_min, multiplier);
+ mul_v2_fl(marker->search_max, multiplier);
+}
+
+/* Helper function for BKE_tracking_tracks_average which takes care of averaging fields of
+ * markers (position, patterns, ...). */
+static void tracking_average_markers(MovieTrackingTrack *dst_track,
+ /*const*/ MovieTrackingTrack **src_tracks,
+ const int num_src_tracks)
+{
+ /* Get global range of frames within which averaging would happen. */
+ int first_frame, last_frame;
+ BKE_tracking_tracks_first_last_frame_minmax(
+ src_tracks, num_src_tracks, &first_frame, &last_frame);
+ if (last_frame < first_frame) {
+ return;
+ }
+ const int num_frames = last_frame - first_frame + 1;
+
+ /* Allocate temporary array where averaging will happen into. */
+ MovieTrackingMarker *accumulator = MEM_calloc_arrayN(
+ num_frames, sizeof(MovieTrackingMarker), "tracks average accumulator");
+ int *counters = MEM_calloc_arrayN(num_frames, sizeof(int), "tracks accumulator counters");
+ for (int frame = first_frame; frame <= last_frame; ++frame) {
+ const int frame_index = frame - first_frame;
+ accumulator[frame_index].framenr = frame;
+ accumulator[frame_index].flag |= (MARKER_DISABLED | MARKER_TRACKED);
+ }
+
+ /* Accumulate track markers. */
+ for (int track_index = 0; track_index < num_src_tracks; ++track_index) {
+ /*const*/ MovieTrackingTrack *track = src_tracks[track_index];
+ for (int frame = first_frame; frame <= last_frame; ++frame) {
+ MovieTrackingMarker interpolated_marker;
+ if (!BKE_tracking_marker_get_interpolated(track, frame, &interpolated_marker)) {
+ continue;
+ }
+ const int frame_index = frame - first_frame;
+ accumulate_marker(&accumulator[frame_index], &interpolated_marker);
+ ++counters[frame_index];
+ }
+ }
+
+ /* Average and store the result. */
+ for (int frame = first_frame; frame <= last_frame; ++frame) {
+ /* Average. */
+ const int frame_index = frame - first_frame;
+ if (!counters[frame_index]) {
+ continue;
+ }
+ const float multiplier = 1.0f / (float)counters[frame_index];
+ multiply_marker(&accumulator[frame_index], multiplier);
+ /* Store the result. */
+ BKE_tracking_marker_insert(dst_track, &accumulator[frame_index]);
+ }
+
+ /* Free memory. */
+ MEM_freeN(accumulator);
+ MEM_freeN(counters);
+}
+
+/* Helper function for BKE_tracking_tracks_average which takes care of averaging fields of
+ * tracks (track for example, offset). */
+static void tracking_average_tracks(MovieTrackingTrack *dst_track,
+ /*const*/ MovieTrackingTrack **src_tracks,
+ const int num_src_tracks)
+{
+ /* TODO(sergey): Consider averaging weight, stabilization weight, maybe even bundle position. */
+ zero_v2(dst_track->offset);
+ for (int track_index = 0; track_index < num_src_tracks; track_index++) {
+ add_v2_v2(dst_track->offset, src_tracks[track_index]->offset);
+ }
+ mul_v2_fl(dst_track->offset, 1.0f / num_src_tracks);
+}
+
+void BKE_tracking_tracks_average(MovieTrackingTrack *dst_track,
+ /*const*/ MovieTrackingTrack **src_tracks,
+ const int num_src_tracks)
+{
+ if (num_src_tracks == 0) {
+ return;
+ }
+
+ tracking_average_markers(dst_track, src_tracks, num_src_tracks);
+ tracking_average_tracks(dst_track, src_tracks, num_src_tracks);
+}
+
MovieTrackingTrack *BKE_tracking_track_get_named(MovieTracking *tracking,
MovieTrackingObject *object,
const char *name)
@@ -1224,8 +1422,6 @@ MovieTrackingMarker *BKE_tracking_marker_insert(MovieTrackingTrack *track,
/* put new marker */
track->markers[a + 1] = *marker;
- track->last_marker = a + 1;
-
return &track->markers[a + 1];
}
@@ -1314,51 +1510,47 @@ void BKE_tracking_marker_clamp(MovieTrackingMarker *marker, int event)
}
}
+/**
+ * Get marker closest to the given frame number.
+ *
+ * If there is maker with exact frame number it returned.
+ * Otherwise, marker with highest frame number but lower than the requested
+ * frame is returned if such marker exists. Otherwise, the marker with lowest
+ * frame number greater than the requested frame number is returned.
+ *
+ * This function has complexity of `O(log number_of_markers)`.
+ */
MovieTrackingMarker *BKE_tracking_marker_get(MovieTrackingTrack *track, int framenr)
{
- int a = track->markersnr - 1;
+ const int num_markers = track->markersnr;
- if (!track->markersnr) {
+ if (num_markers == 0) {
+ BLI_assert(!"Detected degenerated track, should never happen.");
return NULL;
}
- /* approximate pre-first framenr marker with first marker */
- if (framenr < track->markers[0].framenr) {
- return &track->markers[0];
- }
+ int left_boundary = 0;
+ int right_boundary = num_markers;
+ while (left_boundary < right_boundary) {
+ const int median_index = (left_boundary + right_boundary) / 2;
+ MovieTrackingMarker *marker = &track->markers[median_index];
- if (track->last_marker < track->markersnr) {
- a = track->last_marker;
- }
-
- if (track->markers[a].framenr <= framenr) {
- while (a < track->markersnr && track->markers[a].framenr <= framenr) {
- if (track->markers[a].framenr == framenr) {
- track->last_marker = a;
-
- return &track->markers[a];
- }
- a++;
+ if (marker->framenr == framenr) {
+ return marker;
}
- /* if there's no marker for exact position, use nearest marker from left side */
- return &track->markers[a - 1];
- }
-
- while (a >= 0 && track->markers[a].framenr >= framenr) {
- if (track->markers[a].framenr == framenr) {
- track->last_marker = a;
-
- return &track->markers[a];
+ if (marker->framenr < framenr) {
+ left_boundary = median_index + 1;
+ }
+ else {
+ BLI_assert(marker->framenr > framenr);
+ right_boundary = median_index - 1;
}
-
- a--;
}
- /* if there's no marker for exact position, use nearest marker from left side */
- return &track->markers[a];
+ const int closest_index = clamp_i(right_boundary, 0, num_markers - 1);
- return NULL;
+ return &track->markers[closest_index];
}
MovieTrackingMarker *BKE_tracking_marker_get_exact(MovieTrackingTrack *track, int framenr)
@@ -1389,6 +1581,84 @@ MovieTrackingMarker *BKE_tracking_marker_ensure(MovieTrackingTrack *track, int f
return marker;
}
+static const MovieTrackingMarker *get_usable_marker_for_interpolation(
+ struct MovieTrackingTrack *track,
+ const MovieTrackingMarker *anchor_marker,
+ const int direction)
+{
+ BLI_assert(direction == -1 || direction == 1);
+
+ const MovieTrackingMarker *last_marker = track->markers + track->markersnr - 1;
+ const MovieTrackingMarker *current_marker = anchor_marker;
+
+ while (current_marker >= track->markers && current_marker <= last_marker) {
+ if ((current_marker->flag & MARKER_DISABLED) == 0) {
+ return current_marker;
+ }
+ current_marker += direction;
+ }
+
+ return NULL;
+}
+
+bool BKE_tracking_marker_get_interpolated(struct MovieTrackingTrack *track,
+ const int framenr,
+ struct MovieTrackingMarker *r_marker)
+{
+ const MovieTrackingMarker *closest_marker = BKE_tracking_marker_get(track, framenr);
+ if (closest_marker == NULL) {
+ return false;
+ }
+ if (closest_marker->framenr == framenr && (closest_marker->flag & MARKER_DISABLED) == 0) {
+ *r_marker = *closest_marker;
+ return true;
+ }
+
+ const MovieTrackingMarker *left_marker = get_usable_marker_for_interpolation(
+ track, closest_marker, -1);
+ if (left_marker == NULL) {
+ return false;
+ }
+
+ const MovieTrackingMarker *right_marker = get_usable_marker_for_interpolation(
+ track, closest_marker + 1, 1);
+ if (right_marker == NULL) {
+ return false;
+ }
+
+ if (left_marker == right_marker) {
+ *r_marker = *left_marker;
+ return true;
+ }
+
+ const float factor = (float)(framenr - left_marker->framenr) /
+ (right_marker->framenr - left_marker->framenr);
+
+ interp_v2_v2v2(r_marker->pos, left_marker->pos, right_marker->pos, factor);
+
+ for (int i = 0; i < 4; i++) {
+ interp_v2_v2v2(r_marker->pattern_corners[i],
+ left_marker->pattern_corners[i],
+ right_marker->pattern_corners[i],
+ factor);
+ }
+
+ interp_v2_v2v2(r_marker->search_min, left_marker->search_min, right_marker->search_min, factor);
+ interp_v2_v2v2(r_marker->search_max, left_marker->search_max, right_marker->search_max, factor);
+
+ r_marker->framenr = framenr;
+ r_marker->flag = 0;
+
+ if (framenr == left_marker->framenr) {
+ r_marker->flag = left_marker->flag;
+ }
+ else if (framenr == right_marker->framenr) {
+ r_marker->flag = right_marker->flag;
+ }
+
+ return true;
+}
+
void BKE_tracking_marker_pattern_minmax(const MovieTrackingMarker *marker,
float min[2],
float max[2])
@@ -1683,7 +1953,6 @@ MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTra
/* Put new marker to an array. */
plane_track->markers[a + 1] = *plane_marker;
- plane_track->last_marker = a + 1;
return &plane_track->markers[a + 1];
}
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index 6f58416924f..46589a578a8 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -311,11 +311,7 @@ static void retrieve_next_lower_usable_frame(
* translation stabilization, which has an enabled tracking marker at this very
* frame. We search both for the next lower and next higher position, to allow
* the caller to interpolate gaps and to extrapolate at the ends of the
- * definition range.
- *
- * NOTE: Regarding performance note that the individual tracks will cache the
- * last search position.
- */
+ * definition range. */
static void find_next_working_frames(StabContext *ctx,
int framenr,
int *next_lower,
diff --git a/source/blender/blenkernel/intern/tracking_test.cc b/source/blender/blenkernel/intern/tracking_test.cc
index 6afcf6872eb..2877d8db358 100644
--- a/source/blender/blenkernel/intern/tracking_test.cc
+++ b/source/blender/blenkernel/intern/tracking_test.cc
@@ -5,15 +5,23 @@
#include "DNA_tracking_types.h"
#include "BKE_tracking.h"
+#include "BLI_float2.hh"
+
+namespace blender {
namespace {
class TrackingTest : public ::testing::Test {
protected:
- MovieTrackingMarker *addMarkerToTrack(MovieTrackingTrack *track, int frame_number)
+ MovieTrackingMarker *addMarkerToTrack(MovieTrackingTrack *track,
+ int frame_number,
+ const float2 &position = float2(0.0f, 0.0f),
+ int flag = 0)
{
MovieTrackingMarker marker = {{0.0f}};
+ copy_v2_v2(marker.pos, position);
marker.framenr = frame_number;
+ marker.flag = flag;
return BKE_tracking_marker_insert(track, &marker);
}
};
@@ -22,24 +30,58 @@ class TrackingTest : public ::testing::Test {
TEST_F(TrackingTest, BKE_tracking_marker_get)
{
- MovieTrackingTrack track = {nullptr};
+ {
+ MovieTrackingTrack track = {nullptr};
- addMarkerToTrack(&track, 1);
- addMarkerToTrack(&track, 10);
+ addMarkerToTrack(&track, 10);
- {
- const MovieTrackingMarker *marker = BKE_tracking_marker_get(&track, 1);
- EXPECT_NE(marker, nullptr);
- EXPECT_EQ(marker->framenr, 1);
+ EXPECT_EQ(BKE_tracking_marker_get(&track, 0), &track.markers[0]);
+ EXPECT_EQ(BKE_tracking_marker_get(&track, 10), &track.markers[0]);
+ EXPECT_EQ(BKE_tracking_marker_get(&track, 20), &track.markers[0]);
+
+ BKE_tracking_track_free(&track);
}
{
- const MovieTrackingMarker *marker = BKE_tracking_marker_get(&track, 5);
- EXPECT_NE(marker, nullptr);
- EXPECT_EQ(marker->framenr, 1);
+ MovieTrackingTrack track = {nullptr};
+
+ addMarkerToTrack(&track, 1);
+ addMarkerToTrack(&track, 10);
+
+ {
+ const MovieTrackingMarker *marker = BKE_tracking_marker_get(&track, 1);
+ EXPECT_NE(marker, nullptr);
+ EXPECT_EQ(marker->framenr, 1);
+ }
+
+ {
+ const MovieTrackingMarker *marker = BKE_tracking_marker_get(&track, 5);
+ EXPECT_NE(marker, nullptr);
+ EXPECT_EQ(marker->framenr, 1);
+ }
+
+ BKE_tracking_track_free(&track);
}
- BKE_tracking_track_free(&track);
+ {
+ {
+ MovieTrackingTrack track = {nullptr};
+
+ addMarkerToTrack(&track, 1);
+ addMarkerToTrack(&track, 2);
+ addMarkerToTrack(&track, 10);
+
+ EXPECT_EQ(BKE_tracking_marker_get(&track, 0), &track.markers[0]);
+ EXPECT_EQ(BKE_tracking_marker_get(&track, 1), &track.markers[0]);
+ EXPECT_EQ(BKE_tracking_marker_get(&track, 2), &track.markers[1]);
+ EXPECT_EQ(BKE_tracking_marker_get(&track, 3), &track.markers[1]);
+ EXPECT_EQ(BKE_tracking_marker_get(&track, 9), &track.markers[1]);
+ EXPECT_EQ(BKE_tracking_marker_get(&track, 10), &track.markers[2]);
+ EXPECT_EQ(BKE_tracking_marker_get(&track, 11), &track.markers[2]);
+
+ BKE_tracking_track_free(&track);
+ }
+ }
}
TEST_F(TrackingTest, BKE_tracking_marker_get_exact)
@@ -62,3 +104,107 @@ TEST_F(TrackingTest, BKE_tracking_marker_get_exact)
BKE_tracking_track_free(&track);
}
+
+TEST_F(TrackingTest, BKE_tracking_marker_get_interpolated)
+{
+ /* Simple case, no disabled markers in a way. */
+ {
+ MovieTrackingTrack track = {nullptr};
+
+ addMarkerToTrack(&track, 1, float2(1.0f, 5.0f));
+ addMarkerToTrack(&track, 10, float2(2.0f, 1.0f));
+
+ {
+ MovieTrackingMarker interpolated_marker;
+ EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 1, &interpolated_marker));
+ EXPECT_EQ(interpolated_marker.framenr, 1);
+ EXPECT_V2_NEAR(interpolated_marker.pos, float2(1.0f, 5.0f), 1e-6f);
+ }
+
+ {
+ MovieTrackingMarker interpolated_marker;
+ EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 10, &interpolated_marker));
+ EXPECT_EQ(interpolated_marker.framenr, 10);
+ EXPECT_V2_NEAR(interpolated_marker.pos, float2(2.0f, 1.0f), 1e-6f);
+ }
+
+ {
+ MovieTrackingMarker interpolated_marker;
+ EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 4, &interpolated_marker));
+ EXPECT_EQ(interpolated_marker.framenr, 4);
+ EXPECT_V2_NEAR(interpolated_marker.pos, float2(1.3333333f, 3.6666666f), 1e-6f);
+ }
+
+ BKE_tracking_track_free(&track);
+ }
+
+ /* More comprehensive test, which resembles real life trackign scenario better. */
+ {
+ MovieTrackingTrack track = {nullptr};
+
+ addMarkerToTrack(&track, 1, float2(1.0f, 5.0f));
+ addMarkerToTrack(&track, 2, float2(0.0f, 0.0f), MARKER_DISABLED);
+ addMarkerToTrack(&track, 9, float2(0.0f, 0.0f), MARKER_DISABLED);
+ addMarkerToTrack(&track, 10, float2(2.0f, 1.0f));
+
+ {
+ MovieTrackingMarker interpolated_marker;
+ EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 1, &interpolated_marker));
+ EXPECT_EQ(interpolated_marker.framenr, 1);
+ EXPECT_V2_NEAR(interpolated_marker.pos, float2(1.0f, 5.0f), 1e-6f);
+ }
+
+ {
+ MovieTrackingMarker interpolated_marker;
+ EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 10, &interpolated_marker));
+ EXPECT_EQ(interpolated_marker.framenr, 10);
+ EXPECT_V2_NEAR(interpolated_marker.pos, float2(2.0f, 1.0f), 1e-6f);
+ }
+
+ {
+ MovieTrackingMarker interpolated_marker;
+ EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 4, &interpolated_marker));
+ EXPECT_EQ(interpolated_marker.framenr, 4);
+ EXPECT_V2_NEAR(interpolated_marker.pos, float2(1.3333333f, 3.6666666f), 1e-6f);
+ }
+
+ {
+ MovieTrackingMarker interpolated_marker;
+ EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 9, &interpolated_marker));
+ EXPECT_EQ(interpolated_marker.framenr, 9);
+ EXPECT_V2_NEAR(interpolated_marker.pos, float2(1.888888f, 1.4444444f), 1e-6f);
+ }
+
+ BKE_tracking_track_free(&track);
+ }
+
+ /* Tracked/keyframed flag check. */
+ {
+ MovieTrackingTrack track = {nullptr};
+
+ addMarkerToTrack(&track, 1, float2(1.0f, 5.0f), MARKER_TRACKED);
+ addMarkerToTrack(&track, 10, float2(2.0f, 1.0f), MARKER_TRACKED);
+
+ {
+ MovieTrackingMarker interpolated_marker;
+ EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 1, &interpolated_marker));
+ EXPECT_EQ(interpolated_marker.flag, MARKER_TRACKED);
+ }
+
+ {
+ MovieTrackingMarker interpolated_marker;
+ EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 10, &interpolated_marker));
+ EXPECT_EQ(interpolated_marker.flag, MARKER_TRACKED);
+ }
+
+ {
+ MovieTrackingMarker interpolated_marker;
+ EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 4, &interpolated_marker));
+ EXPECT_EQ(interpolated_marker.flag, 0);
+ }
+
+ BKE_tracking_track_free(&track);
+ }
+}
+
+} // namespace blender
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index e78576206de..5f99f629f42 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -586,7 +586,7 @@ UndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
BLI_strncpy(us->name, name, sizeof(us->name));
}
us->type = ut;
- /* True by default, code needs to explicitely set it to false if necessary. */
+ /* True by default, code needs to explicitly set it to false if necessary. */
us->use_old_bmain_data = true;
/* Initialized, not added yet. */
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index b55f80c6473..e98fae9d92a 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -1167,8 +1167,7 @@ bool BKE_unit_replace_string(
/* Replace # with add sign when there is no operator between it and the next number.
*
* "1*1# 3*100# * 3" -> "1*1+ 3*100 * 3"
- *
- * */
+ */
{
char *str_found = str;
const char *ch = str;
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 9e7a3736141..77cfb3ffea5 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -128,7 +128,7 @@ static struct VolumeFileCache {
std::lock_guard<std::mutex> lock(mutex);
return simplified_grids.lookup_or_add_cb(simplify_level, [&]() {
const float resolution_factor = 1.0f / (1 << simplify_level);
- const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid);
+ const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(*grid);
return BKE_volume_grid_create_with_changed_resolution(grid_type, *grid, resolution_factor);
});
}
@@ -523,6 +523,8 @@ static void volume_copy_data(Main *UNUSED(bmain),
volume_dst->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector, grids_src);
}
#endif
+
+ volume_dst->batch_cache = nullptr;
}
static void volume_free_data(ID *id)
@@ -642,6 +644,8 @@ IDTypeInfo IDType_ID_VO = {
/* blend_read_expand */ volume_blend_read_expand,
/* blend_read_undo_preserve */ nullptr,
+
+ /* lib_override_apply_post */ nullptr,
};
void BKE_volume_init_grids(Volume *volume)
@@ -1233,39 +1237,39 @@ const char *BKE_volume_grid_name(const VolumeGrid *volume_grid)
}
#ifdef WITH_OPENVDB
-VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase::Ptr &grid)
+VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase &grid)
{
- if (grid->isType<openvdb::FloatGrid>()) {
+ if (grid.isType<openvdb::FloatGrid>()) {
return VOLUME_GRID_FLOAT;
}
- if (grid->isType<openvdb::Vec3fGrid>()) {
+ if (grid.isType<openvdb::Vec3fGrid>()) {
return VOLUME_GRID_VECTOR_FLOAT;
}
- if (grid->isType<openvdb::BoolGrid>()) {
+ if (grid.isType<openvdb::BoolGrid>()) {
return VOLUME_GRID_BOOLEAN;
}
- if (grid->isType<openvdb::DoubleGrid>()) {
+ if (grid.isType<openvdb::DoubleGrid>()) {
return VOLUME_GRID_DOUBLE;
}
- if (grid->isType<openvdb::Int32Grid>()) {
+ if (grid.isType<openvdb::Int32Grid>()) {
return VOLUME_GRID_INT;
}
- if (grid->isType<openvdb::Int64Grid>()) {
+ if (grid.isType<openvdb::Int64Grid>()) {
return VOLUME_GRID_INT64;
}
- if (grid->isType<openvdb::Vec3IGrid>()) {
+ if (grid.isType<openvdb::Vec3IGrid>()) {
return VOLUME_GRID_VECTOR_INT;
}
- if (grid->isType<openvdb::Vec3dGrid>()) {
+ if (grid.isType<openvdb::Vec3dGrid>()) {
return VOLUME_GRID_VECTOR_DOUBLE;
}
- if (grid->isType<openvdb::StringGrid>()) {
+ if (grid.isType<openvdb::StringGrid>()) {
return VOLUME_GRID_STRING;
}
- if (grid->isType<openvdb::MaskGrid>()) {
+ if (grid.isType<openvdb::MaskGrid>()) {
return VOLUME_GRID_MASK;
}
- if (grid->isType<openvdb::points::PointDataGrid>()) {
+ if (grid.isType<openvdb::points::PointDataGrid>()) {
return VOLUME_GRID_POINTS;
}
return VOLUME_GRID_UNKNOWN;
@@ -1276,7 +1280,7 @@ VolumeGridType BKE_volume_grid_type(const VolumeGrid *volume_grid)
{
#ifdef WITH_OPENVDB
const openvdb::GridBase::Ptr grid = volume_grid->grid();
- return BKE_volume_grid_type_openvdb(grid);
+ return BKE_volume_grid_type_openvdb(*grid);
#else
UNUSED_VARS(volume_grid);
#endif
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 291116556c3..5a101cf009b 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -192,6 +192,8 @@ IDTypeInfo IDType_ID_WS = {
.blend_read_expand = workspace_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 8fe7653fc25..a2ce37a5d90 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -206,6 +206,8 @@ IDTypeInfo IDType_ID_WO = {
.blend_read_expand = world_blend_read_expand,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
World *BKE_world_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h
index 7257be66b79..034f3f39fd3 100644
--- a/source/blender/blenkernel/nla_private.h
+++ b/source/blender/blenkernel/nla_private.h
@@ -112,8 +112,8 @@ typedef struct NlaEvalChannel {
struct NlaEvalChannel *next_blend;
NlaEvalChannelSnapshot *blend_snapshot;
- /* Mask of array items controlled by NLA. */
- NlaValidMask valid;
+ /* Associated with the RNA property's value(s), marks which elements are affected by NLA. */
+ NlaValidMask domain;
/* Base set of values. */
NlaEvalChannelSnapshot base_snapshot;
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 74a491898b6..9f144a0ddaa 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -20,7 +20,7 @@
/** \file
* \ingroup bli
* \brief File and directory operations.
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_float2.hh b/source/blender/blenlib/BLI_float2.hh
index 2a5320e4c35..84dd0e358a2 100644
--- a/source/blender/blenlib/BLI_float2.hh
+++ b/source/blender/blenlib/BLI_float2.hh
@@ -29,6 +29,14 @@ struct float2 {
{
}
+ explicit float2(float value) : x(value), y(value)
+ {
+ }
+
+ explicit float2(int value) : x(value), y(value)
+ {
+ }
+
float2(float x, float y) : x(x), y(y)
{
}
@@ -52,6 +60,11 @@ struct float2 {
return len_v2(*this);
}
+ float length_squared() const
+ {
+ return len_squared_v2(*this);
+ }
+
float2 &operator+=(const float2 &other)
{
x += other.x;
diff --git a/source/blender/blenlib/BLI_fnmatch.h b/source/blender/blenlib/BLI_fnmatch.h
index d09a14621d8..2d0c13bc423 100644
--- a/source/blender/blenlib/BLI_fnmatch.h
+++ b/source/blender/blenlib/BLI_fnmatch.h
@@ -16,7 +16,7 @@
* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
*
* NOTE: The canonical source of this file is maintained with the GNU C Library.
- * Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+ * Bugs can be reported to <bug-glibc@prep.ai.mit.edu>.
*/
#pragma once
diff --git a/source/blender/blenlib/BLI_math.h b/source/blender/blenlib/BLI_math.h
index 51833d081d0..f6075367ac5 100644
--- a/source/blender/blenlib/BLI_math.h
+++ b/source/blender/blenlib/BLI_math.h
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 0ec65999006..c862290b262 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_math_bits.h b/source/blender/blenlib/BLI_math_bits.h
index b007dd7cfed..e881f1a0e4e 100644
--- a/source/blender/blenlib/BLI_math_bits.h
+++ b/source/blender/blenlib/BLI_math_bits.h
@@ -12,8 +12,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 9e613270538..26d2f1fcb29 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_math_color_blend.h b/source/blender/blenlib/BLI_math_color_blend.h
index d5e4eedb1a6..2aff629def8 100644
--- a/source/blender/blenlib/BLI_math_color_blend.h
+++ b/source/blender/blenlib/BLI_math_color_blend.h
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index c0a9ea91e75..d767c2924d1 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
#pragma once
@@ -826,6 +825,11 @@ MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3]);
+/********************************** Geodesics *********************************/
+
+float geodesic_distance_propagate_across_triangle(
+ const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2);
+
/**************************** Inline Definitions ******************************/
#if BLI_MATH_DO_INLINE
diff --git a/source/blender/blenlib/BLI_math_inline.h b/source/blender/blenlib/BLI_math_inline.h
index 506386f8d25..70f56d15164 100644
--- a/source/blender/blenlib/BLI_math_inline.h
+++ b/source/blender/blenlib/BLI_math_inline.h
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index d971f48c4cf..eac7f25f11a 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -17,7 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 15d4dc21f8d..f45a4d6fdef 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_math_solvers.h b/source/blender/blenlib/BLI_math_solvers.h
index 9b2d1eedec7..13481e27e2a 100644
--- a/source/blender/blenlib/BLI_math_solvers.h
+++ b/source/blender/blenlib/BLI_math_solvers.h
@@ -15,7 +15,7 @@
*
* The Original Code is Copyright (C) 2015 by Blender Foundation
* All rights reserved.
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_math_statistics.h b/source/blender/blenlib/BLI_math_statistics.h
index ad6cb1a3c1e..6e818f5c8df 100644
--- a/source/blender/blenlib/BLI_math_statistics.h
+++ b/source/blender/blenlib/BLI_math_statistics.h
@@ -15,7 +15,7 @@
*
* The Original Code is Copyright (C) 2015 by Blender Foundation
* All rights reserved.
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 0bddff9101e..1df22f7c2c9 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
#pragma once
diff --git a/source/blender/blenlib/BLI_mmap.h b/source/blender/blenlib/BLI_mmap.h
new file mode 100644
index 00000000000..4920152c9d1
--- /dev/null
+++ b/source/blender/blenlib/BLI_mmap.h
@@ -0,0 +1,56 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Memory-mapped file IO that implements all the OS-specific details and error handling. */
+
+struct BLI_mmap_file;
+
+typedef struct BLI_mmap_file BLI_mmap_file;
+
+/* Prepares an opened file for memory-mapped IO.
+ * May return NULL if the operation fails.
+ * Note that this seeks to the end of the file to determine its length. */
+BLI_mmap_file *BLI_mmap_open(int fd) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+
+/* Reads length bytes from file at the given offset into dest.
+ * Returns whether the operation was successful (may fail when reading beyond the file
+ * end or when IO errors occur). */
+bool BLI_mmap_read(BLI_mmap_file *file, void *dest, size_t offset, size_t length)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+
+void *BLI_mmap_get_pointer(BLI_mmap_file *file) ATTR_WARN_UNUSED_RESULT;
+
+void BLI_mmap_free(BLI_mmap_file *file) ATTR_NONNULL(1);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 45a1054fb53..363d3003b3c 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -54,6 +54,7 @@ set(SRC
intern/BLI_memblock.c
intern/BLI_memiter.c
intern/BLI_mempool.c
+ intern/BLI_mmap.c
intern/BLI_timer.c
intern/DLRB_tree.c
intern/array_store.c
@@ -243,6 +244,7 @@ set(SRC
BLI_mempool.h
BLI_mesh_boolean.hh
BLI_mesh_intersect.hh
+ BLI_mmap.h
BLI_mpq2.hh
BLI_mpq3.hh
BLI_multi_value_map.hh
diff --git a/source/blender/blenlib/intern/BLI_mmap.c b/source/blender/blenlib/intern/BLI_mmap.c
new file mode 100644
index 00000000000..2fd162de22c
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_mmap.c
@@ -0,0 +1,237 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_mmap.h"
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
+#include "MEM_guardedalloc.h"
+
+#include <string.h>
+
+#ifndef WIN32
+# include <signal.h>
+# include <stdlib.h>
+# include <sys/mman.h> // for mmap
+# include <unistd.h> // for read close
+#else
+# include "BLI_winstuff.h"
+# include <io.h> // for open close read
+#endif
+
+struct BLI_mmap_file {
+ /* The address to which the file was mapped. */
+ char *memory;
+
+ /* The length of the file (and therefore the mapped region). */
+ size_t length;
+
+ /* Platform-specific handle for the mapping. */
+ void *handle;
+
+ /* Flag to indicate IO errors. Needs to be volatile since it's being set from
+ * within the signal handler, which is not part of the normal execution flow. */
+ volatile bool io_error;
+};
+
+#ifndef WIN32
+/* When using memory-mapped files, any IO errors will result in a SIGBUS signal.
+ * Therefore, we need to catch that signal and stop reading the file in question.
+ * To do so, we keep a list of all current FileDatas that use memory-mapped files,
+ * and if a SIGBUS is caught, we check if the failed address is inside one of the
+ * mapped regions.
+ * If it is, we set a flag to indicate a failed read and remap the memory in
+ * question to a zero-backed region in order to avoid additional signals.
+ * The code that actually reads the memory area has to check whether the flag was
+ * set after it's done reading.
+ * If the error occurred outside of a memory-mapped region, we call the previous
+ * handler if one was configured and abort the process otherwise.
+ */
+
+struct error_handler_data {
+ ListBase open_mmaps;
+ char configured;
+ void (*next_handler)(int, siginfo_t *, void *);
+} error_handler = {0};
+
+static void sigbus_handler(int sig, siginfo_t *siginfo, void *ptr)
+{
+ /* We only handle SIGBUS here for now. */
+ BLI_assert(sig == SIGBUS);
+
+ char *error_addr = (char *)siginfo->si_addr;
+ /* Find the file that this error belongs to. */
+ LISTBASE_FOREACH (LinkData *, link, &error_handler.open_mmaps) {
+ BLI_mmap_file *file = link->data;
+
+ /* Is the address where the error occurred in this file's mapped range? */
+ if (error_addr >= file->memory && error_addr < file->memory + file->length) {
+ file->io_error = true;
+
+ /* Replace the mapped memory with zeroes. */
+ const void *mapped_memory = mmap(
+ file->memory, file->length, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ if (mapped_memory == MAP_FAILED) {
+ fprintf(stderr, "SIGBUS handler: Error replacing mapped file with zeros\n");
+ }
+
+ return;
+ }
+ }
+
+ /* Fall back to other handler if there was one. */
+ if (error_handler.next_handler) {
+ error_handler.next_handler(sig, siginfo, ptr);
+ }
+ else {
+ fprintf(stderr, "Unhandled SIGBUS caught\n");
+ abort();
+ }
+}
+
+/* Ensures that the error handler is set up and ready. */
+static bool sigbus_handler_setup(void)
+{
+ if (!error_handler.configured) {
+ struct sigaction newact = {0}, oldact = {0};
+
+ newact.sa_sigaction = sigbus_handler;
+ newact.sa_flags = SA_SIGINFO;
+
+ if (sigaction(SIGBUS, &newact, &oldact)) {
+ return false;
+ }
+
+ /* Remember the previously configured handler to fall back to it if the error
+ * does not belong to any of the mapped files. */
+ error_handler.next_handler = oldact.sa_sigaction;
+ error_handler.configured = 1;
+ }
+
+ return true;
+}
+
+/* Adds a file to the list that the error handler checks. */
+static void sigbus_handler_add(BLI_mmap_file *file)
+{
+ BLI_addtail(&error_handler.open_mmaps, BLI_genericNodeN(file));
+}
+
+/* Removes a file from the list that the error handler checks. */
+static void sigbus_handler_remove(BLI_mmap_file *file)
+{
+ LinkData *link = BLI_findptr(&error_handler.open_mmaps, file, offsetof(LinkData, data));
+ BLI_freelinkN(&error_handler.open_mmaps, link);
+}
+#endif
+
+BLI_mmap_file *BLI_mmap_open(int fd)
+{
+ void *memory, *handle = NULL;
+ size_t length = BLI_lseek(fd, 0, SEEK_END);
+
+#ifndef WIN32
+ /* Ensure that the SIGBUS handler is configured. */
+ if (!sigbus_handler_setup()) {
+ return NULL;
+ }
+
+ /* Map the given file to memory. */
+ memory = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (memory == MAP_FAILED) {
+ return NULL;
+ }
+#else
+ /* Convert the POSIX-style file descriptor to a Windows handle. */
+ void *file_handle = (void *)_get_osfhandle(fd);
+ /* Memory mapping on Windows is a two-step process - first we create a mapping,
+ * then we create a view into that mapping.
+ * In our case, one view that spans the entire file is enough. */
+ handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (handle == NULL) {
+ return NULL;
+ }
+ memory = MapViewOfFile(handle, FILE_MAP_READ, 0, 0, 0);
+ if (memory == NULL) {
+ CloseHandle(handle);
+ return NULL;
+ }
+#endif
+
+ /* Now that the mapping was successful, allocate memory and set up the BLI_mmap_file. */
+ BLI_mmap_file *file = MEM_callocN(sizeof(BLI_mmap_file), __func__);
+ file->memory = memory;
+ file->handle = handle;
+ file->length = length;
+
+#ifndef WIN32
+ /* Register the file with the error handler. */
+ sigbus_handler_add(file);
+#endif
+
+ return file;
+}
+
+bool BLI_mmap_read(BLI_mmap_file *file, void *dest, size_t offset, size_t length)
+{
+ /* If a previous read has already failed or we try to read past the end,
+ * don't even attempt to read any further. */
+ if (file->io_error || (offset + length > file->length)) {
+ return false;
+ }
+
+#ifndef WIN32
+ /* If an error occurs in this call, sigbus_handler will be called and will set
+ * file->io_error to true. */
+ memcpy(dest, file->memory + offset, length);
+#else
+ /* On Windows, we use exception handling to be notified of errors. */
+ __try {
+ memcpy(dest, file->memory + offset, length);
+ }
+ __except (GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER :
+ EXCEPTION_CONTINUE_SEARCH) {
+ file->io_error = true;
+ return false;
+ }
+#endif
+
+ return !file->io_error;
+}
+
+void *BLI_mmap_get_pointer(BLI_mmap_file *file)
+{
+ return file->memory;
+}
+
+void BLI_mmap_free(BLI_mmap_file *file)
+{
+#ifndef WIN32
+ munmap((void *)file->memory, file->length);
+ sigbus_handler_remove(file);
+#else
+ UnmapViewOfFile(file->memory);
+ CloseHandle(file->handle);
+#endif
+
+ MEM_freeN(file);
+}
diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c
index 33250105c79..9d3b66d72d7 100644
--- a/source/blender/blenlib/intern/bitmap_draw_2d.c
+++ b/source/blender/blenlib/intern/bitmap_draw_2d.c
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/boxpack_2d.c b/source/blender/blenlib/intern/boxpack_2d.c
index 9840dc77148..3d010011a79 100644
--- a/source/blender/blenlib/intern/boxpack_2d.c
+++ b/source/blender/blenlib/intern/boxpack_2d.c
@@ -414,8 +414,7 @@ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r
/* This vert has a free quadrant
* Test if we can place the box here
- * vert->free & quad_flags[j] - Checks
- * */
+ * `vert->free & quad_flags[j]` - Checks. */
for (j = 0; (j < 4) && isect; j++) {
if (vert->free & quad_flag(j)) {
diff --git a/source/blender/blenlib/intern/list_sort_impl.h b/source/blender/blenlib/intern/list_sort_impl.h
index 46738803ee8..8f979ba5b0b 100644
--- a/source/blender/blenlib/intern/list_sort_impl.h
+++ b/source/blender/blenlib/intern/list_sort_impl.h
@@ -205,7 +205,7 @@ BLI_INLINE list_node *sweep_up(struct SortInfo *si, list_node *list, unsigned in
* The 'ranks' array essentially captures the recursion stack of a mergesort.
* The merge tree is built in a bottom-up manner. The control loop for
* updating the 'ranks' array is analogous to incrementing a binary integer,
- * and the `O(n)` time for counting upto n translates to `O(n)` merges when
+ * and the `O(n)` time for counting `upto` n translates to `O(n)` merges when
* inserting `rank-0` lists.
* When we plug in the sizes of the lists involved in those merges,
* we get the `O(n log n)` time for the sort.
diff --git a/source/blender/blenlib/intern/math_base.c b/source/blender/blenlib/intern/math_base.c
index 2bf06371740..1137c4114a5 100644
--- a/source/blender/blenlib/intern/math_base.c
+++ b/source/blender/blenlib/intern/math_base.c
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 1dc7c21f1d4..b332a0b2cb9 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/math_bits_inline.c b/source/blender/blenlib/intern/math_bits_inline.c
index ba18bb73850..1b381dccbfd 100644
--- a/source/blender/blenlib/intern/math_bits_inline.c
+++ b/source/blender/blenlib/intern/math_bits_inline.c
@@ -12,8 +12,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/math_boolean.cc b/source/blender/blenlib/intern/math_boolean.cc
index a345bc1d0af..6d4806a3fbc 100644
--- a/source/blender/blenlib/intern/math_boolean.cc
+++ b/source/blender/blenlib/intern/math_boolean.cc
@@ -160,7 +160,7 @@ static RobustInitCaller init_caller;
* Carnegie Mellon University
* 5000 Forbes Avenue
* Pittsburgh, Pennsylvania 15213-3891
- * jrs@cs.cmu.edu
+ * <jrs@cs.cmu.edu>
*
* This file contains C implementation of algorithms for exact addition
* and multiplication of floating-point numbers, and predicates for
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index 31ee81de40e..8fd2802a547 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c
index 7ad4f0d9585..53257cc9285 100644
--- a/source/blender/blenlib/intern/math_color_blend_inline.c
+++ b/source/blender/blenlib/intern/math_color_blend_inline.c
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index 1264620cf36..a1caf2fe02d 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 3cc4d03d547..0873dece864 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
/** \file
* \ingroup bli
@@ -1439,12 +1438,12 @@ int isect_line_sphere_v3(const float l1[3],
/* adapted for use in blender by Campbell Barton - 2011
*
* atelier iebele abel - 2001
- * atelier@iebele.nl
+ * <atelier@iebele.nl>
* http://www.iebele.nl
*
* sphere_line_intersection function adapted from:
* http://astronomy.swin.edu.au/pbourke/geometry/sphereline
- * Paul Bourke pbourke@swin.edu.au
+ * Paul Bourke <pbourke@swin.edu.au>
*/
const float ldir[3] = {
@@ -3887,7 +3886,7 @@ void interp_weights_quad_v3(float w[4],
* - 0 if the point is outside of triangle.
* - 1 if the point is inside triangle.
* - 2 if it's on the edge.
- * */
+ */
int barycentric_inside_triangle_v2(const float w[3])
{
if (IN_RANGE(w[0], 0.0f, 1.0f) && IN_RANGE(w[1], 0.0f, 1.0f) && IN_RANGE(w[2], 0.0f, 1.0f)) {
@@ -6246,3 +6245,56 @@ float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
const float angle_cos = cosf(angle);
return ((1.0f - angle_cos) / (angle_sin * 2.0f)) / angle_sin;
}
+
+/**
+ * Utility for computing approximate geodesic distances on triangle meshes.
+ *
+ * Given triangle with vertex coordinates v0, v1, v2, and known geodesic distances
+ * dist1 and dist2 at v1 and v2, estimate a geodesic distance at vertex v0.
+ *
+ * From "Dart Throwing on Surfaces", EGSR 2009. Section 7, Geodesic Dart Throwing.
+ */
+float geodesic_distance_propagate_across_triangle(
+ const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2)
+{
+ /* Vectors along triangle edges. */
+ float v10[3], v12[3];
+ sub_v3_v3v3(v10, v0, v1);
+ sub_v3_v3v3(v12, v2, v1);
+
+ if (dist1 != 0.0f && dist2 != 0.0f) {
+ /* Local coordinate system in the triangle plane. */
+ float u[3], v[3], n[3];
+ const float d12 = normalize_v3_v3(u, v12);
+
+ if (d12 * d12 > 0.0f) {
+ cross_v3_v3v3(n, v12, v10);
+ normalize_v3(n);
+ cross_v3_v3v3(v, n, u);
+
+ /* v0 in local coordinates */
+ const float v0_[2] = {dot_v3v3(v10, u), fabsf(dot_v3v3(v10, v))};
+
+ /* Compute virtual source point in local coordinates, that we estimate the geodesic
+ * distance is being computed from. See figure 9 in the paper for the derivation. */
+ const float a = 0.5f * (1.0f + (dist1 * dist1 - dist2 * dist2) / (d12 * d12));
+ const float hh = dist1 * dist1 - a * a * d12 * d12;
+
+ if (hh > 0.0f) {
+ const float h = sqrtf(hh);
+ const float S_[2] = {a * d12, -h};
+
+ /* Only valid if the line between the source point and v0 crosses
+ * the edge between v1 and v2. */
+ const float x_intercept = S_[0] + h * (v0_[0] - S_[0]) / (v0_[1] + h);
+ if (x_intercept >= 0.0f && x_intercept <= d12) {
+ return len_v2v2(S_, v0_);
+ }
+ }
+ }
+ }
+
+ /* Fall back to Dijsktra approximation in trivial case, or if no valid source
+ * point found that connects to v0 across the triangle. */
+ return min_ff(dist1 + len_v3(v10), dist2 + len_v3v3(v0, v2));
+}
diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c
index db317f5e81d..23c351026f2 100644
--- a/source/blender/blenlib/intern/math_geom_inline.c
+++ b/source/blender/blenlib/intern/math_geom_inline.c
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 19828e69638..f0d8bea52b9 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -1581,7 +1581,7 @@ void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float qua
* was adapted from
* ANSI C code from the article
* "Euler Angle Conversion"
- * by Ken Shoemake, shoemake@graphics.cis.upenn.edu
+ * by Ken Shoemake <shoemake@graphics.cis.upenn.edu>
* in "Graphics Gems IV", Academic Press, 1994
* for use in Blender
*/
diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c
index e366d834fc4..85900dc32a6 100644
--- a/source/blender/blenlib/intern/math_solvers.c
+++ b/source/blender/blenlib/intern/math_solvers.c
@@ -15,7 +15,7 @@
*
* The Original Code is Copyright (C) 2015 by Blender Foundation.
* All rights reserved.
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/math_statistics.c b/source/blender/blenlib/intern/math_statistics.c
index 18affbed708..b90ac99dbfe 100644
--- a/source/blender/blenlib/intern/math_statistics.c
+++ b/source/blender/blenlib/intern/math_statistics.c
@@ -15,7 +15,7 @@
*
* The Original Code is Copyright (C) 2015 by Blender Foundation.
* All rights reserved.
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 5f3297134c6..000468b3715 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index f17b7535258..ead354c2d87 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -17,8 +17,7 @@
* All rights reserved.
*
* The Original Code is: some of this file.
- *
- * */
+ */
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 5636ffafb6a..7cd7991b8d8 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -1650,7 +1650,7 @@ bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filenam
* - Wont create any directories.
* - Doesn't use CWD, or deal with relative paths.
* - Only fill's in \a dir and \a file when they are non NULL.
- * */
+ */
void BLI_split_dirfile(
const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen)
{
diff --git a/source/blender/blenlib/intern/system_win32.c b/source/blender/blenlib/intern/system_win32.c
index be2195d679d..7572936592e 100644
--- a/source/blender/blenlib/intern/system_win32.c
+++ b/source/blender/blenlib/intern/system_win32.c
@@ -386,7 +386,6 @@ void BLI_system_backtrace(FILE *fp)
bli_windows_system_backtrace_threads(fp);
}
bli_windows_system_backtrace_modules(fp);
- fputc(0, fp); /* Give our selves a nice zero terminator for later on */
}
void BLI_windows_handle_exception(EXCEPTION_POINTERS *exception)
diff --git a/source/blender/blenlib/intern/threads.cc b/source/blender/blenlib/intern/threads.cc
index 0b88cf53442..b42c50803e0 100644
--- a/source/blender/blenlib/intern/threads.cc
+++ b/source/blender/blenlib/intern/threads.cc
@@ -289,9 +289,8 @@ void BLI_threadpool_clear(ListBase *threadbase)
void BLI_threadpool_end(ListBase *threadbase)
{
- /* only needed if there's actually some stuff to end
- * this way we don't end up decrementing thread_levels on an empty threadbase
- * */
+ /* Only needed if there's actually some stuff to end
+ * this way we don't end up decrementing thread_levels on an empty `threadbase`. */
if (threadbase == nullptr || BLI_listbase_is_empty(threadbase)) {
return;
}
diff --git a/source/blender/blenlib/intern/voxel.c b/source/blender/blenlib/intern/voxel.c
index eac01a0e2aa..c0c895654e3 100644
--- a/source/blender/blenlib/intern/voxel.c
+++ b/source/blender/blenlib/intern/voxel.c
@@ -54,12 +54,14 @@ BLI_INLINE int FLOORI(float x)
return ((x >= 0.0f) || (float)r == x) ? r : (r - 1);
}
-/* clamp function, cannot use the CLAMPIS macro,
+/**
+ * clamp function, cannot use the CLAMPIS macro,
* it sometimes returns unwanted results apparently related to
- * gcc optimization flag -fstrict-overflow which is enabled at -O2
+ * gcc optimization flag `-fstrict-overflow` which is enabled at `-O2`
*
* this causes the test (x + 2) < 0 with int x == 2147483647 to return false (x being an integer,
- * x + 2 should wrap around to -2147483647 so the test < 0 should return true, which it doesn't) */
+ * x + 2 should wrap around to -2147483647 so the test < 0 should return true, which it doesn't).
+ */
BLI_INLINE int64_t _clamp(int a, int b, int c)
{
return (a < b) ? b : ((a > c) ? c : a);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index b61abd4ed06..2192e9a378f 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -68,6 +68,7 @@
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_mempool.h"
+#include "BLI_mmap.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
@@ -1179,6 +1180,53 @@ static ssize_t fd_read_from_memory(FileData *filedata,
return readsize;
}
+/* Memory-mapped file reading.
+ * By using mmap(), we can map a file so that it can be treated like normal memory,
+ * meaning that we can just read from it with memcpy() etc.
+ * This avoids system call overhead and can significantly speed up file loading.
+ */
+
+static ssize_t fd_read_from_mmap(FileData *filedata,
+ void *buffer,
+ size_t size,
+ bool *UNUSED(r_is_memchunck_identical))
+{
+ /* don't read more bytes than there are available in the buffer */
+ size_t readsize = MIN2(size, (size_t)(filedata->buffersize - filedata->file_offset));
+
+ if (!BLI_mmap_read(filedata->mmap_file, buffer, filedata->file_offset, readsize)) {
+ return 0;
+ }
+
+ filedata->file_offset += readsize;
+
+ return readsize;
+}
+
+static off64_t fd_seek_from_mmap(FileData *filedata, off64_t offset, int whence)
+{
+ off64_t new_pos;
+ if (whence == SEEK_CUR) {
+ new_pos = filedata->file_offset + offset;
+ }
+ else if (whence == SEEK_SET) {
+ new_pos = offset;
+ }
+ else if (whence == SEEK_END) {
+ new_pos = filedata->buffersize + offset;
+ }
+ else {
+ return -1;
+ }
+
+ if (new_pos < 0 || new_pos > filedata->buffersize) {
+ return -1;
+ }
+
+ filedata->file_offset = new_pos;
+ return filedata->file_offset;
+}
+
/* MemFile reading. */
static ssize_t fd_read_from_memfile(FileData *filedata,
@@ -1306,6 +1354,8 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
{
FileDataReadFn *read_fn = NULL;
FileDataSeekFn *seek_fn = NULL; /* Optional. */
+ size_t buffersize = 0;
+ BLI_mmap_file *mmap_file = NULL;
gzFile gzfile = (gzFile)Z_NULL;
@@ -1322,14 +1372,21 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
return NULL;
}
- BLI_lseek(file, 0, SEEK_SET);
-
/* Regular file. */
if (memcmp(header, "BLENDER", sizeof(header)) == 0) {
read_fn = fd_read_data_from_file;
seek_fn = fd_seek_data_from_file;
+
+ mmap_file = BLI_mmap_open(file);
+ if (mmap_file != NULL) {
+ read_fn = fd_read_from_mmap;
+ seek_fn = fd_seek_from_mmap;
+ buffersize = BLI_lseek(file, 0, SEEK_END);
+ }
}
+ BLI_lseek(file, 0, SEEK_SET);
+
/* Gzip file. */
errno = 0;
if ((read_fn == NULL) &&
@@ -1363,6 +1420,8 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
fd->read = read_fn;
fd->seek = seek_fn;
+ fd->mmap_file = mmap_file;
+ fd->buffersize = buffersize;
return fd;
}
@@ -1531,6 +1590,11 @@ void blo_filedata_free(FileData *fd)
fd->buffer = NULL;
}
+ if (fd->mmap_file) {
+ BLI_mmap_free(fd->mmap_file);
+ fd->mmap_file = NULL;
+ }
+
/* Free all BHeadN data blocks */
#ifndef NDEBUG
BLI_freelistN(&fd->bhead_list);
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index c724cc32051..86f05eda7b7 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -41,6 +41,7 @@ struct Object;
struct OldNewMap;
struct ReportList;
struct UserDef;
+struct BLI_mmap_file;
typedef struct IDNameLib_Map IDNameLib_Map;
@@ -83,8 +84,9 @@ typedef struct FileData {
/** Regular file reading. */
int filedes;
- /** Variables needed for reading from memory / stream. */
+ /** Variables needed for reading from memory / stream / memory-mapped files. */
const char *buffer;
+ struct BLI_mmap_file *mmap_file;
/** Variables needed for reading from memfile (undo). */
struct MemFile *memfile;
/** Whether we are undoing (< 0) or redoing (> 0), used to choose which 'unchanged' flag to use
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index bb477745849..2b630782806 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -475,7 +475,7 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
bGPDframe *gpf = gpl->frames.first;
if (gpf && gpf->framenum > scene->r.sfra) {
- bGPDframe *gpf_dup = BKE_gpencil_frame_duplicate(gpf);
+ bGPDframe *gpf_dup = BKE_gpencil_frame_duplicate(gpf, true);
gpf_dup->framenum = scene->r.sfra;
BLI_addhead(&gpl->frames, gpf_dup);
}
@@ -499,7 +499,7 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
/**
* Make sure Emission Alpha fcurve and drivers is properly mapped after the Emission Strength
* got introduced.
- * */
+ */
/**
* Effectively we are replacing the (animation of) node socket input 18 with 19.
@@ -510,7 +510,7 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
*
* The for loop for the input ids is at the top level otherwise we lose the animation
* keyframe data.
- * */
+ */
for (int input_id = 21; input_id >= 18; input_id--) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
@@ -1548,7 +1548,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_NODETREE_END;
}
- if (!MAIN_VERSION_ATLEAST(bmain, 292, 13)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 1)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
version_node_socket_name(ntree, GEO_NODE_BOOLEAN, "Geometry A", "Geometry 1");
@@ -1573,7 +1573,8 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- if (!MAIN_VERSION_ATLEAST(bmain, 292, 14)) {
+ if ((!MAIN_VERSION_ATLEAST(bmain, 292, 14)) ||
+ ((bmain->versionfile == 293) && (!MAIN_VERSION_ATLEAST(bmain, 293, 1)))) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type != NTREE_GEOMETRY) {
continue;
@@ -1590,6 +1591,75 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_NODETREE_END;
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 1)) {
+ /* Grease pencil layer transform matrix. */
+ if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "float", "location[0]")) {
+ LISTBASE_FOREACH (bGPdata *, gpd, &bmain->gpencils) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ zero_v3(gpl->location);
+ zero_v3(gpl->rotation);
+ copy_v3_fl(gpl->scale, 1.0f);
+ loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
+ invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
+ }
+ }
+ }
+ /* Fix Fill factor for grease pencil fill brushes. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if ((brush->gpencil_settings) && (brush->gpencil_settings->fill_factor == 0.0f)) {
+ brush->gpencil_settings->fill_factor = 1.0f;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 3)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_POINT_INSTANCE && node->storage == NULL) {
+ NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN(
+ sizeof(NodeGeometryPointInstance), __func__);
+ data->instance_type = node->custom1;
+ data->flag = (node->custom2 ? 0 : GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION);
+ node->storage = data;
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 4)) {
+ /* Add support for all operations to the "Attribute Math" node. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_ATTRIBUTE_MATH) {
+ NodeAttributeMath *data = (NodeAttributeMath *)node->storage;
+ data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 5)) {
+ /* Change Nishita sky model Altitude unit. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_TEX_SKY && node->storage) {
+ NodeTexSky *tex = (NodeTexSky *)node->storage;
+ tex->altitude *= 1000.0f;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 322830282e9..04f8023351b 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -827,6 +827,13 @@ void blo_do_versions_userdef(UserDef *userdef)
}
}
+ if (!USER_VERSION_ATLEAST(293, 2)) {
+ /* Enable asset browser features by default for alpha testing.
+ * BLO_sanitize_experimental_features_userpref_blend() will disable it again for non-alpha
+ * builds. */
+ userdef->experimental.use_asset_browser = true;
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -838,6 +845,9 @@ void blo_do_versions_userdef(UserDef *userdef)
*/
{
/* Keep this block, even when empty. */
+ if (userdef->gizmo_size_navigate_v3d == 0) {
+ userdef->gizmo_size_navigate_v3d = 80;
+ }
}
LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) {
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 9899d67c008..65f3d8bbad3 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -238,7 +238,6 @@ typedef struct BMesh {
uint use_toolflags : 1;
int toolflag_index;
- struct BMOperator *currentop;
CustomData vdata, edata, ldata, pdata;
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index c23551ecca7..647a22baaeb 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -29,7 +29,7 @@
#include "bmesh.h"
#include "intern/bmesh_walkers_private.h"
-/* pop into stack memory (common operation) */
+/* Pop into stack memory (common operation). */
#define BMW_state_remove_r(walker, owalk) \
{ \
memcpy(owalk, BMW_current_state(walker), sizeof(*(owalk))); \
@@ -86,7 +86,7 @@ static bool bmw_mask_check_face(BMWalker *walker, BMFace *f)
static bool bmw_edge_is_wire(const BMWalker *walker, const BMEdge *e)
{
if (walker->flag & BMW_FLAG_TEST_HIDDEN) {
- /* check if this is a wire edge, ignoring hidden faces */
+ /* Check if this is a wire edge, ignoring hidden faces. */
if (BM_edge_is_wire(e)) {
return true;
}
@@ -137,8 +137,7 @@ static void bmw_VertShellWalker_begin(BMWalker *walker, void *data)
switch (h->htype) {
case BM_VERT: {
- /* starting the walk at a vert, add all the edges
- * to the worklist */
+ /* Starting the walk at a vert, add all the edges to the work-list. */
v = (BMVert *)h;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
bmw_VertShellWalker_visitEdge(walker, e);
@@ -147,8 +146,7 @@ static void bmw_VertShellWalker_begin(BMWalker *walker, void *data)
}
case BM_EDGE: {
- /* starting the walk at an edge, add the single edge
- * to the worklist */
+ /* Starting the walk at an edge, add the single edge to the work-list. */
e = (BMEdge *)h;
bmw_VertShellWalker_visitEdge(walker, e);
break;
@@ -201,7 +199,7 @@ static void *bmw_VertShellWalker_step(BMWalker *walker)
BMW_state_remove(walker);
- /* find the next edge whose other vertex has not been visite */
+ /* Find the next edge whose other vertex has not been visited. */
curedge = shellWalk.curedge;
do {
if (!BLI_gset_haskey(walker->visit_set, curedge)) {
@@ -212,11 +210,11 @@ static void *bmw_VertShellWalker_step(BMWalker *walker)
v_old = BM_edge_other_vert(curedge, shellWalk.base);
- /* push a new state onto the stac */
+ /* Push a new state onto the stack. */
newState = BMW_state_add(walker);
BLI_gset_insert(walker->visit_set, curedge);
- /* populate the new stat */
+ /* Populate the new state. */
newState->base = v_old;
newState->curedge = curedge;
@@ -266,8 +264,7 @@ static void bmw_LoopShellWalker_begin(BMWalker *walker, void *data)
switch (h->htype) {
case BM_LOOP: {
- /* starting the walk at a vert, add all the edges
- * to the worklist */
+ /* Starting the walk at a vert, add all the edges to the work-list. */
BMLoop *l = (BMLoop *)h;
bmw_LoopShellWalker_visitLoop(walker, l);
break;
@@ -292,7 +289,7 @@ static void bmw_LoopShellWalker_begin(BMWalker *walker, void *data)
case BM_FACE: {
BMFace *f = (BMFace *)h;
BMLoop *l = BM_FACE_FIRST_LOOP(f);
- /* walker will handle other loops within the face */
+ /* Walker will handle other loops within the face. */
bmw_LoopShellWalker_visitLoop(walker, l);
break;
}
@@ -312,7 +309,7 @@ static void bmw_LoopShellWalker_step_impl(BMWalker *walker, BMLoop *l)
BMEdge *e_edj_pair[2];
int i;
- /* seems paranoid, but one caller also walks edges */
+ /* Seems paranoid, but one caller also walks edges. */
BLI_assert(l->head.htype == BM_LOOP);
bmw_LoopShellWalker_visitLoop(walker, l->next);
@@ -409,7 +406,7 @@ static void bmw_LoopShellWireWalker_visitVert(BMWalker *walker, BMVert *v, const
bmw_LoopShellWalker_visitEdgeWire(walker, e);
- /* check if we step onto a non-wire vertex */
+ /* Check if we step onto a non-wire vertex. */
v_other = BM_edge_other_vert(e, v);
BM_ITER_ELEM (l, &iter, v_other, BM_LOOPS_OF_VERT) {
@@ -463,7 +460,7 @@ static void bmw_LoopShellWireWalker_begin(BMWalker *walker, void *data)
break;
}
case BM_FACE: {
- /* wire verts will be walked over */
+ /* Wire verts will be walked over. */
break;
}
default:
@@ -581,12 +578,12 @@ static void bmw_ConnectedVertexWalker_visitVertex(BMWalker *walker, BMVert *v)
BMwConnectedVertexWalker *vwalk;
if (BLI_gset_haskey(walker->visit_set, v)) {
- /* already visited */
+ /* Already visited. */
return;
}
if (!bmw_mask_check_vert(walker, v)) {
- /* not flagged for walk */
+ /* Not flagged for walk. */
return;
}
@@ -670,10 +667,9 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
BMEdge *e;
BMFace *f;
BMLoop *l;
- /* int found = 0; */
memcpy(&owalk, BMW_current_state(walker), sizeof(owalk));
- /* normally we'd remove here, but delay until after error checking */
+ /* Normally we'd remove here, but delay until after error checking. */
iwalk = &owalk;
l = iwalk->curloop;
@@ -681,7 +677,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
v = BM_edge_other_vert(e, iwalk->lastv);
- /* pop off current state */
+ /* Pop off current state. */
BMW_state_remove(walker);
f = l->f;
@@ -699,7 +695,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
}
}
else {
- /* treat non-manifold edges as boundaries */
+ /* Treat non-manifold edges as boundaries. */
f = l->f;
e = l->e;
break;
@@ -717,9 +713,16 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
iwalk = BMW_state_add(walker);
iwalk->base = owalk.base;
- // if (!BMO_face_flag_test(walker->bm, l->f, walker->restrictflag))
- // iwalk->curloop = l->radial_next;
- iwalk->curloop = l; // else iwalk->curloop = l;
+#if 0
+ if (!BMO_face_flag_test(walker->bm, l->f, walker->restrictflag)) {
+ iwalk->curloop = l->radial_next;
+ }
+ else {
+ iwalk->curloop = l;
+ }
+#else
+ iwalk->curloop = l;
+#endif
iwalk->lastv = v;
return owalk.curloop;
@@ -763,7 +766,7 @@ static void *bmw_IslandWalker_step_ex(BMWalker *walker, bool only_manifold)
l_iter = l_first = BM_FACE_FIRST_LOOP(iwalk->cur);
do {
- /* could skip loop here too, but don't add unless we need it */
+ /* Could skip loop here too, but don't add unless we need it. */
if (!bmw_mask_check_edge(walker, l_iter->e)) {
continue;
}
@@ -772,7 +775,7 @@ static void *bmw_IslandWalker_step_ex(BMWalker *walker, bool only_manifold)
if (only_manifold && (l_iter->radial_next != l_iter)) {
int face_count = 1;
- /* check other faces (not this one), ensure only one other can be walked onto. */
+ /* Check other faces (not this one), ensure only one other Can be walked onto. */
l_radial_iter = l_iter->radial_next;
do {
if (bmw_mask_check_face(walker, l_radial_iter->f)) {
@@ -796,7 +799,7 @@ static void *bmw_IslandWalker_step_ex(BMWalker *walker, bool only_manifold)
continue;
}
- /* saves checking BLI_gset_haskey below (manifold edges there's a 50% chance) */
+ /* Saves checking #BLI_gset_haskey below (manifold edges there's a 50% chance). */
if (f == iwalk->cur) {
continue;
}
@@ -947,12 +950,12 @@ static void bmw_EdgeLoopWalker_begin(BMWalker *walker, void *data)
}
if (f_best) {
- /* only use hub selection for 5+ sides else this could
+ /* Only use hub selection for 5+ sides else this could
* conflict with normal edge loop selection. */
lwalk->f_hub = f_best->len > 4 ? f_best : NULL;
}
else {
- /* edge doesn't have any faces connected to it */
+ /* Edge doesn't have any faces connected to it. */
lwalk->f_hub = NULL;
}
}
@@ -960,7 +963,7 @@ static void bmw_EdgeLoopWalker_begin(BMWalker *walker, void *data)
lwalk->f_hub = NULL;
}
- /* rewind */
+ /* Rewind. */
while ((owalk_pt = BMW_current_state(walker))) {
owalk = *((BMwEdgeLoopWalker *)owalk_pt);
BMW_walk(walker);
@@ -1007,7 +1010,7 @@ static void *bmw_EdgeLoopWalker_step(BMWalker *walker)
nexte = BM_edge_exists(v, l->v);
if (bmw_mask_check_edge(walker, nexte) && !BLI_gset_haskey(walker->visit_set, nexte) &&
- /* never step onto a boundary edge, this gives odd-results */
+ /* Never step onto a boundary edge, this gives odd-results. */
(BM_edge_is_boundary(nexte) == false)) {
lwalk = BMW_state_add(walker);
lwalk->cur = nexte;
@@ -1024,7 +1027,7 @@ static void *bmw_EdgeLoopWalker_step(BMWalker *walker)
else if (l == NULL) { /* WIRE EDGE */
BMIter eiter;
- /* match trunk: mark all connected wire edges */
+ /* Match trunk: mark all connected wire edges. */
for (int i = 0; i < 2; i++) {
v = i ? e->v2 : e->v1;
@@ -1051,9 +1054,8 @@ static void *bmw_EdgeLoopWalker_step(BMWalker *walker)
vert_edge_tot = BM_vert_edge_count_nonwire(v);
- /* Typical loopiong over edges in the middle of a mesh */
- /* However, why use 2 here at all?
- * I guess for internal ngon loops it can be useful. Antony R. */
+ /* Typical looping over edges in the middle of a mesh.
+ * Why use 2 here at all? - for internal ngon loops it can be useful. */
if (ELEM(vert_edge_tot, 4, 2)) {
int i_opposite = vert_edge_tot / 2;
int i = 0;
@@ -1094,15 +1096,15 @@ static void *bmw_EdgeLoopWalker_step(BMWalker *walker)
vert_edge_tot = BM_vert_edge_count_nonwire(v);
- /* check if we should step, this is fairly involved */
+ /* Check if we should step, this is fairly involved. */
if (
- /* walk over boundary of faces but stop at corners */
+ /* Walk over boundary of faces but stop at corners. */
(owalk.is_single == false && vert_edge_tot > 2) ||
- /* initial edge was a boundary, so is this edge and vertex is only a part of this face
- * this lets us walk over the boundary of an ngon which is handy */
+ /* Initial edge was a boundary, so is this edge and vertex is only a part of this face
+ * this lets us walk over the boundary of an ngon which is handy. */
(owalk.is_single == true && vert_edge_tot == 2 && BM_edge_is_boundary(e))) {
- /* find next boundary edge in the fan */
+ /* Find next boundary edge in the fan. */
do {
l = BM_loop_other_edge_loop(l, v);
if (BM_edge_is_manifold(l->e)) {
@@ -1148,14 +1150,16 @@ static void *bmw_EdgeLoopWalker_step(BMWalker *walker)
*
* Starts at a tool-flagged face and walks over the face loop
* Conditions for starting and stepping the face loop have been
- * tuned in an attempt to match the face loops built by EditMesh
+ * tuned in an attempt to match the face loops built by edit-mesh
* \{ */
-/* Check whether the face loop should includes the face specified
- * by the given BMLoop */
+/**
+ * Check whether the face loop should includes the face specified
+ * by the given #BMLoop.
+ */
static bool bmw_FaceLoopWalker_include_face(BMWalker *walker, BMLoop *l)
{
- /* face must have degree 4 */
+ /* Face must have degree 4. */
if (l->f->len != 4) {
return false;
}
@@ -1164,7 +1168,7 @@ static bool bmw_FaceLoopWalker_include_face(BMWalker *walker, BMLoop *l)
return false;
}
- /* the face must not have been already visited */
+ /* The face must not have been already visited. */
if (BLI_gset_haskey(walker->visit_set, l->f) && BLI_gset_haskey(walker->visit_set_alt, l->e)) {
return false;
}
@@ -1172,23 +1176,22 @@ static bool bmw_FaceLoopWalker_include_face(BMWalker *walker, BMLoop *l)
return true;
}
-/* Check whether the face loop can start from the given edge */
+/* Check whether the face loop can start from the given edge. */
static bool bmw_FaceLoopWalker_edge_begins_loop(BMWalker *walker, BMEdge *e)
{
- /* There is no face loop starting from a wire edge */
+ /* There is no face loop starting from a wire edge. */
if (BM_edge_is_wire(e)) {
return false;
}
- /* Don't start a loop from a boundary edge if it cannot
- * be extended to cover any faces */
+ /* Don't start a loop from a boundary edge if it cannot be extended to cover any faces. */
if (BM_edge_is_boundary(e)) {
if (!bmw_FaceLoopWalker_include_face(walker, e->l)) {
return false;
}
}
- /* Don't start a face loop from non-manifold edges */
+ /* Don't start a face loop from non-manifold edges. */
if (!BM_edge_is_manifold(e)) {
return false;
}
@@ -1212,7 +1215,7 @@ static void bmw_FaceLoopWalker_begin(BMWalker *walker, void *data)
lwalk->no_calc = false;
BLI_gset_insert(walker->visit_set, lwalk->l->f);
- /* rewind */
+ /* Rewind. */
while ((owalk_pt = BMW_current_state(walker))) {
owalk = *((BMwFaceLoopWalker *)owalk_pt);
BMW_walk(walker);
@@ -1277,7 +1280,7 @@ static void *bmw_FaceLoopWalker_step(BMWalker *walker)
lwalk->no_calc = false;
}
- /* both may already exist */
+ /* Both may already exist. */
BLI_gset_add(walker->visit_set_alt, l->e);
BLI_gset_add(walker->visit_set, l->f);
}
@@ -1312,7 +1315,7 @@ static void bmw_EdgeringWalker_begin(BMWalker *walker, void *data)
BLI_gset_insert(walker->visit_set, lwalk->l->e);
- /* rewind */
+ /* Rewind. */
while ((owalk_pt = BMW_current_state(walker))) {
owalk = *((BMwEdgeringWalker *)owalk_pt);
BMW_walk(walker);
@@ -1370,10 +1373,10 @@ static void *bmw_EdgeringWalker_step(BMWalker *walker)
e = l->e;
if (!EDGE_CHECK(e)) {
- /* walker won't traverse to a non-manifold edge, but may
+ /* Walker won't traverse to a non-manifold edge, but may
* be started on one, and should not traverse *away* from
* a non-manifold edge (non-manifold edges are never in an
- * edge ring with manifold edges */
+ * edge ring with manifold edges. */
return e;
}
@@ -1394,7 +1397,7 @@ static void *bmw_EdgeringWalker_step(BMWalker *walker)
i -= 2;
}
}
- /* only walk to manifold edge */
+ /* Only walk to manifold edge. */
if ((l->f->len % 2 == 0) && EDGE_CHECK(l->e) && !BLI_gset_haskey(walker->visit_set, l->e))
#else
@@ -1404,7 +1407,7 @@ static void *bmw_EdgeringWalker_step(BMWalker *walker)
if ((l->f->len != 4) || !EDGE_CHECK(l->e) || !bmw_mask_check_face(walker, l->f)) {
l = owalk.l->next->next;
}
- /* only walk to manifold edge */
+ /* Only walk to manifold edge. */
if ((l->f->len == 4) && EDGE_CHECK(l->e) && !BLI_gset_haskey(walker->visit_set, l->e))
#endif
{
@@ -1547,8 +1550,8 @@ static void *bmw_UVEdgeWalker_step(BMWalker *walker)
return l;
}
- /* go over loops around l->v and nl->v and see which ones share l and nl's
- * mloopuv's coordinates. in addition, push on l->next if necessary */
+ /* Go over loops around `l->v` and `l->next->v` and see which ones share `l` and `l->next`
+ * UV's coordinates. in addition, push on `l->next` if necessary. */
for (i = 0; i < 2; i++) {
BMIter liter;
BMLoop *l_pivot, *l_radial;
@@ -1600,7 +1603,7 @@ static BMWalker bmw_VertShellWalker_Type = {
bmw_VertShellWalker_yield,
sizeof(BMwShellWalker),
BMW_BREADTH_FIRST,
- BM_EDGE, /* valid restrict masks */
+ BM_EDGE, /* Valid restrict masks. */
};
static BMWalker bmw_LoopShellWalker_Type = {
@@ -1610,7 +1613,7 @@ static BMWalker bmw_LoopShellWalker_Type = {
bmw_LoopShellWalker_yield,
sizeof(BMwLoopShellWalker),
BMW_BREADTH_FIRST,
- BM_EDGE, /* valid restrict masks */
+ BM_EDGE, /* Valid restrict masks. */
};
static BMWalker bmw_LoopShellWireWalker_Type = {
@@ -1620,7 +1623,7 @@ static BMWalker bmw_LoopShellWireWalker_Type = {
bmw_LoopShellWireWalker_yield,
sizeof(BMwLoopShellWireWalker),
BMW_BREADTH_FIRST,
- BM_EDGE, /* valid restrict masks */
+ BM_EDGE, /* Valid restrict masks. */
};
static BMWalker bmw_FaceShellWalker_Type = {
@@ -1630,7 +1633,7 @@ static BMWalker bmw_FaceShellWalker_Type = {
bmw_FaceShellWalker_yield,
sizeof(BMwShellWalker),
BMW_BREADTH_FIRST,
- BM_EDGE, /* valid restrict masks */
+ BM_EDGE, /* Valid restrict masks. */
};
static BMWalker bmw_IslandboundWalker_Type = {
@@ -1640,7 +1643,7 @@ static BMWalker bmw_IslandboundWalker_Type = {
bmw_IslandboundWalker_yield,
sizeof(BMwIslandboundWalker),
BMW_DEPTH_FIRST,
- BM_FACE, /* valid restrict masks */
+ BM_FACE, /* Valid restrict masks. */
};
static BMWalker bmw_IslandWalker_Type = {
@@ -1650,17 +1653,17 @@ static BMWalker bmw_IslandWalker_Type = {
bmw_IslandWalker_yield,
sizeof(BMwIslandWalker),
BMW_BREADTH_FIRST,
- BM_EDGE | BM_FACE, /* valid restrict masks */
+ BM_EDGE | BM_FACE, /* Valid restrict masks. */
};
static BMWalker bmw_IslandManifoldWalker_Type = {
BM_FACE,
bmw_IslandWalker_begin,
- bmw_IslandManifoldWalker_step, /* only difference with BMW_ISLAND */
+ bmw_IslandManifoldWalker_step, /* Only difference with #BMW_ISLAND. */
bmw_IslandWalker_yield,
sizeof(BMwIslandWalker),
BMW_BREADTH_FIRST,
- BM_EDGE | BM_FACE, /* valid restrict masks */
+ BM_EDGE | BM_FACE, /* Valid restrict masks. */
};
static BMWalker bmw_EdgeLoopWalker_Type = {
@@ -1671,7 +1674,7 @@ static BMWalker bmw_EdgeLoopWalker_Type = {
sizeof(BMwEdgeLoopWalker),
BMW_DEPTH_FIRST,
0,
- /* valid restrict masks */ /* could add flags here but so far none are used */
+ /* Valid restrict masks. */ /* Could add flags here but so far none are used. */
};
static BMWalker bmw_FaceLoopWalker_Type = {
@@ -1682,7 +1685,7 @@ static BMWalker bmw_FaceLoopWalker_Type = {
sizeof(BMwFaceLoopWalker),
BMW_DEPTH_FIRST,
0,
- /* valid restrict masks */ /* could add flags here but so far none are used */
+ /* Valid restrict masks. */ /* Could add flags here but so far none are used. */
};
static BMWalker bmw_EdgeringWalker_Type = {
@@ -1692,7 +1695,7 @@ static BMWalker bmw_EdgeringWalker_Type = {
bmw_EdgeringWalker_yield,
sizeof(BMwEdgeringWalker),
BMW_DEPTH_FIRST,
- BM_EDGE, /* valid restrict masks */
+ BM_EDGE, /* Valid restrict masks. */
};
static BMWalker bmw_EdgeboundaryWalker_Type = {
@@ -1712,7 +1715,7 @@ static BMWalker bmw_UVEdgeWalker_Type = {
bmw_UVEdgeWalker_yield,
sizeof(BMwUVEdgeWalker),
BMW_DEPTH_FIRST,
- BM_EDGE, /* valid restrict masks */
+ BM_EDGE, /* Valid restrict masks. */
};
static BMWalker bmw_ConnectedVertexWalker_Type = {
@@ -1722,23 +1725,23 @@ static BMWalker bmw_ConnectedVertexWalker_Type = {
bmw_ConnectedVertexWalker_yield,
sizeof(BMwConnectedVertexWalker),
BMW_BREADTH_FIRST,
- BM_VERT, /* valid restrict masks */
+ BM_VERT, /* Valid restrict masks. */
};
BMWalker *bm_walker_types[] = {
- &bmw_VertShellWalker_Type, /* BMW_VERT_SHELL */
- &bmw_LoopShellWalker_Type, /* BMW_LOOP_SHELL */
- &bmw_LoopShellWireWalker_Type, /* BMW_LOOP_SHELL_WIRE */
- &bmw_FaceShellWalker_Type, /* BMW_FACE_SHELL */
- &bmw_EdgeLoopWalker_Type, /* BMW_EDGELOOP */
- &bmw_FaceLoopWalker_Type, /* BMW_FACELOOP */
- &bmw_EdgeringWalker_Type, /* BMW_EDGERING */
- &bmw_EdgeboundaryWalker_Type, /* BMW_EDGEBOUNDARY */
- &bmw_UVEdgeWalker_Type, /* BMW_LOOPDATA_ISLAND */
- &bmw_IslandboundWalker_Type, /* BMW_ISLANDBOUND */
- &bmw_IslandWalker_Type, /* BMW_ISLAND */
- &bmw_IslandManifoldWalker_Type, /* BMW_ISLAND_MANIFOLD */
- &bmw_ConnectedVertexWalker_Type, /* BMW_CONNECTED_VERTEX */
+ &bmw_VertShellWalker_Type, /* #BMW_VERT_SHELL */
+ &bmw_LoopShellWalker_Type, /* #BMW_LOOP_SHELL */
+ &bmw_LoopShellWireWalker_Type, /* #BMW_LOOP_SHELL_WIRE */
+ &bmw_FaceShellWalker_Type, /* #BMW_FACE_SHELL */
+ &bmw_EdgeLoopWalker_Type, /* #BMW_EDGELOOP */
+ &bmw_FaceLoopWalker_Type, /* #BMW_FACELOOP */
+ &bmw_EdgeringWalker_Type, /* #BMW_EDGERING */
+ &bmw_EdgeboundaryWalker_Type, /* #BMW_EDGEBOUNDARY */
+ &bmw_UVEdgeWalker_Type, /* #BMW_LOOPDATA_ISLAND */
+ &bmw_IslandboundWalker_Type, /* #BMW_ISLANDBOUND */
+ &bmw_IslandWalker_Type, /* #BMW_ISLAND */
+ &bmw_IslandManifoldWalker_Type, /* #BMW_ISLAND_MANIFOLD */
+ &bmw_ConnectedVertexWalker_Type, /* #BMW_CONNECTED_VERTEX */
};
const int bm_totwalkers = ARRAY_SIZE(bm_walker_types);
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index cd12a260f82..36fe6ee655c 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -7229,14 +7229,14 @@ static void set_profile_spacing(BevelParams *bp, ProfileSpacing *pro_spacing, bo
*
* where edges are A, B, and C, following a face around vertices a, b, c, d.
* th1 is angle abc and th2 is angle bcd;
- * and the argument EdgeHalf eb is B, going from b to c.
+ * and the argument `EdgeHalf eb` is B, going from b to c.
* In general case, edge offset specs for A, B, C have
* the form ka*t, kb*t, kc*t where ka, kb, kc are some factors
* (may be 0) and t is the current bp->offset.
* We want to calculate t at which the clone of B parallel
* to it collapses. This can be calculated using trig.
* Another case of geometry collision that can happen is
- * When B slides along A because A is unbeveled.
+ * When B slides along A because A is un-beveled.
* Then it might collide with a. Similarly for B sliding along C.
*/
static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb)
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 60c49587387..6ae889fcee5 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -294,8 +294,7 @@ static void bm_decim_build_edge_cost_single(BMEdge *e,
/* subtract existing cost to further differentiate edges from one another
*
* keep topology cost below 0.0 so their values don't interfere with quadric cost,
- * (and they get handled first).
- * */
+ * (and they get handled first). */
if (vweights == NULL) {
cost = bm_decim_build_edge_cost_single_squared__topology(e) - cost;
}
diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.h b/source/blender/compositor/operations/COM_BokehImageOperation.h
index 01ffa026152..2d775bdf738 100644
--- a/source/blender/compositor/operations/COM_BokehImageOperation.h
+++ b/source/blender/compositor/operations/COM_BokehImageOperation.h
@@ -55,7 +55,7 @@ class BokehImageOperation : public NodeOperation {
NodeBokehImage *m_data;
/**
- * \brief precalced center of the image
+ * \brief precalculate center of the image
*/
float m_center[2];
@@ -87,7 +87,7 @@ class BokehImageOperation : public NodeOperation {
/**
* \brief determine the coordinate of a flap corner.
*
- * \param r: result in bokehimage space are stored [x,y]
+ * \param r: result in bokeh-image space are stored [x,y]
* \param flapNumber: the flap number to calculate
* \param distance: the lens distance is used to simulate lens shifts
*/
diff --git a/source/blender/compositor/operations/COM_DotproductOperation.cpp b/source/blender/compositor/operations/COM_DotproductOperation.cpp
index 750e4308d11..5914be21453 100644
--- a/source/blender/compositor/operations/COM_DotproductOperation.cpp
+++ b/source/blender/compositor/operations/COM_DotproductOperation.cpp
@@ -39,7 +39,7 @@ void DotproductOperation::deinitExecution()
this->m_input2Operation = nullptr;
}
-/** \todo: current implementation is the inverse of a dotproduct. not 'logically' correct
+/** \todo current implementation is the inverse of a dot-product. not 'logically' correct
*/
void DotproductOperation::executePixelSampled(float output[4],
float x,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 463efe52375..ffddb196ae4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -1238,7 +1238,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
// TODO: loc vs rot vs scale?
if (&ct->tar->id == id) {
/* Constraint targeting own object:
- * - This case is fine IFF we're dealing with a bone
+ * - This case is fine IF we're dealing with a bone
* constraint pointing to its own armature. In that
* case, it's just transform -> bone.
* - If however it is a real self targeting case, just
@@ -1814,7 +1814,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
RELATION_FLAG_GODMODE);
}
- /* Final transform is whetever solver gave to us. */
+ /* Final transform is whatever the solver gave to us. */
if (object->rigidbody_object->type == RBO_TYPE_ACTIVE) {
/* We do not have to update the objects final transform after the simulation if it is
* passive or controlled by the animation system in blender.
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index e472d82f2ee..34465c12914 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -193,6 +193,32 @@ bool deg_iterator_components_step(BLI_Iterator *iter)
}
}
+ /* The volume component. */
+ if (data->geometry_component_id == 2) {
+ data->geometry_component_id++;
+
+ /* Don't use a temporary object for this component, when the owner is a volume object. */
+ if (data->geometry_component_owner->type == OB_VOLUME) {
+ iter->current = data->geometry_component_owner;
+ return true;
+ }
+
+ const VolumeComponent *component = geometry_set->get_component_for_read<VolumeComponent>();
+ if (component != nullptr) {
+ const Volume *volume = component->get_for_read();
+
+ if (volume != nullptr) {
+ Object *temp_object = &data->temp_geometry_component_object;
+ *temp_object = *data->geometry_component_owner;
+ temp_object->type = OB_VOLUME;
+ temp_object->data = (void *)volume;
+ temp_object->runtime.select_id = data->geometry_component_owner->runtime.select_id;
+ iter->current = temp_object;
+ return true;
+ }
+ }
+ }
+
data->geometry_component_owner = nullptr;
return false;
}
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h
index c4d36685bb8..e2d3b3fc36f 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.h
+++ b/source/blender/depsgraph/intern/node/deg_node_id.h
@@ -88,7 +88,7 @@ struct IDNode : public Node {
* which could be "stale" pointer. */
uint id_orig_session_uuid;
- /* Evaluated datablock.
+ /* Evaluated data-block.
* Will be covered by the copy-on-write system if the ID Type needs it. */
ID *id_cow;
@@ -107,7 +107,7 @@ struct IDNode : public Node {
eDepsNode_LinkedState_Type linked_state;
- /* Indicates the datablock is visible in the evaluated scene. */
+ /* Indicates the data-block is visible in the evaluated scene. */
bool is_directly_visible;
/* For the collection type of ID, denotes whether collection was fully
diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
index 90948d67895..31e54e371b1 100644
--- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c
+++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
@@ -363,7 +363,7 @@ static void eevee_cryptomatte_download_buffer(EEVEE_Data *vedata, GPUFrameBuffer
download_buffer);
/* Integrate download buffer into the accum buffer.
- * The download buffer contains upto 3 floats per pixel (one float per cryptomatte layer.
+ * The download buffer contains up to 3 floats per pixel (one float per cryptomatte layer.
*
* NOTE: here we deviate from the cryptomatte standard. During integration the standard always
* sort the samples by its weight to make sure that samples with the lowest weight
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 153dcfb6ea7..6627d38366f 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -214,6 +214,7 @@ void GPENCIL_cache_init(void *ved)
NULL :
false;
pd->do_onion = show_onion && !hide_overlay && !playing;
+ pd->playing = playing;
/* Save simplify flags (can change while drawing, so it's better to save). */
Scene *scene = draw_ctx->scene;
pd->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, playing);
@@ -241,6 +242,7 @@ void GPENCIL_cache_init(void *ved)
pd->simplify_fill = false;
pd->simplify_fx = false;
pd->fade_layer_opacity = -1.0f;
+ pd->playing = false;
}
{
@@ -617,6 +619,15 @@ void GPENCIL_cache_populate(void *ved, Object *ob)
/* Special case for rendering onion skin. */
bGPdata *gpd = (bGPdata *)ob->data;
bool do_onion = (!pd->is_render) ? pd->do_onion : (gpd->onion_flag & GP_ONION_GHOST_ALWAYS);
+ gpd->runtime.playing = (short)pd->playing;
+
+ /* When render in background the active frame could not be properly set due thread priority
+ * better set again. This is not required in viewport. */
+ if (txl->render_depth_tx) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ gpl->actframe = BKE_gpencil_layer_frame_get(gpl, pd->cfra, GP_GETFRAME_USE_PREV);
+ }
+ }
/* When render in background the active frame could not be properly set due thread priority
* better set again. This is not required in viewport. */
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index d0bd56b42dd..2b07ea53187 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -342,6 +342,8 @@ typedef struct GPENCIL_PrivateData {
/* Display onion skinning */
bool do_onion;
+ /* Playing animation */
+ bool playing;
/* simplify settings */
bool simplify_fill;
bool simplify_fx;
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
index cb65fbd6ae7..f4af5ebff99 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
@@ -235,7 +235,7 @@ static void gpencil_vfx_rim(RimShaderFxData *fx, Object *ob, gpIterVfxData *iter
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
if (fx->mode == eShaderFxRimMode_Overlay) {
- /* We cannot do custom blending on MultiTarget framebuffers.
+ /* We cannot do custom blending on multi-target frame-buffers.
* Workaround by doing 2 passes. */
grp = DRW_shgroup_create_sub(grp);
DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL);
@@ -363,7 +363,7 @@ static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData
copy_v2_v2(wave_ofs, wave_dir);
SWAP(float, wave_ofs[0], wave_ofs[1]);
wave_ofs[1] *= -1.0f;
- /* Keep world space scalling and aspect ratio. */
+ /* Keep world space scaling and aspect ratio. */
mul_v2_fl(wave_dir, 1.0f / (max_ff(1e-8f, fx->period) * distance_factor));
mul_v2_v2(wave_dir, vp_size);
mul_v2_fl(wave_ofs, fx->amplitude * distance_factor);
@@ -515,7 +515,7 @@ static void gpencil_vfx_wave(WaveShaderFxData *fx, Object *ob, gpIterVfxData *it
copy_v2_v2(wave_ofs, wave_dir);
SWAP(float, wave_ofs[0], wave_ofs[1]);
wave_ofs[1] *= -1.0f;
- /* Keep world space scalling and aspect ratio. */
+ /* Keep world space scaling and aspect ratio. */
mul_v2_fl(wave_dir, 1.0f / (max_ff(1e-8f, fx->period) * distance_factor));
mul_v2_v2(wave_dir, vp_size);
mul_v2_fl(wave_ofs, fx->amplitude * distance_factor);
@@ -647,7 +647,7 @@ void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, Object *ob, GPENCIL_tObjec
DRW_shgroup_uniform_int_copy(grp, "isFirstPass", true);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
- /* We cannot do custom blending on MultiTarget framebuffers.
+ /* We cannot do custom blending on multi-target frame-buffers.
* Workaround by doing 2 passes. */
grp = DRW_shgroup_create_sub(grp);
DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL);
diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c
index 7f9290a6c3a..19af3ae7e5d 100644
--- a/source/blender/draw/engines/overlay/overlay_gpencil.c
+++ b/source/blender/draw/engines/overlay/overlay_gpencil.c
@@ -258,6 +258,16 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
copy_m4_m4(mat, ob->obmat);
+ /* Rotate and scale except align to cursor. */
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
+ if (gpl != NULL) {
+ if (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_CURSOR) {
+ float matrot[3][3];
+ copy_m3_m4(matrot, gpl->layer_mat);
+ mul_m4_m4m3(mat, mat, matrot);
+ }
+ }
+
float viewinv[4][4];
/* Set the grid in the selected axis */
switch (ts->gp_sculpt.lock_axis) {
@@ -294,6 +304,11 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
mul_v2_v2fl(size, gpd->grid.scale, 2.0f * ED_scene_grid_scale(scene, &grid_unit));
rescale_m4(mat, (float[3]){size[0], size[1], 0.0f});
+ /* Apply layer loc transform, except cursor mode. */
+ if ((gpl != NULL) && (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
+ add_v3_v3(mat[3], gpl->layer_mat[3]);
+ }
+
const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
int line_ct = gridlines * 4 + 2;
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
index e1523db36c7..8feacf8b026 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -800,20 +800,20 @@ static void gpencil_edit_curve_stroke_iter_cb(bGPDlayer *gpl,
};
/* First segment. */
- copy_v3_v3(vert_ptr->pos, bezt->vec[0]);
+ mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[0]);
vert_ptr->data = vflag[0];
vert_ptr++;
- copy_v3_v3(vert_ptr->pos, bezt->vec[1]);
+ mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[1]);
vert_ptr->data = vflag[1];
vert_ptr++;
/* Second segment. */
- copy_v3_v3(vert_ptr->pos, bezt->vec[1]);
+ mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[1]);
vert_ptr->data = vflag[1];
vert_ptr++;
- copy_v3_v3(vert_ptr->pos, bezt->vec[2]);
+ mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[2]);
vert_ptr->data = vflag[2];
vert_ptr++;
}
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 5f7aa28c3c9..67778584d25 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -344,7 +344,7 @@ void DRW_state_reset(void)
/* Should stay constant during the whole rendering. */
GPU_point_size(5);
GPU_line_smooth(false);
- /* Bypass U.pixelsize factor by using a factor of 0.0f. Will be clamped to 1.0f. */
+ /* Bypass #U.pixelsize factor by using a factor of 0.0f. Will be clamped to 1.0f. */
GPU_line_width(0.0f);
}
diff --git a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
index a87b4558227..0ecfc397e95 100644
--- a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
@@ -1,7 +1,7 @@
/* ---------------------------------------------------------------------------------
* File: es3-kepler\FXAA/FXAA3_11.h
* SDK Version: v3.00
- * Email: gameworks@nvidia.com
+ * Email: <gameworks@nvidia.com>
* Site: http://developer.nvidia.com/
*
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 05cbb3ef48f..64fa93773b9 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -133,7 +133,16 @@ static void acf_generic_root_backdrop(bAnimContext *ac,
UI_draw_roundbox_corner_set((expanded) ? UI_CNR_TOP_LEFT :
(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
UI_draw_roundbox_3fv_alpha(
- true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f);
+ &(const rctf){
+ .xmin = offset,
+ .xmax = v2d->cur.xmax + EXTRA_SCROLL_PAD,
+ .ymin = yminc,
+ .ymax = ymaxc,
+ },
+ true,
+ 8,
+ color,
+ 1.0f);
}
/* get backdrop color for data expanders under top-level Scene/Object */
@@ -464,7 +473,16 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi
*/
UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
UI_draw_roundbox_3fv_alpha(
- true, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f);
+ &(const rctf){
+ .xmin = 0,
+ .xmax = v2d->cur.xmax + EXTRA_SCROLL_PAD,
+ .ymin = yminc - 2,
+ .ymax = ymaxc,
+ },
+ true,
+ 8,
+ color,
+ 1.0f);
}
/* name for summary entries */
@@ -875,7 +893,16 @@ static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc
/* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
UI_draw_roundbox_3fv_alpha(
- true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f);
+ &(const rctf){
+ .xmin = offset,
+ .xmax = v2d->cur.xmax + EXTRA_SCROLL_PAD,
+ .ymin = yminc,
+ .ymax = ymaxc,
+ },
+ true,
+ 8,
+ color,
+ 1.0f);
}
/* name for group entries */
@@ -1149,7 +1176,16 @@ static void acf_nla_controls_backdrop(bAnimContext *ac,
/* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
UI_draw_roundbox_3fv_alpha(
- true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5, color, 1.0f);
+ &(const rctf){
+ .xmin = offset,
+ .xmax = v2d->cur.xmax + EXTRA_SCROLL_PAD,
+ .ymin = yminc,
+ .ymax = ymaxc,
+ },
+ true,
+ 5,
+ color,
+ 1.0f);
}
/* name for nla controls expander entries */
@@ -3936,13 +3972,16 @@ static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float y
/* draw slightly shifted up vertically to look like it has more separation from other channels,
* but we then need to slightly shorten it so that it doesn't look like it overlaps
*/
- UI_draw_roundbox_4fv(true,
- offset,
- yminc + NLACHANNEL_SKIP,
- (float)v2d->cur.xmax,
- ymaxc + NLACHANNEL_SKIP - 1,
- 8,
- color);
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = offset,
+ .xmax = (float)v2d->cur.xmax,
+ .ymin = yminc + NLACHANNEL_SKIP,
+ .ymax = ymaxc + NLACHANNEL_SKIP - 1,
+ },
+ true,
+ 8,
+ color);
}
/* name for nla action entries */
@@ -4710,7 +4749,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
(float)CFRA);
NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(
- &nla_cache, &id_ptr, adt, &anim_eval_context, false);
+ &nla_cache, &id_ptr, adt, &anim_eval_context);
/* get current frame and apply NLA-mapping to it (if applicable) */
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
@@ -4766,7 +4805,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
(float)CFRA);
NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(
- &nla_cache, &id_ptr, key->adt, &anim_eval_context, false);
+ &nla_cache, &id_ptr, key->adt, &anim_eval_context);
/* get current frame and apply NLA-mapping to it (if applicable) */
const float remapped_frame = BKE_nla_tweakedit_remap(
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index a6e96a4d919..7afb03b833d 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -393,7 +393,11 @@ static void anim_channels_select_set(bAnimContext *ac,
FCurve *fcu = (FCurve *)ale->data;
ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED);
- fcu->flag &= ~FCURVE_ACTIVE;
+ if ((fcu->flag & FCURVE_SELECTED) == 0) {
+ /* Only erase the ACTIVE flag when deselecting. This ensures that "select all curves"
+ * retains the currently active curve. */
+ fcu->flag &= ~FCURVE_ACTIVE;
+ }
break;
}
case ANIMTYPE_SHAPEKEY: {
@@ -1197,7 +1201,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn
rearrange_animchannel_islands(
&adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible);
- /* Add back non-local NLA tracks at the begining of the animation data's list. */
+ /* Add back non-local NLA tracks at the beginning of the animation data's list. */
if (!BLI_listbase_is_empty(&extracted_nonlocal_nla_tracks)) {
BLI_assert(is_liboverride);
((NlaTrack *)extracted_nonlocal_nla_tracks.last)->next = adt->nla_tracks.first;
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index e8146ca960a..db3a1b99135 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -1384,7 +1384,7 @@ static AnimationEvalContext nla_time_remap(const AnimationEvalContext *anim_eval
if (adt && adt->action == act) {
/* Get NLA context for value remapping. */
*r_nla_context = BKE_animsys_get_nla_keyframing_context(
- nla_cache, id_ptr, adt, anim_eval_context, false);
+ nla_cache, id_ptr, adt, anim_eval_context);
/* Apply NLA-mapping to frame. */
const float remapped_frame = BKE_nla_tweakedit_remap(
diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c
index 98b4d93fbf1..034378399b9 100644
--- a/source/blender/editors/animation/time_scrub_ui.c
+++ b/source/blender/editors/animation/time_scrub_ui.c
@@ -124,23 +124,22 @@ static void draw_current_frame(const Scene *scene,
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_3fv_alpha(true,
- frame_x - box_width / 2 + U.pixelsize / 2,
- scrub_region_rect->ymin + box_padding,
- frame_x + box_width / 2 + U.pixelsize / 2,
- scrub_region_rect->ymax - box_padding,
- 4 * UI_DPI_FAC,
- bg_color,
- 1.0f);
-
- UI_GetThemeColorShade4fv(TH_CFRAME, 5, bg_color);
- UI_draw_roundbox_aa(false,
- frame_x - box_width / 2 + U.pixelsize / 2,
- scrub_region_rect->ymin + box_padding,
- frame_x + box_width / 2 + U.pixelsize / 2,
- scrub_region_rect->ymax - box_padding,
- 4 * UI_DPI_FAC,
- bg_color);
+ float outline_color[4];
+ UI_GetThemeColorShade4fv(TH_CFRAME, 5, outline_color);
+
+ UI_draw_roundbox_4fv_ex(
+ &(const rctf){
+ .xmin = frame_x - box_width / 2 + U.pixelsize / 2,
+ .xmax = frame_x + box_width / 2 + U.pixelsize / 2,
+ .ymin = scrub_region_rect->ymin + box_padding,
+ .ymax = scrub_region_rect->ymax - box_padding,
+ },
+ bg_color,
+ NULL,
+ 1.0f,
+ outline_color,
+ U.pixelsize,
+ 4 * UI_DPI_FAC);
uchar text_color[4];
UI_GetThemeColor4ubv(TH_HEADER_TEXT_HI, text_color);
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index a0b8bf862d7..e538c20df6c 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -306,8 +306,7 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name)
return NULL;
}
-/* Call this before doing any duplications
- * */
+/* Call this before doing any duplications. */
void preEditBoneDuplicate(ListBase *editbones)
{
/* clear temp */
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 4b646bb26e2..0b3c3855059 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -1246,15 +1246,15 @@ static void pose_slide_opdef_properties(wmOperatorType *ot)
{
PropertyRNA *prop;
- prop = RNA_def_float_percentage(ot->srna,
- "percentage",
- 0.5f,
- 0.0f,
- 1.0f,
- "Percentage",
- "Weighting factor for which keyframe is favored more",
- 0.0,
- 1.0);
+ prop = RNA_def_float_factor(ot->srna,
+ "factor",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Factor",
+ "Weighting factor for which keyframe is favored more",
+ 0.0,
+ 1.0);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_int(ot->srna,
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index 4097275a2b9..82f7b456284 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -1242,7 +1242,7 @@ static void curve_select_random(ListBase *editnurb, float randfac, int seed, boo
static int curve_select_random_exec(bContext *C, wmOperator *op)
{
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
- const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const float randfac = RNA_float_get(op->ptr, "ratio");
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
ViewLayer *view_layer = CTX_data_view_layer(C);
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index eb40500d011..cbca230da7e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -320,6 +320,16 @@ static int gizmo_button2d_cursor_get(wmGizmo *gz)
return WM_CURSOR_DEFAULT;
}
+static void gizmo_button2d_bounds(bContext *C, wmGizmo *gz, rcti *r_bounding_box)
+{
+ ScrArea *area = CTX_wm_area(C);
+ float rad = CIRCLE_RESOLUTION * U.dpi_fac / 2.0f;
+ r_bounding_box->xmin = gz->matrix_basis[3][0] + area->totrct.xmin - rad;
+ r_bounding_box->ymin = gz->matrix_basis[3][1] + area->totrct.ymin - rad;
+ r_bounding_box->xmax = r_bounding_box->xmin + rad;
+ r_bounding_box->ymax = r_bounding_box->ymin + rad;
+}
+
static void gizmo_button2d_free(wmGizmo *gz)
{
ButtonGizmo2D *shape = (ButtonGizmo2D *)gz;
@@ -346,6 +356,7 @@ static void GIZMO_GT_button_2d(wmGizmoType *gzt)
gzt->draw_select = gizmo_button2d_draw_select;
gzt->test_select = gizmo_button2d_test_select;
gzt->cursor_get = gizmo_button2d_cursor_get;
+ gzt->screen_bounds_get = gizmo_button2d_bounds;
gzt->free = gizmo_button2d_free;
gzt->struct_size = sizeof(ButtonGizmo2D);
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index aae31b11025..166111c582c 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -276,7 +276,7 @@ void ED_gpencil_layer_frames_duplicate(bGPDlayer *gpl)
bGPDframe *gpfd;
/* duplicate frame, and deselect self */
- gpfd = BKE_gpencil_frame_duplicate(gpf);
+ gpfd = BKE_gpencil_frame_duplicate(gpf, true);
gpf->flag &= ~GP_FRAME_SELECT;
BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
@@ -361,7 +361,7 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
/* if frame is selected, make duplicate it and its strokes */
if (gpf->flag & GP_FRAME_SELECT) {
/* make a copy of this frame */
- bGPDframe *new_frame = BKE_gpencil_frame_duplicate(gpf);
+ bGPDframe *new_frame = BKE_gpencil_frame_duplicate(gpf, true);
BLI_addtail(&copied_frames, new_frame);
/* extend extents for keyframes encountered */
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 09b57029350..22a628de8b1 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -178,7 +178,7 @@ static void gpencil_strokepoint_convertcoords(bContext *C,
/* apply parent transform */
float fpt[3];
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
mul_v3_m4v3(fpt, diff_mat, &source_pt->x);
copy_v3_v3(&pt->x, fpt);
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index ad9b72b713e..e297a806895 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -449,20 +449,25 @@ void GPENCIL_OT_layer_annotation_move(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
}
/* ********************* Duplicate Layer ************************** */
+enum {
+ GP_LAYER_DUPLICATE_ALL = 0,
+ GP_LAYER_DUPLICATE_EMPTY = 1,
+};
-static int gpencil_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_layer_copy_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
bGPDlayer *new_layer;
-
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ const bool dup_strokes = (bool)(mode == GP_LAYER_DUPLICATE_ALL);
/* sanity checks */
if (ELEM(NULL, gpd, gpl)) {
return OPERATOR_CANCELLED;
}
/* make copy of layer, and add it immediately after the existing layer */
- new_layer = BKE_gpencil_layer_duplicate(gpl);
+ new_layer = BKE_gpencil_layer_duplicate(gpl, true, dup_strokes);
BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
/* ensure new layer has a unique name, and is now the active layer */
@@ -484,6 +489,12 @@ static int gpencil_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
{
+ static const EnumPropertyItem copy_mode[] = {
+ {GP_LAYER_DUPLICATE_ALL, "ALL", 0, "All Data", ""},
+ {GP_LAYER_DUPLICATE_EMPTY, "EMPTY", 0, "Empty Keyframes", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
/* identifiers */
ot->name = "Duplicate Layer";
ot->idname = "GPENCIL_OT_layer_duplicate";
@@ -495,6 +506,8 @@ void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_DUPLICATE_ALL, "Mode", "");
}
/* ********************* Duplicate Layer in a new object ************************** */
@@ -1560,7 +1573,7 @@ static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
/* some stroke is already at front*/
@@ -1725,7 +1738,7 @@ static int gpencil_stroke_change_color_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
@@ -2849,12 +2862,12 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
mul_v3_m3v3(offset_local, imat, offset_global);
LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) {
- bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src);
+ bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src, true, true);
float diff_mat[4][4];
float inverse_diff_mat[4][4];
/* recalculate all stroke points */
- BKE_gpencil_parent_matrix_get(depsgraph, ob_iter, gpl_src, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, ob_iter, gpl_src, diff_mat);
invert_m4_m4_safe_ortho(inverse_diff_mat, diff_mat);
Material *ma_src = NULL;
@@ -3388,7 +3401,7 @@ static int gpencil_material_select_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index d1c8eca1be0..b5269bbfacf 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -1867,7 +1867,7 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op)
}
/* Check if the color is editable. */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
@@ -2610,7 +2610,7 @@ static int gpencil_delete_selected_points(bContext *C)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
@@ -2800,7 +2800,7 @@ static int gpencil_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
float diff_mat[4][4];
/* calculate difference matrix object */
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
@@ -2808,7 +2808,7 @@ static int gpencil_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) {
continue;
}
@@ -2935,7 +2935,7 @@ static int gpencil_snap_to_cursor(bContext *C, wmOperator *op)
float diff_mat[4][4];
/* calculate difference matrix */
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
bGPDspoint *pt;
@@ -2946,7 +2946,7 @@ static int gpencil_snap_to_cursor(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) {
continue;
}
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
@@ -3039,7 +3039,7 @@ static bool gpencil_stroke_points_centroid(Depsgraph *depsgraph,
float diff_mat[4][4];
/* calculate difference matrix */
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
bGPDspoint *pt;
@@ -3050,7 +3050,7 @@ static bool gpencil_stroke_points_centroid(Depsgraph *depsgraph,
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) {
continue;
}
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
@@ -3565,7 +3565,7 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable. */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
elem = &strokes_list[tot_strokes];
@@ -3697,7 +3697,7 @@ static int gpencil_stroke_flip_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
@@ -4516,7 +4516,7 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
/* Separate selected strokes. */
@@ -4717,7 +4717,7 @@ static int gpencil_stroke_split_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
/* Split selected strokes. */
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 8bd0b2f86de..e3e73d5deb5 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -81,6 +81,7 @@
#define LEAK_HORZ 0
#define LEAK_VERT 1
+#define MIN_WINDOW_SIZE 128
/* Temporary fill operation data (op->customdata) */
typedef struct tGPDfill {
@@ -137,7 +138,7 @@ typedef struct tGPDfill {
/** boundary limits drawing mode */
int fill_draw_mode;
/* scaling factor */
- short fill_factor;
+ float fill_factor;
/* Frame to use. */
int active_cfra;
@@ -262,14 +263,14 @@ static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4])
BLI_assert(gpl_active_index >= 0);
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
- /* calculate parent position */
- BKE_gpencil_parent_matrix_get(tgpw.depsgraph, ob, gpl, tgpw.diff_mat);
-
/* do not draw layer if hidden */
if (gpl->flag & GP_LAYER_HIDE) {
continue;
}
+ /* calculate parent position */
+ BKE_gpencil_layer_transform_matrix_get(tgpw.depsgraph, ob, gpl, tgpw.diff_mat);
+
/* Decide if the strokes of layers are included or not depending on the layer mode.
* Cannot skip the layer because it can use boundary strokes and must be used. */
bool skip = false;
@@ -398,8 +399,8 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf)
/* resize region */
tgpf->region->winrct.xmin = 0;
tgpf->region->winrct.ymin = 0;
- tgpf->region->winrct.xmax = (int)tgpf->region->winx * tgpf->fill_factor;
- tgpf->region->winrct.ymax = (int)tgpf->region->winy * tgpf->fill_factor;
+ tgpf->region->winrct.xmax = max_ii((int)tgpf->region->winx * tgpf->fill_factor, MIN_WINDOW_SIZE);
+ tgpf->region->winrct.ymax = max_ii((int)tgpf->region->winy * tgpf->fill_factor, MIN_WINDOW_SIZE);
tgpf->region->winx = (short)abs(tgpf->region->winrct.xmax - tgpf->region->winrct.xmin);
tgpf->region->winy = (short)abs(tgpf->region->winrct.ymax - tgpf->region->winrct.ymin);
@@ -456,7 +457,7 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf)
}
GPU_matrix_push_projection();
- GPU_matrix_identity_set();
+ GPU_matrix_identity_projection_set();
GPU_matrix_push();
GPU_matrix_identity_set();
@@ -1275,7 +1276,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
float origin[3];
ED_gpencil_drawing_reference_get(tgpf->scene, tgpf->ob, ts->gpencil_v3d_align, origin);
ED_gpencil_project_stroke_to_plane(
- tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin, tgpf->lock_axis - 1);
+ tgpf->scene, tgpf->ob, tgpf->rv3d, tgpf->gpl, gps, origin, tgpf->lock_axis - 1);
}
/* if parented change position relative to parent object */
@@ -1395,11 +1396,12 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *UNUSED(op))
Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
tgpf->brush = brush;
tgpf->flag = brush->gpencil_settings->flag;
- tgpf->fill_leak = brush->gpencil_settings->fill_leak;
tgpf->fill_threshold = brush->gpencil_settings->fill_threshold;
tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl;
tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode;
- tgpf->fill_factor = (short)max_ii(1, min_ii((int)brush->gpencil_settings->fill_factor, 8));
+ tgpf->fill_factor = max_ff(GPENCIL_MIN_FILL_FAC,
+ min_ff(brush->gpencil_settings->fill_factor, 8.0f));
+ tgpf->fill_leak = (int)ceil((float)brush->gpencil_settings->fill_leak * tgpf->fill_factor);
int totcol = tgpf->ob->totcol;
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 4a908eff92e..5fea46626d5 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -667,7 +667,8 @@ struct GP_EditableStrokes_Iter {
bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \
for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
- BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
+ BKE_gpencil_layer_transform_matrix_get( \
+ depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
/* loop over strokes */ \
bGPDstroke *gpsn_; \
@@ -678,7 +679,7 @@ struct GP_EditableStrokes_Iter {
continue; \
} \
/* check if the color is editable */ \
- if (ED_gpencil_stroke_color_use(obact_, gpl, gps) == false) { \
+ if (ED_gpencil_stroke_material_editable(obact_, gpl, gps) == false) { \
continue; \
} \
/* ... Do Stuff With Strokes ... */
@@ -718,7 +719,8 @@ struct GP_EditableStrokes_Iter {
bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \
for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
- BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
+ BKE_gpencil_layer_transform_matrix_get( \
+ depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
/* loop over strokes */ \
bGPDstroke *gpsn_; \
@@ -767,8 +769,10 @@ struct GP_EditableStrokes_Iter {
bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \
for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
- BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
- invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
+ BKE_gpencil_layer_transform_matrix_get( \
+ depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
+ /* Undo layer transform. */ \
+ mul_m4_m4m4(gpstroke_iter.diff_mat, gpstroke_iter.diff_mat, gpl->layer_invmat); \
/* loop over strokes */ \
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf_->strokes) { \
/* skip strokes that are invalid for current view */ \
@@ -776,7 +780,7 @@ struct GP_EditableStrokes_Iter {
continue; \
} \
/* check if the color is editable */ \
- if (ED_gpencil_stroke_color_use(obact_, gpl, gps) == false) { \
+ if (ED_gpencil_stroke_material_editable(obact_, gpl, gps) == false) { \
continue; \
} \
/* ... Do Stuff With Strokes ... */
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index c666fcb67b7..2e756cf9c8d 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -229,7 +229,7 @@ static bool gpencil_interpolate_check_todo(bContext *C, bGPdata *gpd)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps_from) == false) {
continue;
}
@@ -283,8 +283,8 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
tgpil->gpl = gpl;
- tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe);
- tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next);
+ tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe, true);
+ tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next, true);
BLI_addtail(&tgpi->ilayers, tgpil);
@@ -315,7 +315,7 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, tgpil->gpl, gps_from) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, tgpil->gpl, gps_from) == false) {
valid = false;
}
@@ -734,7 +734,7 @@ void GPENCIL_OT_interpolate(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
/* properties */
- RNA_def_float_percentage(
+ RNA_def_float_factor(
ot->srna,
"shift",
0.0f,
@@ -1008,8 +1008,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
}
/* store extremes */
- prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe);
- nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next);
+ prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe, true);
+ nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next, true);
/* Loop over intermediary frames and create the interpolation */
for (cframe = prevFrame->framenum + step; cframe < nextFrame->framenum; cframe += step) {
@@ -1048,7 +1048,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps_from) == false) {
continue;
}
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index ed56f004ca4..2d5491e7569 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -426,7 +426,7 @@ static void gpencil_reproject_toplane(tGPsdata *p, bGPDstroke *gps)
/* get drawing origin */
gpencil_get_3d_reference(p, origin);
- ED_gpencil_project_stroke_to_plane(p->scene, obact, rv3d, gps, origin, p->lock_axis - 1);
+ ED_gpencil_project_stroke_to_plane(p->scene, obact, rv3d, p->gpl, gps, origin, p->lock_axis - 1);
}
/* convert screen-coordinates to buffer-coordinates */
@@ -887,11 +887,13 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
gpencil_get_3d_reference(p, origin);
/* reproject current */
ED_gpencil_tpoint_to_point(p->region, origin, pt, &spt);
- ED_gpencil_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt);
+ ED_gpencil_project_point_to_plane(
+ p->scene, obact, p->gpl, rv3d, origin, p->lock_axis - 1, &spt);
/* reproject previous */
ED_gpencil_tpoint_to_point(p->region, origin, ptb, &spt2);
- ED_gpencil_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt2);
+ ED_gpencil_project_point_to_plane(
+ p->scene, obact, p->gpl, rv3d, origin, p->lock_axis - 1, &spt2);
p->totpixlen += len_v3v3(&spt.x, &spt2.x);
pt->uv_fac = p->totpixlen;
}
@@ -1349,7 +1351,7 @@ static bool gpencil_stroke_eraser_is_occluded(tGPsdata *p,
float diff_mat[4][4];
/* calculate difference matrix if parent object */
- BKE_gpencil_parent_matrix_get(p->depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(p->depsgraph, obact, gpl, diff_mat);
if (ED_view3d_autodist_simple(p->region, mval_i, mval_3d, 0, NULL)) {
const float depth_mval = view3d_point_depth(rv3d, mval_3d);
@@ -1731,12 +1733,12 @@ static void gpencil_stroke_doeraser(tGPsdata *p)
continue;
}
/* calculate difference matrix */
- BKE_gpencil_parent_matrix_get(p->depsgraph, p->ob, gpl, p->diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(p->depsgraph, p->ob, gpl, p->diff_mat);
/* loop over strokes, checking segments for intersections */
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(p->ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(p->ob, gpl, gps) == false) {
continue;
}
@@ -2103,6 +2105,11 @@ static void gpencil_paint_initstroke(tGPsdata *p,
copy_v3_v3(p->gpl->color, p->custom_color);
}
}
+
+ /* Recalculate layer transform matrix to avoid problems if props are animated. */
+ loc_eul_size_to_mat4(p->gpl->layer_mat, p->gpl->location, p->gpl->rotation, p->gpl->scale);
+ invert_m4_m4(p->gpl->layer_invmat, p->gpl->layer_mat);
+
if ((paintmode != GP_PAINTMODE_ERASER) && (p->gpl->flag & GP_LAYER_LOCKED)) {
p->status = GP_STATUS_ERROR;
if (G.debug & G_DEBUG) {
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 53e0043df37..d94a02204a2 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -317,6 +317,10 @@ static void gpencil_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
}
tgpi->gpl = gpl;
+ /* Recalculate layer transform matrix to avoid problems if props are animated. */
+ loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
+ invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
+
/* create a new temporary frame */
tgpi->gpf = MEM_callocN(sizeof(bGPDframe), "Temp bGPDframe");
tgpi->gpf->framenum = tgpi->cframe = cfra;
@@ -1004,12 +1008,12 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* reproject current */
ED_gpencil_tpoint_to_point(tgpi->region, origin, tpt, &spt);
ED_gpencil_project_point_to_plane(
- tgpi->scene, tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt);
+ tgpi->scene, tgpi->ob, tgpi->gpl, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt);
/* reproject previous */
ED_gpencil_tpoint_to_point(tgpi->region, origin, tptb, &spt2);
ED_gpencil_project_point_to_plane(
- tgpi->scene, tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt2);
+ tgpi->scene, tgpi->ob, tgpi->gpl, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt2);
tgpi->totpixlen += len_v3v3(&spt.x, &spt2.x);
tpt->uv_fac = tgpi->totpixlen;
}
@@ -1068,7 +1072,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
float origin[3];
ED_gpencil_drawing_reference_get(tgpi->scene, tgpi->ob, ts->gpencil_v3d_align, origin);
ED_gpencil_project_stroke_to_plane(
- tgpi->scene, tgpi->ob, tgpi->rv3d, gps, origin, ts->gp_sculpt.lock_axis - 1);
+ tgpi->scene, tgpi->ob, tgpi->rv3d, tgpi->gpl, gps, origin, ts->gp_sculpt.lock_axis - 1);
}
/* if parented change position relative to parent object */
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index bb9dd8cac5d..0d3ab9011d6 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -1441,11 +1441,6 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
bool changed = false;
float rot_eval = 0.0f;
- /* Check if the stroke collide with brush. */
- if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) {
- return false;
- }
-
if (gps->totpoints == 1) {
bGPDspoint pt_temp;
pt = &gps->points[0];
@@ -1577,6 +1572,13 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
Object *ob = gso->object;
bGPdata *gpd = ob->data;
char tool = gso->brush->gpencil_sculpt_tool;
+ GP_SpaceConversion *gsc = &gso->gsc;
+ Brush *brush = gso->brush;
+ const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
+ gso->brush->size;
+ /* Calc bound box matrix. */
+ float bound_mat[4][4];
+ BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat);
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
@@ -1584,7 +1586,12 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
+ continue;
+ }
+
+ /* Check if the stroke collide with brush. */
+ if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
continue;
}
@@ -1742,7 +1749,8 @@ static bool gpencil_sculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *
/* calculate difference matrix */
float diff_mat[4][4];
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
+ mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_invmat);
/* Active Frame or MultiFrame? */
if (gso->is_multiframe) {
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 281ab8c5adc..a00d21bf88a 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -2473,7 +2473,7 @@ static void gpencil_selected_hue_table(bContext *C,
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
if ((gps->flag & GP_STROKE_SELECT) == 0) {
diff --git a/source/blender/editors/gpencil/gpencil_trace_ops.c b/source/blender/editors/gpencil/gpencil_trace_ops.c
index 0be9d74278e..8d3ae9567cf 100644
--- a/source/blender/editors/gpencil/gpencil_trace_ops.c
+++ b/source/blender/editors/gpencil/gpencil_trace_ops.c
@@ -87,6 +87,7 @@ typedef struct TraceJob {
bGPDlayer *gpl;
bool was_ob_created;
+ bool use_current_frame;
int32_t frame_target;
float threshold;
@@ -228,15 +229,17 @@ static void trace_start_job(void *customdata, short *stop, short *do_update, flo
trace_job->do_update = do_update;
trace_job->progress = progress;
trace_job->was_canceled = false;
+ const int init_frame = max_ii((trace_job->use_current_frame) ? trace_job->frame_target : 0, 0);
G.is_break = false;
/* Single Image. */
-
if ((trace_job->image->source == IMA_SRC_FILE) ||
(trace_job->mode == GPENCIL_TRACE_MODE_SINGLE)) {
void *lock;
- ImBuf *ibuf = BKE_image_acquire_ibuf(trace_job->image, NULL, &lock);
+ ImageUser *iuser = trace_job->ob_active->iuser;
+ iuser->framenr = init_frame;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(trace_job->image, iuser, &lock);
if (ibuf) {
/* Create frame. */
bGPDframe *gpf = BKE_gpencil_layer_frame_get(
@@ -249,7 +252,7 @@ static void trace_start_job(void *customdata, short *stop, short *do_update, flo
/* Image sequence. */
else if (trace_job->image->type == IMA_TYPE_IMAGE) {
ImageUser *iuser = trace_job->ob_active->iuser;
- for (int i = 0; i < iuser->frames; i++) {
+ for (int i = init_frame; i < iuser->frames; i++) {
if (G.is_break) {
trace_job->was_canceled = true;
break;
@@ -320,6 +323,7 @@ static int gpencil_trace_image_exec(bContext *C, wmOperator *op)
job->ob_active = job->base_active->object;
job->image = (Image *)job->ob_active->data;
job->frame_target = CFRA;
+ job->use_current_frame = RNA_boolean_get(op->ptr, "use_current_frame");
/* Create a new grease pencil object or reuse selected. */
eGP_TargetObjectMode target = RNA_enum_get(op->ptr, "target");
@@ -493,4 +497,9 @@ void GPENCIL_OT_trace_image(wmOperatorType *ot)
GPENCIL_TRACE_MODE_SINGLE,
"Mode",
"Determines if trace simple image or full sequence");
+ RNA_def_boolean(ot->srna,
+ "use_current_frame",
+ true,
+ "Start At Current Frame",
+ "Trace Image starting in current image frame");
}
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index c2504ce329e..e545a3365e9 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -61,28 +61,22 @@ int ED_gpencil_session_active(void)
return (BLI_listbase_is_empty(&undo_nodes) == false);
}
-int ED_undo_gpencil_step(bContext *C, int step, const char *name)
+int ED_undo_gpencil_step(bContext *C, const int step)
{
bGPdata **gpd_ptr = NULL, *new_gpd = NULL;
gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
- if (step == 1) { /* undo */
- // printf("\t\tGP - undo step\n");
+ if (step == -1) { /* undo */
if (cur_node->prev) {
- if (!name || STREQ(cur_node->name, name)) {
- cur_node = cur_node->prev;
- new_gpd = cur_node->gpd;
- }
+ cur_node = cur_node->prev;
+ new_gpd = cur_node->gpd;
}
}
- else if (step == -1) {
- // printf("\t\tGP - redo step\n");
+ else if (step == 1) {
if (cur_node->next) {
- if (!name || STREQ(cur_node->name, name)) {
- cur_node = cur_node->next;
- new_gpd = cur_node->gpd;
- }
+ cur_node = cur_node->next;
+ new_gpd = cur_node->gpd;
}
}
@@ -99,7 +93,7 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* make a copy of source layer and its data */
- gpld = BKE_gpencil_layer_duplicate(gpl);
+ gpld = BKE_gpencil_layer_duplicate(gpl, true, true);
BLI_addtail(&gpd->layers, gpld);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 7c796f7b7a1..42e3055ef65 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -579,7 +579,7 @@ bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
}
/* Check whether given stroke can be edited for the current color */
-bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
+bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
{
/* check if the color is editable */
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
@@ -674,7 +674,7 @@ void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, b
float inverse_diff_mat[4][4];
float fpt[3];
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
for (i = 0; i < gps->totpoints; i++) {
@@ -697,10 +697,11 @@ void gpencil_apply_parent_point(Depsgraph *depsgraph,
float inverse_diff_mat[4][4];
float fpt[3];
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
+
copy_v3_v3(&pt->x, fpt);
}
@@ -997,6 +998,12 @@ void ED_gpencil_drawing_reference_get(const Scene *scene,
else {
/* use object location */
copy_v3_v3(r_vec, ob->obmat[3]);
+ /* Apply layer offset. */
+ bGPdata *gpd = ob->data;
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
+ if (gpl != NULL) {
+ add_v3_v3(r_vec, gpl->layer_mat[3]);
+ }
}
}
}
@@ -1021,7 +1028,7 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *
/* init space conversion stuff */
gpencil_point_conversion_init(C, &gsc);
- BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
/* Adjust each point */
@@ -1046,6 +1053,7 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *
void ED_gpencil_project_stroke_to_plane(const Scene *scene,
const Object *ob,
const RegionView3D *rv3d,
+ bGPDlayer *gpl,
bGPDstroke *gps,
const float origin[3],
const int axis)
@@ -1058,6 +1066,10 @@ void ED_gpencil_project_stroke_to_plane(const Scene *scene,
float ray[3];
float rpoint[3];
+ /* Recalculate layer transform matrix. */
+ loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
+ invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
+
/* normal vector for a plane locked to axis */
zero_v3(plane_normal);
if (axis < 0) {
@@ -1074,24 +1086,27 @@ void ED_gpencil_project_stroke_to_plane(const Scene *scene,
copy_m4_m4(mat, ob->obmat);
/* move origin to cursor */
+ if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
+ if (gpl != NULL) {
+ add_v3_v3(mat[3], gpl->location);
+ }
+ }
if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
copy_v3_v3(mat[3], cursor->location);
}
mul_mat3_m4_v3(mat, plane_normal);
}
+
+ if ((gpl != NULL) && (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_CURSOR)) {
+ mul_mat3_m4_v3(gpl->layer_mat, plane_normal);
+ }
}
else {
const float scale[3] = {1.0f, 1.0f, 1.0f};
plane_normal[2] = 1.0f;
float mat[4][4];
loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, scale);
-
- /* move origin to object */
- if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
- copy_v3_v3(mat[3], ob->obmat[3]);
- }
-
mul_mat3_m4_v3(mat, plane_normal);
}
@@ -1127,8 +1142,12 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
ARegion *region = gsc->region;
RegionView3D *rv3d = region->regiondata;
+ /* Recalculate layer transform matrix. */
+ loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
+ invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
+
float diff_mat[4][4], inverse_diff_mat[4][4];
- BKE_gpencil_parent_matrix_get(depsgraph, gsc->ob, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, gsc->ob, gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
float origin[3];
@@ -1194,7 +1213,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
}
}
- ED_gpencil_project_point_to_plane(gsc->scene, gsc->ob, rv3d, origin, axis, &pt2);
+ ED_gpencil_project_point_to_plane(gsc->scene, gsc->ob, gpl, rv3d, origin, axis, &pt2);
copy_v3_v3(&pt->x, &pt2.x);
@@ -1250,6 +1269,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
*/
void ED_gpencil_project_point_to_plane(const Scene *scene,
const Object *ob,
+ bGPDlayer *gpl,
const RegionView3D *rv3d,
const float origin[3],
const int axis,
@@ -1277,6 +1297,11 @@ void ED_gpencil_project_point_to_plane(const Scene *scene,
if (ob && (ob->type == OB_GPENCIL)) {
float mat[4][4];
copy_m4_m4(mat, ob->obmat);
+ if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
+ if (gpl != NULL) {
+ add_v3_v3(mat[3], gpl->location);
+ }
+ }
/* move origin to cursor */
if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
@@ -1284,6 +1309,10 @@ void ED_gpencil_project_point_to_plane(const Scene *scene,
}
mul_mat3_m4_v3(mat, plane_normal);
+ /* Apply layer rotation (local transform). */
+ if ((gpl != NULL) && (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_CURSOR)) {
+ mul_mat3_m4_v3(gpl->layer_mat, plane_normal);
+ }
}
}
else {
@@ -1449,7 +1478,7 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata
/* only redo if any change */
if (!equals_m4m4(gpl->inverse, cur_mat)) {
/* first apply current transformation to all strokes */
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
/* undo local object */
sub_v3_v3(diff_mat[3], gpl_loc);
@@ -2144,7 +2173,7 @@ void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* check if it is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
gps_ma = BKE_gpencil_material(ob, gps->mat_nr + 1);
@@ -3126,7 +3155,7 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
/* calculate difference matrix object */
float diff_mat[4][4];
- BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
/* Calculate the extremes of the stroke in 2D. */
bGPDspoint pt_parent;
@@ -3144,15 +3173,13 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
float dist_min = FLT_MAX;
LISTBASE_FOREACH (bGPDstroke *, gps_target, &gpf->strokes) {
/* Check if the color is editable. */
- if ((gps_target == gps) || (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)) {
+ if ((gps_target == gps) || (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false)) {
continue;
}
/* Check if one of the ends is inside target stroke bounding box. */
- if (!ED_gpencil_stroke_check_collision(gsc, gps, pt2d_start, radius, diff_mat)) {
- continue;
- }
- if (!ED_gpencil_stroke_check_collision(gsc, gps, pt2d_end, radius, diff_mat)) {
+ if ((!ED_gpencil_stroke_check_collision(gsc, gps_target, pt2d_start, radius, diff_mat)) &&
+ (!ED_gpencil_stroke_check_collision(gsc, gps_target, pt2d_end, radius, diff_mat))) {
continue;
}
/* Check the distance of the ends with the ends of target stroke to avoid middle contact.
diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c
index b212872b607..49f45acdb11 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_ops.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c
@@ -674,7 +674,7 @@ static bool gpencil_extract_palette_from_vertex(bContext *C,
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
@@ -859,7 +859,7 @@ static int gpencil_material_to_vertex_exec(bContext *C, wmOperator *op)
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c
index e2c81d53fba..ae94836af03 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_paint.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c
@@ -825,7 +825,8 @@ static void gpencil_save_selected_point(tGP_BrushVertexpaintData *gso,
static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
bGPDstroke *gps,
const char tool,
- const float diff_mat[4][4])
+ const float diff_mat[4][4],
+ const float bound_mat[4][4])
{
GP_SpaceConversion *gsc = &gso->gsc;
rcti *rect = &gso->brush_rect;
@@ -853,7 +854,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
}
/* Check if the stroke collide with brush. */
- if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) {
+ if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
return false;
}
@@ -998,7 +999,8 @@ static bool gpencil_vertexpaint_brush_do_frame(bContext *C,
tGP_BrushVertexpaintData *gso,
bGPDlayer *gpl,
bGPDframe *gpf,
- const float diff_mat[4][4])
+ const float diff_mat[4][4],
+ const float bound_mat[4][4])
{
Object *ob = CTX_data_active_object(C);
const char tool = ob->mode == OB_MODE_VERTEX_GPENCIL ? gso->brush->gpencil_vertex_tool :
@@ -1020,12 +1022,12 @@ static bool gpencil_vertexpaint_brush_do_frame(bContext *C,
continue;
}
/* Check if the color is editable. */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
/* Check points below the brush. */
- bool hit = gpencil_vertexpaint_select_stroke(gso, gps, tool, diff_mat);
+ bool hit = gpencil_vertexpaint_select_stroke(gso, gps, tool, diff_mat, bound_mat);
/* If stroke was hit and has an editcurve the curve needs an update. */
bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
@@ -1130,9 +1132,11 @@ static bool gpencil_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVert
continue;
}
- /* calculate difference matrix */
- float diff_mat[4][4];
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ /* Calculate transform matrix. */
+ float diff_mat[4][4], bound_mat[4][4];
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
+ copy_m4_m4(bound_mat, diff_mat);
+ mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_invmat);
/* Active Frame or MultiFrame? */
if (gso->is_multiframe) {
@@ -1159,7 +1163,7 @@ static bool gpencil_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVert
}
/* affect strokes in this frame */
- changed |= gpencil_vertexpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat);
+ changed |= gpencil_vertexpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat, bound_mat);
}
}
}
@@ -1167,7 +1171,8 @@ static bool gpencil_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVert
/* Apply to active frame's strokes */
if (gpl->actframe != NULL) {
gso->mf_falloff = 1.0f;
- changed |= gpencil_vertexpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
+ changed |= gpencil_vertexpaint_brush_do_frame(
+ C, gso, gpl, gpl->actframe, diff_mat, bound_mat);
}
}
}
diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c
index 7fa71fcce3c..a3e5ece5862 100644
--- a/source/blender/editors/gpencil/gpencil_weight_paint.c
+++ b/source/blender/editors/gpencil/gpencil_weight_paint.c
@@ -383,7 +383,8 @@ static void gpencil_save_selected_point(tGP_BrushWeightpaintData *gso,
/* Select points in this stroke and add to an array to be used later. */
static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
bGPDstroke *gps,
- const float diff_mat[4][4])
+ const float diff_mat[4][4],
+ const float bound_mat[4][4])
{
GP_SpaceConversion *gsc = &gso->gsc;
rcti *rect = &gso->brush_rect;
@@ -402,7 +403,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
bool include_last = false;
/* Check if the stroke collide with brush. */
- if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) {
+ if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
return;
}
@@ -505,7 +506,8 @@ static bool gpencil_weightpaint_brush_do_frame(bContext *C,
tGP_BrushWeightpaintData *gso,
bGPDlayer *gpl,
bGPDframe *gpf,
- const float diff_mat[4][4])
+ const float diff_mat[4][4],
+ const float bound_mat[4][4])
{
Object *ob = CTX_data_active_object(C);
char tool = gso->brush->gpencil_weight_tool;
@@ -526,12 +528,12 @@ static bool gpencil_weightpaint_brush_do_frame(bContext *C,
continue;
}
/* Check if the color is editable. */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
continue;
}
/* Check points below the brush. */
- gpencil_weightpaint_select_stroke(gso, gps, diff_mat);
+ gpencil_weightpaint_select_stroke(gso, gps, diff_mat, bound_mat);
}
/*---------------------------------------------------------------------
@@ -578,9 +580,11 @@ static bool gpencil_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeig
continue;
}
- /* calculate difference matrix */
- float diff_mat[4][4];
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ /* Calculate transform matrix. */
+ float diff_mat[4][4], bound_mat[4][4];
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
+ copy_m4_m4(bound_mat, diff_mat);
+ mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_invmat);
/* Active Frame or MultiFrame? */
if (gso->is_multiframe) {
@@ -608,7 +612,7 @@ static bool gpencil_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeig
}
/* affect strokes in this frame */
- changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat);
+ changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat, bound_mat);
}
}
}
@@ -616,7 +620,8 @@ static bool gpencil_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeig
if (gpl->actframe != NULL) {
/* Apply to active frame's strokes */
gso->mf_falloff = 1.0f;
- changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
+ changed |= gpencil_weightpaint_brush_do_frame(
+ C, gso, gpl, gpl->actframe, diff_mat, bound_mat);
}
}
}
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 0a66c439f79..56494f87bfe 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -99,6 +99,30 @@ void ED_space_clip_set_clip(struct bContext *C,
struct Mask *ED_space_clip_get_mask(struct SpaceClip *sc);
void ED_space_clip_set_mask(struct bContext *C, struct SpaceClip *sc, struct Mask *mask);
+/* Locked state is used to preserve current clip editor viewport upon changes. Example usage:
+ *
+ * ...
+ *
+ * ClipViewLockState lock_state;
+ * ED_clip_view_lock_state_store(C, &lock_state);
+ *
+ * <change selection>
+ *
+ * ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
+ *
+ * These function are to be used from space clip editor context only. Otherwise debug builds will
+ * assert, release builds will crash. */
+
+typedef struct ClipViewLockState {
+ float offset_x, offset_y;
+ float lock_offset_x, lock_offset_y;
+ float zoom;
+} ClipViewLockState;
+
+void ED_clip_view_lock_state_store(const struct bContext *C, ClipViewLockState *state);
+void ED_clip_view_lock_state_restore_no_jump(const struct bContext *C,
+ const ClipViewLockState *state);
+
/* ** clip_ops.c ** */
void ED_operatormacros_clip(void);
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 1b7caf27ecf..acaa6495ba9 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -147,9 +147,9 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr
bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *area, const struct bGPDstroke *gps);
bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
-bool ED_gpencil_stroke_color_use(struct Object *ob,
- const struct bGPDlayer *gpl,
- const struct bGPDstroke *gps);
+bool ED_gpencil_stroke_material_editable(struct Object *ob,
+ const struct bGPDlayer *gpl,
+ const struct bGPDstroke *gps);
/* ----------- Grease Pencil Operators ----------------- */
@@ -213,7 +213,7 @@ bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mod
/* ------------ Grease-Pencil Undo System ------------------ */
int ED_gpencil_session_active(void);
-int ED_undo_gpencil_step(struct bContext *C, int step, const char *name);
+int ED_undo_gpencil_step(struct bContext *C, const int step);
/* ------------ Grease-Pencil Armature ------------------ */
bool ED_gpencil_add_armature(const struct bContext *C,
@@ -263,11 +263,13 @@ bool ED_object_gpencil_exit(struct Main *bmain, struct Object *ob);
void ED_gpencil_project_stroke_to_plane(const struct Scene *scene,
const struct Object *ob,
const struct RegionView3D *rv3d,
+ struct bGPDlayer *gpl,
struct bGPDstroke *gps,
const float origin[3],
const int axis);
void ED_gpencil_project_point_to_plane(const struct Scene *scene,
const struct Object *ob,
+ struct bGPDlayer *gpl,
const struct RegionView3D *rv3d,
const float origin[3],
const int axis,
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index bcf52da3f69..b20dae694fc 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -63,7 +63,10 @@ void ED_mask_point_pos__reverse(
struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr);
void ED_mask_cursor_location_get(struct ScrArea *area, float cursor[2]);
-bool ED_mask_selected_minmax(const struct bContext *C, float min[2], float max[2]);
+bool ED_mask_selected_minmax(const struct bContext *C,
+ float min[2],
+ float max[2],
+ bool include_handles);
/* mask_draw.c */
void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 417cae800ea..78f354a300d 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -51,6 +51,10 @@ typedef enum {
#define NODE_GRID_STEPS 5
/* space_node.c */
+
+void ED_node_cursor_location_get(const struct SpaceNode *snode, float value[2]);
+void ED_node_cursor_location_set(struct SpaceNode *snode, const float value[2]);
+
int ED_node_tree_path_length(struct SpaceNode *snode);
void ED_node_tree_path_get(struct SpaceNode *snode, char *value);
void ED_node_tree_path_get_fixedbuf(struct SpaceNode *snode, char *value, int max_length);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index bd1a4a0c63f..73326a2d5f2 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -159,7 +159,7 @@ extern struct EnumPropertyItem prop_clear_parent_types[];
extern struct EnumPropertyItem prop_make_parent_types[];
#endif
-/* Set the object's parent, return true iff successful. */
+/* Set the object's parent, return true if successful. */
bool ED_object_parent_set(struct ReportList *reports,
const struct bContext *C,
struct Scene *scene,
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 20417634020..deb6b7502c7 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -57,15 +57,14 @@ struct wmMsgSubscribeKey;
struct wmMsgSubscribeValue;
struct wmNotifier;
struct wmOperatorType;
+struct wmRegionListenerParams;
+struct wmRegionMessageSubscribeParams;
+struct wmSpaceTypeListenerParams;
struct wmWindow;
struct wmWindowManager;
/* regions */
-void ED_region_do_listen(struct wmWindow *win,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmNotifier *note,
- const Scene *scene);
+void ED_region_do_listen(struct wmRegionListenerParams *params);
void ED_region_do_layout(struct bContext *C, struct ARegion *region);
void ED_region_do_draw(struct bContext *C, struct ARegion *region);
void ED_region_exit(struct bContext *C, struct ARegion *region);
@@ -144,29 +143,11 @@ void ED_area_do_msg_notify_tag_refresh(struct bContext *C,
struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValue *msg_val);
-void ED_area_do_mgs_subscribe_for_tool_header(const struct bContext *C,
- struct WorkSpace *workspace,
- struct Scene *scene,
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus);
-void ED_area_do_mgs_subscribe_for_tool_ui(const struct bContext *C,
- struct WorkSpace *workspace,
- struct Scene *scene,
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus);
+void ED_area_do_mgs_subscribe_for_tool_header(const struct wmRegionMessageSubscribeParams *params);
+void ED_area_do_mgs_subscribe_for_tool_ui(const struct wmRegionMessageSubscribeParams *params);
/* message bus */
-void ED_region_message_subscribe(struct bContext *C,
- struct WorkSpace *workspace,
- struct Scene *scene,
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus);
+void ED_region_message_subscribe(struct wmRegionMessageSubscribeParams *params);
/* spaces */
void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
@@ -178,7 +159,7 @@ void ED_area_exit(struct bContext *C, struct ScrArea *area);
int ED_screen_area_active(const struct bContext *C);
void ED_screen_global_areas_refresh(struct wmWindow *win);
void ED_screen_global_areas_sync(struct wmWindow *win);
-void ED_area_do_listen(struct wmWindow *win, ScrArea *area, struct wmNotifier *note, Scene *scene);
+void ED_area_do_listen(struct wmSpaceTypeListenerParams *params);
void ED_area_tag_redraw(ScrArea *area);
void ED_area_tag_redraw_no_rebuild(ScrArea *area);
void ED_area_tag_redraw_regiontype(ScrArea *area, int type);
@@ -427,13 +408,8 @@ void ED_region_cache_draw_cached_segments(struct ARegion *region,
const int efra);
/* area_utils.c */
-void ED_region_generic_tools_region_message_subscribe(const struct bContext *C,
- struct WorkSpace *workspace,
- struct Scene *scene,
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus);
+void ED_region_generic_tools_region_message_subscribe(
+ const struct wmRegionMessageSubscribeParams *params);
int ED_region_generic_tools_region_snap_size(const struct ARegion *region, int size, int axis);
/* area_query.c */
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index ca3e351a052..2ab062a718c 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -98,8 +98,7 @@ enum TfmMode {
/* Standalone call to get the transformation center corresponding to the current situation
* returns 1 if successful, 0 otherwise (usually means there's no selection)
- * (if 0 is returns, *vec is unmodified)
- * */
+ * (if false is returns, `cent3d` is unmodified). */
bool calculateTransformCenter(struct bContext *C,
int centerMode,
float cent3d[3],
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 7bbb7225f14..bc053f60ca3 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -56,6 +56,7 @@ struct bNode;
struct bNodeSocket;
struct bNodeTree;
struct bScreen;
+struct rctf;
struct rcti;
struct uiButSearch;
struct uiFontStyle;
@@ -414,57 +415,38 @@ void UI_draw_anti_tria(
void UI_draw_anti_fan(float tri_array[][2], unsigned int length, const float color[4]);
void UI_draw_roundbox_corner_set(int type);
-void UI_draw_roundbox_aa(
- bool filled, float minx, float miny, float maxx, float maxy, float rad, const float color[4]);
-void UI_draw_roundbox_4fv(
- bool filled, float minx, float miny, float maxx, float maxy, float rad, const float col[4]);
-void UI_draw_roundbox_3ub_alpha(bool filled,
- float minx,
- float miny,
- float maxx,
- float maxy,
+void UI_draw_roundbox_aa(const struct rctf *rect, bool filled, float rad, const float color[4]);
+void UI_draw_roundbox_4fv(const struct rctf *rect, bool filled, float rad, const float col[4]);
+void UI_draw_roundbox_3ub_alpha(const struct rctf *rect,
+ bool filled,
float rad,
const unsigned char col[3],
unsigned char alpha);
-void UI_draw_roundbox_3fv_alpha(bool filled,
- float minx,
- float miny,
- float maxx,
- float maxy,
- float rad,
- const float col[3],
- float alpha);
-void UI_draw_roundbox_shade_x(bool filled,
- float minx,
- float miny,
- float maxx,
- float maxy,
+void UI_draw_roundbox_3fv_alpha(
+ const struct rctf *rect, bool filled, float rad, const float col[3], float alpha);
+void UI_draw_roundbox_shade_x(const struct rctf *rect,
+ bool filled,
float rad,
float shadetop,
float shadedown,
const float col[4]);
+void UI_draw_roundbox_4fv_ex(const struct rctf *rect,
+ const float inner1[4],
+ const float inner2[4],
+ float shade_dir,
+ const float outline[4],
+ float outline_width,
+ float rad);
#if 0 /* unused */
int UI_draw_roundbox_corner_get(void);
-void UI_draw_roundbox_shade_y(bool filled,
- float minx,
- float miny,
- float maxx,
- float maxy,
- float rad,
- float shadeleft,
- float shaderight,
- const float col[4]);
#endif
-void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy);
+void UI_draw_box_shadow(const struct rctf *rect, unsigned char alpha);
void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4]);
void UI_draw_safe_areas(uint pos,
- float x1,
- float x2,
- float y1,
- float y2,
+ const struct rctf *rect,
const float title_aspect[2],
const float action_aspect[2]);
@@ -526,6 +508,7 @@ typedef bool (*uiButSearchContextMenuFn)(struct bContext *C,
const struct wmEvent *event);
typedef struct ARegion *(*uiButSearchTooltipFn)(struct bContext *C,
struct ARegion *region,
+ const struct rcti *item_rect,
void *arg,
void *active);
@@ -664,8 +647,7 @@ bool UI_popup_block_name_exists(const struct bScreen *screen, const char *name);
* Begin/Define Buttons/End/Draw is the typical order in which these
* function should be called, though for popup blocks Draw is left out.
* Freeing blocks is done by the screen/ module automatically.
- *
- * */
+ */
uiBlock *UI_block_begin(const struct bContext *C,
struct ARegion *region,
@@ -2499,11 +2481,12 @@ void UI_context_active_but_prop_get_templateID(struct bContext *C,
struct PropertyRNA **r_prop);
struct ID *UI_context_active_but_get_tab_ID(struct bContext *C);
-uiBut *UI_region_active_but_get(struct ARegion *region);
+uiBut *UI_region_active_but_get(const struct ARegion *region);
uiBut *UI_region_but_find_rect_over(const struct ARegion *region, const struct rcti *rect_px);
uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region,
const int xy[2],
bool only_clip);
+struct ARegion *UI_region_searchbox_region_get(const struct ARegion *button_region);
/* uiFontStyle.align */
typedef enum eFontStyle_Align {
@@ -2583,6 +2566,21 @@ struct ARegion *UI_tooltip_create_from_button(struct bContext *C,
struct ARegion *UI_tooltip_create_from_gizmo(struct bContext *C, struct wmGizmo *gz);
void UI_tooltip_free(struct bContext *C, struct bScreen *screen, struct ARegion *region);
+typedef struct {
+ /** A description for the item, e.g. what happens when selecting it. */
+ char description[UI_MAX_DRAW_STR];
+ /* The full name of the item, without prefixes or suffixes (e.g. hint with UI_SEP_CHARP). */
+ const char *name;
+ /** Additional info about the item (e.g. library name of a linked data-block). */
+ char hint[UI_MAX_DRAW_STR];
+} uiSearchItemTooltipData;
+
+struct ARegion *UI_tooltip_create_from_search_item_generic(
+ struct bContext *C,
+ const struct ARegion *searchbox_region,
+ const struct rcti *item_rect,
+ const uiSearchItemTooltipData *item_tooltip_data);
+
/* How long before a tool-tip shows. */
#define UI_TOOLTIP_DELAY 0.5
#define UI_TOOLTIP_DELAY_LABEL 0.2
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 8df29e5b520..64f881052a1 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -231,7 +231,7 @@ struct View2D *UI_view2d_fromcontext(const struct bContext *C);
struct View2D *UI_view2d_fromcontext_rwin(const struct bContext *C);
void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_y);
-void UI_view2d_scale_get(struct View2D *v2d, float *r_x, float *r_y);
+void UI_view2d_scale_get(const struct View2D *v2d, float *r_x, float *r_y);
float UI_view2d_scale_get_x(const struct View2D *v2d);
float UI_view2d_scale_get_y(const struct View2D *v2d);
void UI_view2d_scale_get_inverse(const struct View2D *v2d, float *r_x, float *r_y);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 319ae385ffc..4f70d68f495 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1284,12 +1284,10 @@ static bool ui_but_event_property_operator_string(const bContext *C,
char *buf,
const size_t buf_len)
{
- /* context toggle operator names to check... */
+ /* Context toggle operator names to check. */
/* This function could use a refactor to generalize button type to operator relationship
- * as well as which operators use properties.
- * - Campbell
- * */
+ * as well as which operators use properties. - Campbell */
const char *ctx_toggle_opnames[] = {
"WM_OT_context_toggle",
"WM_OT_context_toggle_enum",
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 5bb6b0f21e7..0bae57f14d3 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -81,544 +81,116 @@ int UI_draw_roundbox_corner_get(void)
}
#endif
-void UI_draw_roundbox_3ub_alpha(bool filled,
- float minx,
- float miny,
- float maxx,
- float maxy,
- float rad,
- const uchar col[3],
- uchar alpha)
+void UI_draw_roundbox_4fv_ex(const rctf *rect,
+ const float inner1[4],
+ const float inner2[4],
+ float shade_dir,
+ const float outline[4],
+ float outline_width,
+ float rad)
{
- float colv[4];
- colv[0] = ((float)col[0]) / 255;
- colv[1] = ((float)col[1]) / 255;
- colv[2] = ((float)col[2]) / 255;
- colv[3] = ((float)alpha) / 255;
- UI_draw_roundbox_4fv(filled, minx, miny, maxx, maxy, rad, colv);
-}
-
-void UI_draw_roundbox_3fv_alpha(bool filled,
- float minx,
- float miny,
- float maxx,
- float maxy,
- float rad,
- const float col[3],
- float alpha)
-{
- float colv[4];
- colv[0] = col[0];
- colv[1] = col[1];
- colv[2] = col[2];
- colv[3] = alpha;
- UI_draw_roundbox_4fv(filled, minx, miny, maxx, maxy, rad, colv);
-}
-
-void UI_draw_roundbox_aa(
- bool filled, float minx, float miny, float maxx, float maxy, float rad, const float color[4])
-{
- uiWidgetBaseParameters widget_params = {
- .recti.xmin = minx + U.pixelsize,
- .recti.ymin = miny + U.pixelsize,
- .recti.xmax = maxx - U.pixelsize,
- .recti.ymax = maxy - U.pixelsize,
- .rect.xmin = minx,
- .rect.ymin = miny,
- .rect.xmax = maxx,
- .rect.ymax = maxy,
- .radi = rad,
- .rad = rad,
- .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
- .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
- .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
- .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
- .color_inner1[0] = filled ? color[0] : 0.0f,
- .color_inner1[1] = filled ? color[1] : 0.0f,
- .color_inner1[2] = filled ? color[2] : 0.0f,
- .color_inner1[3] = filled ? color[3] : 0.0f,
- .color_inner2[0] = filled ? color[0] : 0.0f,
- .color_inner2[1] = filled ? color[1] : 0.0f,
- .color_inner2[2] = filled ? color[2] : 0.0f,
- .color_inner2[3] = filled ? color[3] : 0.0f,
- .color_outline[0] = color[0],
- .color_outline[1] = color[1],
- .color_outline[2] = color[2],
- .color_outline[3] = color[3],
- .alpha_discard = 1.0f,
- };
-
- /* XXX this is to emulate previous behavior of semitransparent fills but that's was a side effect
- * of the previous AA method. Better fix the callers. */
- if (filled) {
- widget_params.color_inner1[3] *= 0.65f;
- widget_params.color_inner2[3] *= 0.65f;
- widget_params.color_outline[3] *= 0.65f;
- }
-
/* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space.
* If it has been scaled, then it's no longer valid. */
-
- GPUBatch *batch = ui_batch_roundbox_widget_get();
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
- GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float(*)[4]) & widget_params);
-
- GPU_blend(GPU_BLEND_ALPHA);
-
- GPU_batch_draw(batch);
-
- GPU_blend(GPU_BLEND_NONE);
-}
-
-void UI_draw_roundbox_4fv(
- bool filled, float minx, float miny, float maxx, float maxy, float rad, const float col[4])
-{
-#if 0
- float vec[7][2] = {
- {0.195, 0.02},
- {0.383, 0.067},
- {0.55, 0.169},
- {0.707, 0.293},
- {0.831, 0.45},
- {0.924, 0.617},
- {0.98, 0.805},
- };
- int a;
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- /* mult */
- for (a = 0; a < 7; a++) {
- mul_v2_fl(vec[a], rad);
- }
-
- uint vert_len = 0;
- vert_len += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1;
- vert_len += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1;
- vert_len += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1;
- vert_len += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1;
-
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4fv(col);
-
- immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, vert_len);
- /* start with corner right-bottom */
- if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
- immVertex2f(pos, maxx - rad, miny);
- for (a = 0; a < 7; a++) {
- immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]);
- }
- immVertex2f(pos, maxx, miny + rad);
- }
- else {
- immVertex2f(pos, maxx, miny);
- }
-
- /* corner right-top */
- if (roundboxtype & UI_CNR_TOP_RIGHT) {
- immVertex2f(pos, maxx, maxy - rad);
- for (a = 0; a < 7; a++) {
- immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]);
- }
- immVertex2f(pos, maxx - rad, maxy);
- }
- else {
- immVertex2f(pos, maxx, maxy);
- }
-
- /* corner left-top */
- if (roundboxtype & UI_CNR_TOP_LEFT) {
- immVertex2f(pos, minx + rad, maxy);
- for (a = 0; a < 7; a++) {
- immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]);
- }
- immVertex2f(pos, minx, maxy - rad);
- }
- else {
- immVertex2f(pos, minx, maxy);
- }
-
- /* corner left-bottom */
- if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
- immVertex2f(pos, minx, miny + rad);
- for (a = 0; a < 7; a++) {
- immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]);
- }
- immVertex2f(pos, minx + rad, miny);
- }
- else {
- immVertex2f(pos, minx, miny);
- }
-
- immEnd();
- immUnbindProgram();
-#endif
uiWidgetBaseParameters widget_params = {
- .recti.xmin = minx + U.pixelsize,
- .recti.ymin = miny + U.pixelsize,
- .recti.xmax = maxx - U.pixelsize,
- .recti.ymax = maxy - U.pixelsize,
- .rect.xmin = minx,
- .rect.ymin = miny,
- .rect.xmax = maxx,
- .rect.ymax = maxy,
+ .recti.xmin = rect->xmin + outline_width,
+ .recti.ymin = rect->ymin + outline_width,
+ .recti.xmax = rect->xmax - outline_width,
+ .recti.ymax = rect->ymax - outline_width,
+ .rect = *rect,
.radi = rad,
.rad = rad,
.round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
.round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
.round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
.round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
- .color_inner1[0] = filled ? col[0] : 0.0f,
- .color_inner1[1] = filled ? col[1] : 0.0f,
- .color_inner1[2] = filled ? col[2] : 0.0f,
- .color_inner1[3] = filled ? col[3] : 0.0f,
- .color_inner2[0] = filled ? col[0] : 0.0f,
- .color_inner2[1] = filled ? col[1] : 0.0f,
- .color_inner2[2] = filled ? col[2] : 0.0f,
- .color_inner2[3] = filled ? col[3] : 0.0f,
- .color_outline[0] = col[0],
- .color_outline[1] = col[1],
- .color_outline[2] = col[2],
- .color_outline[3] = col[3],
+ .color_inner1[0] = inner1 ? inner1[0] : 0.0f,
+ .color_inner1[1] = inner1 ? inner1[1] : 0.0f,
+ .color_inner1[2] = inner1 ? inner1[2] : 0.0f,
+ .color_inner1[3] = inner1 ? inner1[3] : 0.0f,
+ .color_inner2[0] = inner2 ? inner2[0] : inner1 ? inner1[0] : 0.0f,
+ .color_inner2[1] = inner2 ? inner2[1] : inner1 ? inner1[1] : 0.0f,
+ .color_inner2[2] = inner2 ? inner2[2] : inner1 ? inner1[2] : 0.0f,
+ .color_inner2[3] = inner2 ? inner2[3] : inner1 ? inner1[3] : 0.0f,
+ .color_outline[0] = outline ? outline[0] : inner1 ? inner1[0] : 0.0f,
+ .color_outline[1] = outline ? outline[1] : inner1 ? inner1[1] : 0.0f,
+ .color_outline[2] = outline ? outline[2] : inner1 ? inner1[2] : 0.0f,
+ .color_outline[3] = outline ? outline[3] : inner1 ? inner1[3] : 0.0f,
+ .shade_dir = shade_dir,
.alpha_discard = 1.0f,
};
- /* Exactly the same as UI_draw_roundbox_aa but does not do the legacy transparency. */
-
- /* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space.
- * If it has been scaled, then it's no longer valid. */
-
GPUBatch *batch = ui_batch_roundbox_widget_get();
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float(*)[4]) & widget_params);
-
GPU_blend(GPU_BLEND_ALPHA);
-
GPU_batch_draw(batch);
-
GPU_blend(GPU_BLEND_NONE);
}
-#if 0
-static void round_box_shade_col(uint attr,
- const float col1[3],
- float const col2[3],
- const float fac)
+void UI_draw_roundbox_3ub_alpha(
+ const rctf *rect, bool filled, float rad, const uchar col[3], uchar alpha)
{
- float col[4] = {
- fac * col1[0] + (1.0f - fac) * col2[0],
- fac * col1[1] + (1.0f - fac) * col2[1],
- fac * col1[2] + (1.0f - fac) * col2[2],
- 1.0f,
+ float colv[4] = {
+ ((float)col[0]) / 255,
+ ((float)col[1]) / 255,
+ ((float)col[2]) / 255,
+ ((float)alpha) / 255,
};
- immAttr4fv(attr, col);
+ UI_draw_roundbox_4fv_ex(rect, (filled) ? colv : NULL, NULL, 1.0f, colv, U.pixelsize, rad);
}
-#endif
-/* linear horizontal shade within button or in outline */
-/* view2d scrollers use it */
-void UI_draw_roundbox_shade_x(bool filled,
- float minx,
- float miny,
- float maxx,
- float maxy,
- float rad,
- float shadetop,
- float shadedown,
- const float col[4])
+void UI_draw_roundbox_3fv_alpha(
+ const rctf *rect, bool filled, float rad, const float col[3], float alpha)
{
-#if 0
- float vec[7][2] = {
- {0.195, 0.02},
- {0.383, 0.067},
- {0.55, 0.169},
- {0.707, 0.293},
- {0.831, 0.45},
- {0.924, 0.617},
- {0.98, 0.805},
- };
- const float div = maxy - miny;
- const float idiv = 1.0f / div;
- float coltop[3], coldown[3];
- int vert_count = 0;
- int a;
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
-
- /* mult */
- for (a = 0; a < 7; a++) {
- mul_v2_fl(vec[a], rad);
- }
-
- /* 'shade' defines strength of shading */
- coltop[0] = min_ff(1.0f, col[0] + shadetop);
- coltop[1] = min_ff(1.0f, col[1] + shadetop);
- coltop[2] = min_ff(1.0f, col[2] + shadetop);
- coldown[0] = max_ff(0.0f, col[0] + shadedown);
- coldown[1] = max_ff(0.0f, col[1] + shadedown);
- coldown[2] = max_ff(0.0f, col[2] + shadedown);
-
- vert_count += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1;
- vert_count += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1;
- vert_count += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1;
- vert_count += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1;
-
- immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, vert_count);
-
- /* start with corner right-bottom */
- if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
-
- round_box_shade_col(color, coltop, coldown, 0.0);
- immVertex2f(pos, maxx - rad, miny);
-
- for (a = 0; a < 7; a++) {
- round_box_shade_col(color, coltop, coldown, vec[a][1] * idiv);
- immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]);
- }
-
- round_box_shade_col(color, coltop, coldown, rad * idiv);
- immVertex2f(pos, maxx, miny + rad);
- }
- else {
- round_box_shade_col(color, coltop, coldown, 0.0);
- immVertex2f(pos, maxx, miny);
- }
-
- /* corner right-top */
- if (roundboxtype & UI_CNR_TOP_RIGHT) {
-
- round_box_shade_col(color, coltop, coldown, (div - rad) * idiv);
- immVertex2f(pos, maxx, maxy - rad);
-
- for (a = 0; a < 7; a++) {
- round_box_shade_col(color, coltop, coldown, (div - rad + vec[a][1]) * idiv);
- immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]);
- }
- round_box_shade_col(color, coltop, coldown, 1.0);
- immVertex2f(pos, maxx - rad, maxy);
- }
- else {
- round_box_shade_col(color, coltop, coldown, 1.0);
- immVertex2f(pos, maxx, maxy);
- }
-
- /* corner left-top */
- if (roundboxtype & UI_CNR_TOP_LEFT) {
-
- round_box_shade_col(color, coltop, coldown, 1.0);
- immVertex2f(pos, minx + rad, maxy);
-
- for (a = 0; a < 7; a++) {
- round_box_shade_col(color, coltop, coldown, (div - vec[a][1]) * idiv);
- immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]);
- }
-
- round_box_shade_col(color, coltop, coldown, (div - rad) * idiv);
- immVertex2f(pos, minx, maxy - rad);
- }
- else {
- round_box_shade_col(color, coltop, coldown, 1.0);
- immVertex2f(pos, minx, maxy);
- }
-
- /* corner left-bottom */
- if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
-
- round_box_shade_col(color, coltop, coldown, rad * idiv);
- immVertex2f(pos, minx, miny + rad);
-
- for (a = 0; a < 7; a++) {
- round_box_shade_col(color, coltop, coldown, (rad - vec[a][1]) * idiv);
- immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]);
- }
+ float colv[4] = {col[0], col[1], col[2], alpha};
+ UI_draw_roundbox_4fv_ex(rect, (filled) ? colv : NULL, NULL, 1.0f, colv, U.pixelsize, rad);
+}
- round_box_shade_col(color, coltop, coldown, 0.0);
- immVertex2f(pos, minx + rad, miny);
- }
- else {
- round_box_shade_col(color, coltop, coldown, 0.0);
- immVertex2f(pos, minx, miny);
+void UI_draw_roundbox_aa(const rctf *rect, bool filled, float rad, const float color[4])
+{
+ /* XXX this is to emulate previous behavior of semitransparent fills but that's was a side effect
+ * of the previous AA method. Better fix the callers. */
+ float colv[4] = {color[0], color[1], color[2], color[3]};
+ if (filled) {
+ colv[3] *= 0.65f;
}
- immEnd();
- immUnbindProgram();
-#endif
- uiWidgetBaseParameters widget_params = {
- .recti.xmin = minx + U.pixelsize,
- .recti.ymin = miny + U.pixelsize,
- .recti.xmax = maxx - U.pixelsize,
- .recti.ymax = maxy - U.pixelsize,
- .rect.xmin = minx,
- .rect.ymin = miny,
- .rect.xmax = maxx,
- .rect.ymax = maxy,
- .radi = rad,
- .rad = rad,
- .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
- .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
- .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
- .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
- .color_inner1[0] = !filled ? 0.0f : min_ff(1.0f, col[0] + shadetop),
- .color_inner1[1] = !filled ? 0.0f : min_ff(1.0f, col[1] + shadetop),
- .color_inner1[2] = !filled ? 0.0f : min_ff(1.0f, col[2] + shadetop),
- .color_inner1[3] = !filled ? 0.0f : 1.0f,
- .color_inner2[0] = !filled ? 0.0f : max_ff(0.0f, col[0] + shadedown),
- .color_inner2[1] = !filled ? 0.0f : max_ff(0.0f, col[1] + shadedown),
- .color_inner2[2] = !filled ? 0.0f : max_ff(0.0f, col[2] + shadedown),
- .color_inner2[3] = !filled ? 0.0f : 1.0f,
- /* TODO: non-filled box don't have gradients. Just use middle color. */
- .color_outline[0] = clamp_f(col[0] + shadetop + shadedown, 0.0f, 1.0f),
- .color_outline[1] = clamp_f(col[1] + shadetop + shadedown, 0.0f, 1.0f),
- .color_outline[2] = clamp_f(col[2] + shadetop + shadedown, 0.0f, 1.0f),
- .color_outline[3] = clamp_f(col[3] + shadetop + shadedown, 0.0f, 1.0f),
- .shade_dir = 1.0f,
- .alpha_discard = 1.0f,
- };
-
- GPU_blend(GPU_BLEND_ALPHA);
-
- GPUBatch *batch = ui_batch_roundbox_widget_get();
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
- GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float(*)[4]) & widget_params);
- GPU_batch_draw(batch);
+ UI_draw_roundbox_4fv_ex(rect, (filled) ? colv : NULL, NULL, 1.0f, colv, U.pixelsize, rad);
+}
- GPU_blend(GPU_BLEND_NONE);
+void UI_draw_roundbox_4fv(const rctf *rect, bool filled, float rad, const float col[4])
+{
+ /* Exactly the same as UI_draw_roundbox_aa but does not do the legacy transparency. */
+ UI_draw_roundbox_4fv_ex(rect, (filled) ? col : NULL, NULL, 1.0f, col, U.pixelsize, rad);
}
-#if 0 /* unused */
-/* linear vertical shade within button or in outline */
+/* linear horizontal shade within button or in outline */
/* view2d scrollers use it */
-void UI_draw_roundbox_shade_y(bool filled,
- float minx,
- float miny,
- float maxx,
- float maxy,
- float rad,
- float shadeleft,
- float shaderight,
- const float col[4])
+void UI_draw_roundbox_shade_x(
+ const rctf *rect, bool filled, float rad, float shadetop, float shadedown, const float col[4])
{
- float vec[7][2] = {
- {0.195, 0.02},
- {0.383, 0.067},
- {0.55, 0.169},
- {0.707, 0.293},
- {0.831, 0.45},
- {0.924, 0.617},
- {0.98, 0.805},
- };
- const float div = maxx - minx;
- const float idiv = 1.0f / div;
- float colLeft[3], colRight[3];
- int vert_count = 0;
- int a;
-
- /* mult */
- for (a = 0; a < 7; a++) {
- mul_v2_fl(vec[a], rad);
- }
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
-
- /* 'shade' defines strength of shading */
- colLeft[0] = min_ff(1.0f, col[0] + shadeleft);
- colLeft[1] = min_ff(1.0f, col[1] + shadeleft);
- colLeft[2] = min_ff(1.0f, col[2] + shadeleft);
- colRight[0] = max_ff(0.0f, col[0] + shaderight);
- colRight[1] = max_ff(0.0f, col[1] + shaderight);
- colRight[2] = max_ff(0.0f, col[2] + shaderight);
-
- vert_count += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1;
- vert_count += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1;
- vert_count += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1;
- vert_count += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1;
-
- immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, vert_count);
+ float inner1[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float inner2[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float outline[4];
- /* start with corner right-bottom */
- if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
- round_box_shade_col(color, colLeft, colRight, 0.0);
- immVertex2f(pos, maxx - rad, miny);
-
- for (a = 0; a < 7; a++) {
- round_box_shade_col(color, colLeft, colRight, vec[a][0] * idiv);
- immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]);
- }
-
- round_box_shade_col(color, colLeft, colRight, rad * idiv);
- immVertex2f(pos, maxx, miny + rad);
- }
- else {
- round_box_shade_col(color, colLeft, colRight, 0.0);
- immVertex2f(pos, maxx, miny);
- }
-
- /* corner right-top */
- if (roundboxtype & UI_CNR_TOP_RIGHT) {
- round_box_shade_col(color, colLeft, colRight, 0.0);
- immVertex2f(pos, maxx, maxy - rad);
-
- for (a = 0; a < 7; a++) {
-
- round_box_shade_col(color, colLeft, colRight, (div - rad - vec[a][0]) * idiv);
- immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]);
- }
- round_box_shade_col(color, colLeft, colRight, (div - rad) * idiv);
- immVertex2f(pos, maxx - rad, maxy);
- }
- else {
- round_box_shade_col(color, colLeft, colRight, 0.0);
- immVertex2f(pos, maxx, maxy);
- }
-
- /* corner left-top */
- if (roundboxtype & UI_CNR_TOP_LEFT) {
- round_box_shade_col(color, colLeft, colRight, (div - rad) * idiv);
- immVertex2f(pos, minx + rad, maxy);
-
- for (a = 0; a < 7; a++) {
- round_box_shade_col(color, colLeft, colRight, (div - rad + vec[a][0]) * idiv);
- immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]);
- }
-
- round_box_shade_col(color, colLeft, colRight, 1.0);
- immVertex2f(pos, minx, maxy - rad);
- }
- else {
- round_box_shade_col(color, colLeft, colRight, 1.0);
- immVertex2f(pos, minx, maxy);
- }
-
- /* corner left-bottom */
- if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
- round_box_shade_col(color, colLeft, colRight, 1.0);
- immVertex2f(pos, minx, miny + rad);
-
- for (a = 0; a < 7; a++) {
- round_box_shade_col(color, colLeft, colRight, (vec[a][0]) * idiv);
- immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]);
- }
-
- round_box_shade_col(color, colLeft, colRight, 1.0);
- immVertex2f(pos, minx + rad, miny);
- }
- else {
- round_box_shade_col(color, colLeft, colRight, 1.0);
- immVertex2f(pos, minx, miny);
- }
-
- immEnd();
- immUnbindProgram();
+ if (filled) {
+ inner1[0] = min_ff(1.0f, col[0] + shadetop);
+ inner1[1] = min_ff(1.0f, col[1] + shadetop);
+ inner1[2] = min_ff(1.0f, col[2] + shadetop);
+ inner1[3] = 1.0f;
+ inner2[0] = max_ff(0.0f, col[0] + shadedown);
+ inner2[1] = max_ff(0.0f, col[1] + shadedown);
+ inner2[2] = max_ff(0.0f, col[2] + shadedown);
+ inner2[3] = 1.0f;
+ }
+
+ /* TODO: non-filled box don't have gradients. Just use middle color. */
+ outline[0] = clamp_f(col[0] + shadetop + shadedown, 0.0f, 1.0f);
+ outline[1] = clamp_f(col[1] + shadetop + shadedown, 0.0f, 1.0f);
+ outline[2] = clamp_f(col[2] + shadetop + shadedown, 0.0f, 1.0f);
+ outline[3] = clamp_f(col[3] + shadetop + shadedown, 0.0f, 1.0f);
+
+ UI_draw_roundbox_4fv_ex(rect, inner1, inner2, 1.0f, outline, U.pixelsize, rad);
}
-#endif /* unused */
void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4])
{
@@ -799,15 +371,12 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region),
* \param x1, x2, y1, y2: The offsets for the view, not the zones.
*/
void UI_draw_safe_areas(uint pos,
- float x1,
- float x2,
- float y1,
- float y2,
+ const rctf *rect,
const float title_aspect[2],
const float action_aspect[2])
{
- const float size_x_half = (x2 - x1) * 0.5f;
- const float size_y_half = (y2 - y1) * 0.5f;
+ const float size_x_half = (rect->xmax - rect->xmin) * 0.5f;
+ const float size_y_half = (rect->ymax - rect->ymin) * 0.5f;
const float *safe_areas[] = {title_aspect, action_aspect};
const int safe_len = ARRAY_SIZE(safe_areas);
@@ -817,10 +386,10 @@ void UI_draw_safe_areas(uint pos,
const float margin_x = safe_areas[i][0] * size_x_half;
const float margin_y = safe_areas[i][1] * size_y_half;
- const float minx = x1 + margin_x;
- const float miny = y1 + margin_y;
- const float maxx = x2 - margin_x;
- const float maxy = y2 - margin_y;
+ const float minx = rect->xmin + margin_x;
+ const float miny = rect->ymin + margin_y;
+ const float maxx = rect->xmax - margin_x;
+ const float maxy = rect->ymax - margin_y;
imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
}
@@ -835,7 +404,15 @@ static void draw_scope_end(const rctf *rect)
UI_draw_roundbox_corner_set(UI_CNR_ALL);
const float color[4] = {0.0f, 0.0f, 0.0f, 0.5f};
UI_draw_roundbox_4fv(
- false, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f, color);
+ &(const rctf){
+ .xmin = rect->xmin - 1,
+ .xmax = rect->xmax + 1,
+ .ymin = rect->ymin,
+ .ymax = rect->ymax + 1,
+ },
+ false,
+ 3.0f,
+ color);
}
static void histogram_draw_one(float r,
@@ -928,7 +505,15 @@ void ui_draw_but_HISTOGRAM(ARegion *UNUSED(region),
UI_GetThemeColor4fv(TH_PREVIEW_BACK, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_4fv(
- true, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
+ &(const rctf){
+ .xmin = rect.xmin - 1,
+ .xmax = rect.xmax + 1,
+ .ymin = rect.ymin - 1,
+ .ymax = rect.ymax + 1,
+ },
+ true,
+ 3.0f,
+ color);
/* need scissor test, histogram can draw outside of boundary */
int scissor[4];
@@ -1070,7 +655,15 @@ void ui_draw_but_WAVEFORM(ARegion *UNUSED(region),
UI_GetThemeColor4fv(TH_PREVIEW_BACK, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_4fv(
- true, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
+ &(const rctf){
+ .xmin = rect.xmin - 1,
+ .xmax = rect.xmax + 1,
+ .ymin = rect.ymin - 1,
+ .ymax = rect.ymax + 1,
+ },
+ true,
+ 3.0f,
+ color);
/* need scissor test, waveform can draw outside of boundary */
GPU_scissor_get(scissor);
@@ -1399,7 +992,15 @@ void ui_draw_but_VECTORSCOPE(ARegion *UNUSED(region),
UI_GetThemeColor4fv(TH_PREVIEW_BACK, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_4fv(
- true, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
+ &(const rctf){
+ .xmin = rect.xmin - 1,
+ .xmax = rect.xmax + 1,
+ .ymin = rect.ymin - 1,
+ .ymax = rect.ymax + 1,
+ },
+ true,
+ 3.0f,
+ color);
/* need scissor test, hvectorscope can draw outside of boundary */
int scissor[4];
@@ -1774,7 +1375,16 @@ void ui_draw_but_UNITVEC(uiBut *but, const uiWidgetColors *wcol, const rcti *rec
/* backdrop */
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_3ub_alpha(
- true, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f, wcol->inner, 255);
+ &(const rctf){
+ .xmin = rect->xmin,
+ .xmax = rect->xmax,
+ .ymin = rect->ymin,
+ .ymax = rect->ymax,
+ },
+ true,
+ 5.0f,
+ wcol->inner,
+ 255);
GPU_face_culling(GPU_CULL_BACK);
@@ -2465,7 +2075,15 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region),
const float color[4] = {0.7f, 0.3f, 0.3f, 0.3f};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_4fv(
- true, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
+ &(const rctf){
+ .xmin = rect.xmin - 1,
+ .xmax = rect.xmax + 1,
+ .ymin = rect.ymin,
+ .ymax = rect.ymax + 1,
+ },
+ true,
+ 3.0f,
+ color);
ok = true;
}
@@ -2514,7 +2132,15 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region),
const float color[4] = {0.0f, 0.0f, 0.0f, 0.3f};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_4fv(
- true, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
+ &(const rctf){
+ .xmin = rect.xmin - 1,
+ .xmax = rect.xmax + 1,
+ .ymin = rect.ymin,
+ .ymax = rect.ymax + 1,
+ },
+ true,
+ 3.0f,
+ color);
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
@@ -2577,7 +2203,15 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region),
const float color[4] = {0.0f, 0.0f, 0.0f, 0.3f};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_4fv(
- true, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
+ &(const rctf){
+ .xmin = rect.xmin - 1,
+ .xmax = rect.xmax + 1,
+ .ymin = rect.ymin,
+ .ymax = rect.ymax + 1,
+ },
+ true,
+ 3.0f,
+ color);
}
/* Restore scissor test. */
@@ -2594,14 +2228,7 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region),
* would replace / modify the following 3 functions - merwin
*/
-static void ui_shadowbox(uint pos,
- uint color,
- float minx,
- float miny,
- float maxx,
- float maxy,
- float shadsize,
- uchar alpha)
+static void ui_shadowbox(const rctf *rect, uint pos, uint color, float shadsize, uchar alpha)
{
/**
* <pre>
@@ -2616,16 +2243,16 @@ static void ui_shadowbox(uint pos,
* v8______v6_-
* </pre>
*/
- const float v1[2] = {maxx, maxy - 0.3f * shadsize};
- const float v2[2] = {maxx + shadsize, maxy - 0.75f * shadsize};
- const float v3[2] = {maxx, miny};
- const float v4[2] = {maxx + shadsize, miny};
+ const float v1[2] = {rect->xmax, rect->ymax - 0.3f * shadsize};
+ const float v2[2] = {rect->xmax + shadsize, rect->ymax - 0.75f * shadsize};
+ const float v3[2] = {rect->xmax, rect->ymin};
+ const float v4[2] = {rect->xmax + shadsize, rect->ymin};
- const float v5[2] = {maxx + 0.7f * shadsize, miny - 0.7f * shadsize};
+ const float v5[2] = {rect->xmax + 0.7f * shadsize, rect->ymin - 0.7f * shadsize};
- const float v6[2] = {maxx, miny - shadsize};
- const float v7[2] = {minx + 0.3f * shadsize, miny};
- const float v8[2] = {minx + 0.5f * shadsize, miny - shadsize};
+ const float v6[2] = {rect->xmax, rect->ymin - shadsize};
+ const float v7[2] = {rect->xmin + 0.3f * shadsize, rect->ymin};
+ const float v8[2] = {rect->xmin + 0.5f * shadsize, rect->ymin - shadsize};
/* right quad */
immAttr4ub(color, 0, 0, 0, alpha);
@@ -2664,7 +2291,7 @@ static void ui_shadowbox(uint pos,
immVertex2fv(pos, v3);
}
-void UI_draw_box_shadow(uchar alpha, float minx, float miny, float maxx, float maxy)
+void UI_draw_box_shadow(const rctf *rect, uchar alpha)
{
GPU_blend(GPU_BLEND_ALPHA);
@@ -2678,9 +2305,9 @@ void UI_draw_box_shadow(uchar alpha, float minx, float miny, float maxx, float m
immBegin(GPU_PRIM_TRIS, 54);
/* accumulated outline boxes to make shade not linear, is more pleasant */
- ui_shadowbox(pos, color, minx, miny, maxx, maxy, 11.0, (20 * alpha) >> 8);
- ui_shadowbox(pos, color, minx, miny, maxx, maxy, 7.0, (40 * alpha) >> 8);
- ui_shadowbox(pos, color, minx, miny, maxx, maxy, 5.0, (80 * alpha) >> 8);
+ ui_shadowbox(rect, pos, color, 11.0, (20 * alpha) >> 8);
+ ui_shadowbox(rect, pos, color, 7.0, (40 * alpha) >> 8);
+ ui_shadowbox(rect, pos, color, 5.0, (80 * alpha) >> 8);
immEnd();
@@ -2755,13 +2382,16 @@ void ui_draw_dropshadow(
/* outline emphasis */
const float color[4] = {0.0f, 0.0f, 0.0f, 0.4f};
- UI_draw_roundbox_4fv(false,
- rct->xmin - 0.5f,
- rct->ymin - 0.5f,
- rct->xmax + 0.5f,
- rct->ymax + 0.5f,
- radius + 0.5f,
- color);
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = rct->xmin - 0.5f,
+ .xmax = rct->xmax + 0.5f,
+ .ymin = rct->ymin - 0.5f,
+ .ymax = rct->ymax + 0.5f,
+ },
+ false,
+ radius + 0.5f,
+ color);
GPU_blend(GPU_BLEND_NONE);
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index b5aeee3d3bc..d246dfadefa 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -8325,7 +8325,7 @@ void ui_but_active_free(const bContext *C, uiBut *but)
}
/* returns the active button with an optional checking function */
-static uiBut *ui_context_button_active(ARegion *region, bool (*but_check_cb)(uiBut *))
+static uiBut *ui_context_button_active(const ARegion *region, bool (*but_check_cb)(const uiBut *))
{
uiBut *but_found = NULL;
@@ -8366,7 +8366,7 @@ static uiBut *ui_context_button_active(ARegion *region, bool (*but_check_cb)(uiB
return but_found;
}
-static bool ui_context_rna_button_active_test(uiBut *but)
+static bool ui_context_rna_button_active_test(const uiBut *but)
{
return (but->rnapoin.data != NULL);
}
@@ -8391,7 +8391,7 @@ uiBut *UI_context_active_but_get_respect_menu(const bContext *C)
return ui_context_button_active(region_menu ? region_menu : CTX_wm_region(C), NULL);
}
-uiBut *UI_region_active_but_get(ARegion *region)
+uiBut *UI_region_active_but_get(const ARegion *region)
{
return ui_context_button_active(region, NULL);
}
@@ -8489,6 +8489,15 @@ wmOperator *UI_context_active_operator_get(const struct bContext *C)
return NULL;
}
+/**
+ * Try to find a search-box region opened from a button in \a button_region.
+ */
+ARegion *UI_region_searchbox_region_get(const ARegion *button_region)
+{
+ uiBut *but = UI_region_active_but_get(button_region);
+ return (but != NULL) ? but->active->searchbox : NULL;
+}
+
/* helper function for insert keyframe, reset to default, etc operators */
void UI_context_update_anim_flag(const bContext *C)
{
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index 223fcbfd45b..3962ff6a702 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -118,7 +118,15 @@ void icon_draw_rect_input(float x,
UI_GetThemeColor4fv(TH_TEXT, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_aa(
- false, (int)x - U.pixelsize, (int)y, (int)(x + w), (int)(y + h), 3.0f * U.pixelsize, color);
+ &(const rctf){
+ .xmin = (int)x - U.pixelsize,
+ .xmax = (int)(x + w),
+ .ymin = (int)y,
+ .ymax = (int)(y + h),
+ },
+ false,
+ 3.0f * U.pixelsize,
+ color);
const enum {
UNIX,
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index bf140eb1692..b4af63b6f4d 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -1121,13 +1121,16 @@ static void panel_draw_highlight_border(const Panel *panel,
float color[4];
UI_GetThemeColor4fv(TH_SELECT_ACTIVE, color);
- UI_draw_roundbox_4fv(false,
- rect->xmin,
- UI_panel_is_closed(panel) ? header_rect->ymin : rect->ymin,
- rect->xmax,
- header_rect->ymax,
- radius,
- color);
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = rect->xmin,
+ .xmax = rect->xmax,
+ .ymin = UI_panel_is_closed(panel) ? header_rect->ymin : rect->ymin,
+ .ymax = header_rect->ymax,
+ },
+ false,
+ radius,
+ color);
}
static void panel_draw_aligned_widgets(const uiStyle *style,
@@ -1253,13 +1256,16 @@ static void panel_draw_aligned_backdrop(const Panel *panel,
float color[4];
UI_GetThemeColor4fv(TH_PANEL_SUB_BACK, color);
/* Change the width a little bit to line up with sides. */
- UI_draw_roundbox_aa(true,
- rect->xmin + U.pixelsize,
- rect->ymin + U.pixelsize,
- rect->xmax - U.pixelsize,
- rect->ymax,
- box_wcol->roundness * U.widget_unit,
- color);
+ UI_draw_roundbox_aa(
+ &(const rctf){
+ .xmin = rect->xmin + U.pixelsize,
+ .xmax = rect->xmax - U.pixelsize,
+ .ymin = rect->ymin + U.pixelsize,
+ .ymax = rect->ymax,
+ },
+ true,
+ box_wcol->roundness * U.widget_unit,
+ color);
}
else {
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
@@ -1544,20 +1550,26 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
{
/* Draw filled rectangle and outline for tab. */
UI_draw_roundbox_corner_set(roundboxtype);
- UI_draw_roundbox_4fv(true,
- rct->xmin,
- rct->ymin,
- rct->xmax,
- rct->ymax,
- tab_curve_radius,
- is_active ? theme_col_tab_active : theme_col_tab_inactive);
- UI_draw_roundbox_4fv(false,
- rct->xmin,
- rct->ymin,
- rct->xmax,
- rct->ymax,
- tab_curve_radius,
- theme_col_tab_outline);
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = rct->xmin,
+ .xmax = rct->xmax,
+ .ymin = rct->ymin,
+ .ymax = rct->ymax,
+ },
+ true,
+ tab_curve_radius,
+ is_active ? theme_col_tab_active : theme_col_tab_inactive);
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = rct->xmin,
+ .xmax = rct->xmax,
+ .ymin = rct->ymin,
+ .ymax = rct->ymax,
+ },
+ false,
+ tab_curve_radius,
+ theme_col_tab_outline);
/* Disguise the outline on one side to join the tab to the panel. */
pos = GPU_vertformat_attr_add(
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index 93e3dbb2cc8..62b8ce9d3eb 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -413,12 +413,11 @@ static void ui_block_region_draw(const bContext *C, ARegion *region)
/**
* Use to refresh centered popups on screen resizing (for splash).
*/
-static void ui_block_region_popup_window_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void ui_block_region_popup_window_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
switch (wmn->category) {
case NC_WINDOW: {
switch (wmn->action) {
diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c
index 816162e9aa2..d5a9a94b8ae 100644
--- a/source/blender/editors/interface/interface_region_search.c
+++ b/source/blender/editors/interface/interface_region_search.c
@@ -347,9 +347,20 @@ static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C,
}
uiButSearch *search_but = (uiButSearch *)but;
- if (search_but->item_tooltip_fn) {
- return search_but->item_tooltip_fn(C, region, search_but->arg, search_but->item_active);
+ if (!search_but->item_tooltip_fn) {
+ continue;
}
+
+ ARegion *searchbox_region = UI_region_searchbox_region_get(region);
+ uiSearchboxData *data = searchbox_region->regiondata;
+
+ BLI_assert(data->items.pointers[data->active] == search_but->item_active);
+
+ rcti rect;
+ ui_searchbox_butrect(&rect, data, data->active);
+
+ return search_but->item_tooltip_fn(
+ C, region, &rect, search_but->arg, search_but->item_active);
}
}
return NULL;
@@ -452,8 +463,11 @@ static void ui_searchbox_update_fn(bContext *C,
const char *str,
uiSearchItems *items)
{
- wmWindow *win = CTX_wm_window(C);
- WM_tooltip_clear(C, win);
+ /* While the button is in text editing mode (searchbox open), remove tooltips on every update. */
+ if (search_but->but.editstr) {
+ wmWindow *win = CTX_wm_window(C);
+ WM_tooltip_clear(C, win);
+ }
search_but->items_update_fn(C, search_but->arg, str, items);
}
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index 2bf63955855..050a14cf574 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -1456,15 +1456,91 @@ ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz)
{
wmWindow *win = CTX_wm_window(C);
const float aspect = 1.0f;
- float init_position[2];
+ float init_position[2] = {win->eventstate->x, win->eventstate->y};
uiTooltipData *data = ui_tooltip_data_from_gizmo(C, gz);
if (data == NULL) {
return NULL;
}
+ /* TODO(harley):
+ * Julian preferred that the gizmo callback return the 3D bounding box
+ * which we then project to 2D here. Would make a nice improvement.
+ */
+ if (gz->type->screen_bounds_get) {
+ rcti bounds;
+ gz->type->screen_bounds_get(C, gz, &bounds);
+ init_position[0] = bounds.xmin;
+ init_position[1] = bounds.ymin;
+ }
+
+ return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect);
+}
+
+static uiTooltipData *ui_tooltip_data_from_search_item_tooltip_data(
+ const uiSearchItemTooltipData *item_tooltip_data)
+{
+ uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
+
+ if (item_tooltip_data->description[0]) {
+ uiTooltipField *field = text_field_add(data,
+ &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_HEADER,
+ .color_id = UI_TIP_LC_NORMAL,
+ .is_pad = true,
+ });
+ field->text = BLI_strdup(item_tooltip_data->description);
+ }
+
+ if (item_tooltip_data->name && item_tooltip_data->name[0]) {
+ uiTooltipField *field = text_field_add(data,
+ &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = BLI_strdup(item_tooltip_data->name);
+ }
+ if (item_tooltip_data->hint[0]) {
+ uiTooltipField *field = text_field_add(data,
+ &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_NORMAL,
+ .is_pad = true,
+ });
+ field->text = BLI_strdup(item_tooltip_data->hint);
+ }
+
+ if (data->fields_len == 0) {
+ MEM_freeN(data);
+ return NULL;
+ }
+ return data;
+}
+
+/**
+ * Create a tooltip from search-item tooltip data \a item_tooltip data.
+ * To be called from a callback set with #UI_but_func_search_set_tooltip().
+ *
+ * \param item_rect: Rectangle of the search item in search region space (#ui_searchbox_butrect())
+ * which is passed to the tooltip callback.
+ */
+ARegion *UI_tooltip_create_from_search_item_generic(
+ bContext *C,
+ const ARegion *searchbox_region,
+ const rcti *item_rect,
+ const uiSearchItemTooltipData *item_tooltip_data)
+{
+ uiTooltipData *data = ui_tooltip_data_from_search_item_tooltip_data(item_tooltip_data);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ const float aspect = 1.0f;
+ const wmWindow *win = CTX_wm_window(C);
+ float init_position[2];
init_position[0] = win->eventstate->x;
- init_position[1] = win->eventstate->y;
+ init_position[1] = item_rect->ymin + searchbox_region->winrct.ymin - (UI_POPUP_MARGIN / 2);
return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect);
}
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index a37fb0dfde1..eaefc2c3736 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -341,13 +341,16 @@ void UI_fontstyle_draw_simple_backdrop(const uiFontStyle *fs,
const float color[4] = {col_bg[0], col_bg[1], col_bg[2], 0.5f};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(true,
- x - margin,
- (y + decent) - margin,
- x + width + margin,
- (y + decent) + height + margin,
- margin,
- color);
+ UI_draw_roundbox_aa(
+ &(const rctf){
+ .xmin = x - margin,
+ .xmax = x + width + margin,
+ .ymin = (y + decent) - margin,
+ .ymax = (y + decent) + height + margin,
+ },
+ true,
+ margin,
+ color);
}
BLF_position(fs->uifont_id, x, y, 0.0f);
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c
index 9f4cd32588d..25cf2e12377 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.c
@@ -1069,6 +1069,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
struct ARegion *region,
+ const rcti *UNUSED(item_rect),
void *arg,
void *active)
{
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 003bb110baf..8127a32b271 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -208,6 +208,7 @@ static uiBlock *template_common_search_menu(const bContext *C,
void *search_arg,
uiButHandleFunc search_exec_fn,
void *active_item,
+ uiButSearchTooltipFn item_tooltip_fn,
const int preview_rows,
const int preview_cols,
float scale)
@@ -284,6 +285,7 @@ static uiBlock *template_common_search_menu(const bContext *C,
NULL,
search_exec_fn,
active_item);
+ UI_but_func_search_set_tooltip(but, item_tooltip_fn);
UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
UI_block_direction_set(block, UI_DIR_DOWN);
@@ -485,6 +487,31 @@ static void id_search_cb_objects_from_scene(const bContext *C,
id_search_cb_tagged(C, arg_template, str, items);
}
+static ARegion *template_ID_search_menu_item_tooltip(
+ bContext *C, ARegion *region, const rcti *item_rect, void *arg, void *active)
+{
+ TemplateID *template_ui = arg;
+ ID *active_id = active;
+ StructRNA *type = RNA_property_pointer_type(&template_ui->ptr, template_ui->prop);
+
+ uiSearchItemTooltipData tooltip_data = {0};
+
+ tooltip_data.name = active_id->name + 2;
+ BLI_snprintf(tooltip_data.description,
+ sizeof(tooltip_data.description),
+ TIP_("Choose %s data-block to be assigned to this user"),
+ RNA_struct_ui_name(type));
+ if (ID_IS_LINKED(active_id)) {
+ BLI_snprintf(tooltip_data.hint,
+ sizeof(tooltip_data.hint),
+ TIP_("Source library: %s\n%s"),
+ active_id->lib->id.name + 2,
+ active_id->lib->filepath);
+ }
+
+ return UI_tooltip_create_from_search_item_generic(C, region, item_rect, &tooltip_data);
+}
+
/* ID Search browse menu, open */
static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
{
@@ -512,6 +539,7 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
&template_ui,
template_ID_set_property_exec_fn,
active_item_ptr.data,
+ template_ID_search_menu_item_tooltip,
template_ui.prv_rows,
template_ui.prv_cols,
template_ui.scale);
@@ -1632,6 +1660,7 @@ static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_tem
&template_search,
template_search_exec_fn,
active_ptr.data,
+ NULL,
template_search.preview_rows,
template_search.preview_cols,
1.0f);
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 868f62c89c9..0c3448b987d 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1533,25 +1533,22 @@ static void ui_text_clip_right_ex(const uiFontStyle *fstyle,
{
BLI_assert(str[0]);
- /* If the trailing ellipsis takes more than 20% of all available width, just cut the string
- * (as using the ellipsis would remove even more useful chars, and we cannot show much
- * already!).
- */
- if (sep_strwidth / okwidth > 0.2f) {
- float tmp;
- const int l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, &tmp);
- str[l_end] = '\0';
+ /* How many BYTES (not characters) of this utf-8 string can fit, along with appended ellipsis. */
+ int l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, NULL);
+
+ if (l_end > 0) {
+ /* At least one character, so clip and add the ellipsis. */
+ memcpy(str + l_end, sep, sep_len + 1); /* +1 for trailing '\0'. */
if (r_final_len) {
- *r_final_len = (size_t)l_end;
+ *r_final_len = (size_t)(l_end) + sep_len;
}
}
else {
- float tmp;
- const int l_end = BLF_width_to_strlen(
- fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, &tmp);
- memcpy(str + l_end, sep, sep_len + 1); /* +1 for trailing '\0'. */
+ /* Otherwise fit as much as we can without adding an ellipsis. */
+ l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, NULL);
+ str[l_end] = '\0';
if (r_final_len) {
- *r_final_len = (size_t)(l_end) + sep_len;
+ *r_final_len = (size_t)l_end;
}
}
}
@@ -5224,8 +5221,7 @@ void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(bl
*
* \param state: The state of the button,
* typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
- * \param use_sep: When true, characters after the last #UI_SEP_CHAR are right aligned,
- * use for displaying key shortcuts.
+ * \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.
*/
@@ -5273,7 +5269,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_DPI_ICON_SIZE;
}
else if (separator_type == UI_MENU_ITEM_SEPARATOR_HINT) {
- /* Deterimine max-width for the hint string to leave the name string un-clipped (if there's
+ /* Determine max-width for the hint string to leave the name string un-clipped (if there's
* enough space to display it). */
const int available_width = BLI_rcti_size_x(rect) - padding;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index f115618c13b..59aee0fde29 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -1895,7 +1895,7 @@ void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
*
* \param r_x, r_y: scale on each axis
*/
-void UI_view2d_scale_get(View2D *v2d, float *r_x, float *r_y)
+void UI_view2d_scale_get(const View2D *v2d, float *r_x, float *r_y)
{
if (r_x) {
*r_x = UI_view2d_scale_get_x(v2d);
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 222f03ee1d8..4e642137d2a 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -1106,11 +1106,6 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op)
float dx = RNA_float_get(op->ptr, "deltax") / U.dpi_fac;
float dy = RNA_float_get(op->ptr, "deltay") / U.dpi_fac;
- if (U.uiflag & USER_ZOOM_INVERT) {
- dx *= -1;
- dy *= -1;
- }
-
/* Check if the 'timer' is initialized, as zooming with the trackpad
* never uses the "Continuous" zoom method, and the 'timer' is not initialized. */
if ((U.viewzoom == USER_ZOOM_CONT) && vzd->timer) { /* XXX store this setting as RNA prop? */
@@ -1232,26 +1227,53 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *even
vzd->lastx = event->prevx;
vzd->lasty = event->prevy;
- /* As we have only 1D information (magnify value), feed both axes
- * with magnify information that is stored in x axis
- */
- float fac = 0.01f * (event->prevx - event->x);
- float dx = fac * BLI_rctf_size_x(&v2d->cur) / 10.0f;
+ float facx, facy;
+ float zoomfac = 0.01f;
+
+ /* Some view2d's (graph) don't have min/max zoom, or extreme ones. */
+ if (v2d->maxzoom > 0.0f) {
+ zoomfac = clamp_f(0.001f * v2d->maxzoom, 0.001f, 0.01f);
+ }
+
if (event->type == MOUSEPAN) {
- fac = 0.01f * (event->prevy - event->y);
+ facx = zoomfac * WM_event_absolute_delta_x(event);
+ facy = zoomfac * WM_event_absolute_delta_y(event);
+
+ if (U.uiflag & USER_ZOOM_INVERT) {
+ facx *= -1.0f;
+ facy *= -1.0f;
+ }
+ }
+ else { /* MOUSEZOOM */
+ facx = facy = zoomfac * WM_event_absolute_delta_x(event);
+ }
+
+ /* Only respect user setting zoom axis if the view does not have any zoom restrictions
+ * any will be scaled uniformly. */
+ if (((v2d->keepzoom & (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y)) == 0) &&
+ (v2d->keepzoom & V2D_KEEPASPECT)) {
+ if (U.uiflag & USER_ZOOM_HORIZ) {
+ facy = 0.0f;
+ }
+ else {
+ facx = 0.0f;
+ }
}
- float dy = fac * BLI_rctf_size_y(&v2d->cur) / 10.0f;
/* support trackpad zoom to always zoom entirely - the v2d code uses portrait or
* landscape exceptions */
if (v2d->keepzoom & V2D_KEEPASPECT) {
- if (fabsf(dx) > fabsf(dy)) {
- dy = dx;
+ if (fabsf(facx) > fabsf(facy)) {
+ facy = facx;
}
else {
- dx = dy;
+ facx = facy;
}
}
+
+ const float dx = facx * BLI_rctf_size_x(&v2d->cur);
+ const float dy = facy * BLI_rctf_size_y(&v2d->cur);
+
RNA_float_set(op->ptr, "deltax", dx);
RNA_float_set(op->ptr, "deltay", dy);
@@ -1320,19 +1342,13 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event
/* x-axis transform */
dist = BLI_rcti_size_x(&v2d->mask) / 2.0f;
- len_old[0] = fabsf(vzd->lastx - vzd->region->winrct.xmin - dist);
- len_new[0] = fabsf(event->x - vzd->region->winrct.xmin - dist);
-
- len_old[0] *= zoomfac * BLI_rctf_size_x(&v2d->cur);
- len_new[0] *= zoomfac * BLI_rctf_size_x(&v2d->cur);
+ len_old[0] = zoomfac * fabsf(vzd->lastx - vzd->region->winrct.xmin - dist);
+ len_new[0] = zoomfac * fabsf(event->x - vzd->region->winrct.xmin - dist);
/* y-axis transform */
dist = BLI_rcti_size_y(&v2d->mask) / 2.0f;
- len_old[1] = fabsf(vzd->lasty - vzd->region->winrct.ymin - dist);
- len_new[1] = fabsf(event->y - vzd->region->winrct.ymin - dist);
-
- len_old[1] *= zoomfac * BLI_rctf_size_y(&v2d->cur);
- len_new[1] *= zoomfac * BLI_rctf_size_y(&v2d->cur);
+ len_old[1] = zoomfac * fabsf(vzd->lasty - vzd->region->winrct.ymin - dist);
+ len_new[1] = zoomfac * fabsf(event->y - vzd->region->winrct.ymin - dist);
/* Calculate distance */
if (v2d->keepzoom & V2D_KEEPASPECT) {
@@ -1343,40 +1359,44 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event
dx = len_new[0] - len_old[0];
dy = len_new[1] - len_old[1];
}
- }
- else {
- /* 'continuous' or 'dolly' */
- float fac;
- /* x-axis transform */
- fac = zoomfac * (event->x - vzd->lastx);
- dx = fac * BLI_rctf_size_x(&v2d->cur);
- /* y-axis transform */
- fac = zoomfac * (event->y - vzd->lasty);
- dy = fac * BLI_rctf_size_y(&v2d->cur);
+ dx *= BLI_rctf_size_x(&v2d->cur);
+ dy *= BLI_rctf_size_y(&v2d->cur);
+ }
+ else { /* USER_ZOOM_CONT or USER_ZOOM_DOLLY */
+ float facx = zoomfac * (event->x - vzd->lastx);
+ float facy = zoomfac * (event->y - vzd->lasty);
/* Only respect user setting zoom axis if the view does not have any zoom restrictions
* any will be scaled uniformly */
if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 && (v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 &&
(v2d->keepzoom & V2D_KEEPASPECT)) {
if (U.uiflag & USER_ZOOM_HORIZ) {
- dy = 0;
+ facy = 0.0f;
}
else {
- dx = 0;
+ facx = 0.0f;
}
}
- }
- /* support zoom to always zoom entirely - the v2d code uses portrait or
- * landscape exceptions */
- if (v2d->keepzoom & V2D_KEEPASPECT) {
- if (fabsf(dx) > fabsf(dy)) {
- dy = dx;
- }
- else {
- dx = dy;
+ /* support zoom to always zoom entirely - the v2d code uses portrait or
+ * landscape exceptions */
+ if (v2d->keepzoom & V2D_KEEPASPECT) {
+ if (fabsf(facx) > fabsf(facy)) {
+ facy = facx;
+ }
+ else {
+ facx = facy;
+ }
}
+
+ dx = facx * BLI_rctf_size_x(&v2d->cur);
+ dy = facy * BLI_rctf_size_y(&v2d->cur);
+ }
+
+ if (U.uiflag & USER_ZOOM_INVERT) {
+ dx *= -1.0f;
+ dy *= -1.0f;
}
/* set transform amount, and add current deltas to stored total delta (for redo) */
diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c
index 4497ca1a379..cb3f9a89e62 100644
--- a/source/blender/editors/lattice/editlattice_select.c
+++ b/source/blender/editors/lattice/editlattice_select.c
@@ -108,7 +108,7 @@ bool ED_lattice_deselect_all_multi(struct bContext *C)
static int lattice_select_random_exec(bContext *C, wmOperator *op)
{
- const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const float randfac = RNA_float_get(op->ptr, "ratio");
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index d7b3d74bc7e..1226cc57359 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -507,6 +507,9 @@ static int add_vertex_handle_cyclic(
static int add_vertex_exec(bContext *C, wmOperator *op)
{
+ MaskViewLockState lock_state;
+ ED_mask_view_lock_state_store(C, &lock_state);
+
Mask *mask = CTX_data_edit_mask(C);
if (mask == NULL) {
/* if there's no active mask, create one */
@@ -548,6 +551,8 @@ static int add_vertex_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY);
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
+
return OPERATOR_FINISHED;
}
@@ -690,6 +695,9 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot)
static int create_primitive_from_points(
bContext *C, wmOperator *op, const float (*points)[2], int num_points, char handle_type)
{
+ MaskViewLockState lock_state;
+ ED_mask_view_lock_state_store(C, &lock_state);
+
ScrArea *area = CTX_wm_area(C);
int size = RNA_float_get(op->ptr, "size");
@@ -752,6 +760,8 @@ static int create_primitive_from_points(
DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY);
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index 663ae0097ad..f1041d062a8 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -184,3 +184,39 @@ void ED_operatormacros_mask(void)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lock-to-selection viewport preservation
+ * \{ */
+
+void ED_mask_view_lock_state_store(const bContext *C, MaskViewLockState *state)
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ if (space_clip != NULL) {
+ ED_clip_view_lock_state_store(C, &state->space_clip_state);
+ }
+}
+
+void ED_mask_view_lock_state_restore_no_jump(const bContext *C, const MaskViewLockState *state)
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ if (space_clip != NULL) {
+ if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
+ /* Early output if the editor is not locked to selection.
+ * Avoids forced dependency graph evaluation here. */
+ return;
+ }
+
+ /* Mask's lock-to-selection requires deformed splines to be evaluated to calculate bounds of
+ * points after animation has been evaluated. The restore-no-jump type of function does
+ * calculation of new offset for the view for an updated state of mask to cancel the offset out
+ * by modifying locked offset. In order to do such calculation mask needs to be evaluated after
+ * modification by an operator. */
+ struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ (void)depsgraph;
+
+ ED_clip_view_lock_state_restore_no_jump(C, &state->space_clip_state);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index f6990583383..ee1784011ea 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -23,6 +23,8 @@
#pragma once
+#include "ED_clip.h"
+
struct Mask;
struct bContext;
struct wmOperatorType;
@@ -92,6 +94,19 @@ void ED_mask_select_flush_all(struct Mask *mask);
bool ED_maskedit_poll(struct bContext *C);
bool ED_maskedit_mask_poll(struct bContext *C);
+/* Generalized solution for preserving editor viewport when making changes while lock-to-selection
+ * is enabled.
+ * Any mask operator can use this API, without worrying that some editors do not have an idea of
+ * lock-to-selection. */
+
+typedef struct MaskViewLockState {
+ ClipViewLockState space_clip_state;
+} MaskViewLockState;
+
+void ED_mask_view_lock_state_store(const struct bContext *C, MaskViewLockState *state);
+void ED_mask_view_lock_state_restore_no_jump(const struct bContext *C,
+ const MaskViewLockState *state);
+
/* mask_query.c */
bool ED_mask_find_nearest_diff_point(const struct bContext *C,
struct Mask *mask,
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index 25cc39bf9a0..14f81520b9a 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -226,13 +226,19 @@ typedef struct SlidePointData {
int width, height;
float prev_mouse_coord[2];
+
+ /* Previous clip coordinate which was resolved from mouse position (0, 0).
+ * Is used to compensate for view offset moving in-between of mouse events when
+ * lock-to-selection is enabled. */
+ float prev_zero_coord[2];
+
float no[2];
bool is_curvature_only, is_accurate, is_initial_feather, is_overall_feather;
bool is_sliding_new_point;
- /* Data needed to restre the state. */
+ /* Data needed to restore the state. */
float vec[3][3];
char old_h1, old_h2;
@@ -431,6 +437,9 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
const float threshold = 19;
eMaskWhichHandle which_handle;
+ MaskViewLockState lock_state;
+ ED_mask_view_lock_state_store(C, &lock_state);
+
ED_mask_mouse_pos(area, region, event->mval, co);
ED_mask_get_size(area, &width, &height);
@@ -530,7 +539,15 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
}
customdata->which_handle = which_handle;
+ {
+ WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
+ DEG_id_tag_update(&mask->id, 0);
+
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
+ }
+
ED_mask_mouse_pos(area, region, event->mval, customdata->prev_mouse_coord);
+ ED_mask_mouse_pos(area, region, (int[2]){0, 0}, customdata->prev_zero_coord);
}
return customdata;
@@ -655,10 +672,24 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_mask_mouse_pos(area, region, event->mval, co);
sub_v2_v2v2(delta, co, data->prev_mouse_coord);
+ copy_v2_v2(data->prev_mouse_coord, co);
+
+ /* Compensate for possibly moved view offset since the last event.
+ * The idea is to see how mapping of a fixed and known position did change. */
+ {
+ float zero_coord[2];
+ ED_mask_mouse_pos(area, region, (int[2]){0, 0}, zero_coord);
+
+ float zero_delta[2];
+ sub_v2_v2v2(zero_delta, zero_coord, data->prev_zero_coord);
+ sub_v2_v2(delta, zero_delta);
+
+ copy_v2_v2(data->prev_zero_coord, zero_coord);
+ }
+
if (data->is_accurate) {
mul_v2_fl(delta, 0.2f);
}
- copy_v2_v2(data->prev_mouse_coord, co);
if (data->action == SLIDE_ACTION_HANDLE) {
float new_handle[2];
@@ -832,7 +863,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == data->event_invoke_type && event->val == KM_RELEASE) {
Scene *scene = CTX_data_scene(C);
- /* dont key sliding feather uw's */
+ /* Don't key sliding feather UW's. */
if ((data->action == SLIDE_ACTION_FEATHER && data->uw) == false) {
if (IS_AUTOKEY_ON(scene)) {
ED_mask_layer_shape_auto_key(data->mask_layer, CFRA);
@@ -966,6 +997,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(bContext *C,
float u, co[2];
BezTriple *next_bezt;
+ MaskViewLockState lock_state;
+ ED_mask_view_lock_state_store(C, &lock_state);
+
ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co);
if (!ED_mask_find_nearest_diff_point(C,
@@ -1019,7 +1053,7 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(bContext *C,
slide_data->bezt_backup = *slide_data->adjust_bezt;
slide_data->other_bezt_backup = *slide_data->other_bezt;
- /* Let's dont touch other side of the point for now, so set handle to FREE. */
+ /* Let's don't touch other side of the point for now, so set handle to FREE. */
if (u < 0.5f) {
if (slide_data->adjust_bezt->h2 <= HD_VECT) {
slide_data->adjust_bezt->h2 = HD_FREE;
@@ -1047,6 +1081,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(bContext *C,
mask_layer->act_point = point;
ED_mask_select_flush_all(mask);
+ DEG_id_tag_update(&mask->id, 0);
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
+
return slide_data;
}
@@ -1233,7 +1270,7 @@ static int slide_spline_curvature_modal(bContext *C, wmOperator *op, const wmEve
case LEFTMOUSE:
case RIGHTMOUSE:
if (event->type == slide_data->event_invoke_type && event->val == KM_RELEASE) {
- /* dont key sliding feather uw's */
+ /* Don't key sliding feather UW's. */
if (IS_AUTOKEY_ON(scene)) {
ED_mask_layer_shape_auto_key(slide_data->mask_layer, CFRA);
}
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index cfd57ca3477..eace146dbe9 100644
--- a/source/blender/editors/mask/mask_query.c
+++ b/source/blender/editors/mask/mask_query.c
@@ -604,22 +604,22 @@ void ED_mask_point_pos__reverse(
*yr = co[1];
}
-bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
+bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2], bool include_handles)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Mask *mask = CTX_data_edit_mask(C);
- /* Use evaluated mask to take animation into account.
- * The animation of splies is not "flushed" back to original, so need to explicitly
- * sue evaluated datablock here. */
- Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask->id);
-
bool ok = false;
if (mask == NULL) {
return ok;
}
+ /* Use evaluated mask to take animation into account.
+ * The animation of splies is not "flushed" back to original, so need to explicitly
+ * sue evaluated datablock here. */
+ Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask->id);
+
INIT_MINMAX2(min, max);
for (MaskLayer *mask_layer = mask_eval->masklayers.first; mask_layer != NULL;
mask_layer = mask_layer->next) {
@@ -638,22 +638,29 @@ bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
}
if (bezt->f2 & SELECT) {
minmax_v2v2_v2(min, max, deform_point->bezt.vec[1]);
+ ok = true;
+ }
+
+ if (!include_handles) {
+ /* Ignore handles. */
}
- if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+ else if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_STICK, handle);
minmax_v2v2_v2(min, max, handle);
+ ok = true;
}
else {
if ((bezt->f1 & SELECT) && (bezt->h1 != HD_VECT)) {
BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_LEFT, handle);
minmax_v2v2_v2(min, max, handle);
+ ok = true;
}
if ((bezt->f3 & SELECT) && (bezt->h2 != HD_VECT)) {
BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_RIGHT, handle);
minmax_v2v2_v2(min, max, handle);
+ ok = true;
}
}
- ok = true;
}
}
}
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index cdc6ece1e84..5c369afc4cd 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -214,12 +214,17 @@ static int select_all_exec(bContext *C, wmOperator *op)
Mask *mask = CTX_data_edit_mask(C);
int action = RNA_enum_get(op->ptr, "action");
+ MaskViewLockState lock_state;
+ ED_mask_view_lock_state_store(C, &lock_state);
+
ED_mask_select_toggle_all(mask, action);
ED_mask_select_flush_all(mask);
DEG_id_tag_update(&mask->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
+
return OPERATOR_FINISHED;
}
@@ -261,6 +266,9 @@ static int select_exec(bContext *C, wmOperator *op)
eMaskWhichHandle which_handle;
const float threshold = 19;
+ MaskViewLockState lock_state;
+ ED_mask_view_lock_state_store(C, &lock_state);
+
RNA_float_get_array(op->ptr, "location", co);
point = ED_mask_point_find_nearest(
@@ -324,6 +332,8 @@ static int select_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&mask->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
+
return OPERATOR_FINISHED;
}
@@ -364,12 +374,15 @@ static int select_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&mask->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
+
return OPERATOR_FINISHED;
}
if (deselect_all) {
/* For clip editor tracks, leave deselect all to clip editor. */
if (!ED_clip_can_select(C)) {
ED_mask_deselect_all(C);
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
return OPERATOR_FINISHED;
}
}
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index f45f48e0e32..379140a821a 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2752,8 +2752,6 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
}
- view3d_operator_needs_opengl(C);
-
/* alloc new customdata */
kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
@@ -2831,7 +2829,6 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
em_setup_viewcontext(C, &kcd->vc);
kcd->region = kcd->vc.region;
- view3d_operator_needs_opengl(C);
ED_view3d_init_mats_rv3d(obedit, kcd->vc.rv3d); /* needed to initialize clipping */
if (kcd->mode == MODE_PANNING) {
@@ -3067,8 +3064,6 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
{
KnifeTool_OpData *kcd;
- view3d_operator_needs_opengl(C);
-
/* init */
{
const bool only_select = false;
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index b5b4802aa78..0c68bb8f82b 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -4573,7 +4573,7 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot)
static int edbm_select_random_exec(bContext *C, wmOperator *op)
{
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
- const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const float randfac = RNA_float_get(op->ptr, "ratio");
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
ViewLayer *view_layer = CTX_data_view_layer(C);
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 094011ebef1..cf453bf0c32 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -483,7 +483,7 @@ void MBALL_OT_select_similar(wmOperatorType *ot)
static int select_random_metaelems_exec(bContext *C, wmOperator *op)
{
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
- const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const float randfac = RNA_float_get(op->ptr, "ratio");
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
ViewLayer *view_layer = CTX_data_view_layer(C);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index c6d6b8b16b9..9ab5eafa84d 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -607,7 +607,6 @@ Object *ED_object_add_type_with_obdata(bContext *C,
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- /* For as long scene has editmode... */
{
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
if (obedit != NULL) {
@@ -3364,6 +3363,9 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
ED_view3d_cursor3d_position(C, mval, false, basen->object->loc);
}
+ /* object_add_duplicate_internal() doesn't deselect other objects, unlike object_add_common() or
+ * BKE_view_layer_base_deselect_all(). */
+ ED_object_base_deselect_all(view_layer, NULL, BA_DESELECT);
ED_object_base_select(basen, BA_SELECT);
ED_object_base_activate(C, basen);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index acad1b43cbb..e4d06dca8cf 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1790,20 +1790,33 @@ void OBJECT_OT_make_links_scene(wmOperatorType *ot)
void OBJECT_OT_make_links_data(wmOperatorType *ot)
{
static const EnumPropertyItem make_links_items[] = {
- {MAKE_LINKS_OBDATA, "OBDATA", 0, "Object Data", ""},
- {MAKE_LINKS_MATERIALS, "MATERIAL", 0, "Materials", ""},
- {MAKE_LINKS_ANIMDATA, "ANIMATION", 0, "Animation Data", ""},
- {MAKE_LINKS_GROUP, "GROUPS", 0, "Collection", ""},
- {MAKE_LINKS_DUPLICOLLECTION, "DUPLICOLLECTION", 0, "Instance Collection", ""},
- {MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Modifiers", ""},
- {MAKE_LINKS_FONTS, "FONTS", 0, "Fonts", ""},
- {MAKE_LINKS_SHADERFX, "EFFECTS", 0, "Effects", ""},
+ {MAKE_LINKS_OBDATA, "OBDATA", 0, "Link Object Data", "Replace assigned Object Data"},
+ {MAKE_LINKS_MATERIALS, "MATERIAL", 0, "Link Materials", "Replace assigned Materials"},
+ {MAKE_LINKS_ANIMDATA,
+ "ANIMATION",
+ 0,
+ "Link Animation Data",
+ "Replace assigned Animation Data"},
+ {MAKE_LINKS_GROUP, "GROUPS", 0, "Link Collections", "Replace assigned Collections"},
+ {MAKE_LINKS_DUPLICOLLECTION,
+ "DUPLICOLLECTION",
+ 0,
+ "Link Instance Collection",
+ "Replace assigned Collection Instance"},
+ {MAKE_LINKS_FONTS, "FONTS", 0, "Link Fonts to Text", "Replace Text object Fonts"},
+ {0, "", 0, NULL, NULL},
+ {MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Copy Modifiers", "Replace Modifiers"},
+ {MAKE_LINKS_SHADERFX,
+ "EFFECTS",
+ 0,
+ "Copy Grease Pencil Effects",
+ "Replace Grease Pencil Effects"},
{0, NULL, 0, NULL, NULL},
};
/* identifiers */
- ot->name = "Link Data";
- ot->description = "Apply active object links to other selected objects";
+ ot->name = "Link/Transfer Data";
+ ot->description = "Transfer data from active object to selected objects";
ot->idname = "OBJECT_OT_make_links_data";
/* api callbacks */
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index b36d89dc37a..50dac12ab57 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -1453,7 +1453,7 @@ void OBJECT_OT_select_less(wmOperatorType *ot)
static int object_select_random_exec(bContext *C, wmOperator *op)
{
- const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const float randfac = RNA_float_get(op->ptr, "ratio");
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 0528d64dca9..13c0740bce6 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1394,7 +1394,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
* (all layers are considered without evaluating lock attributes) */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* calculate difference matrix */
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
/* undo matrix */
invert_m4_m4(inverse_diff_mat, diff_mat);
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 381bf317bee..a761701f60b 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -233,7 +233,7 @@ static int output_toggle_exec(bContext *C, wmOperator *op)
/* if type is already enabled, toggle it off */
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- int exists = dynamicPaint_outputLayerExists(surface, ob, output);
+ bool exists = dynamicPaint_outputLayerExists(surface, ob, output);
const char *name;
if (output == 0) {
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 8ab25fa74b8..3a6201fd418 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1999,7 +1999,7 @@ static int select_random_exec(bContext *C, wmOperator *op)
int p;
int k;
- const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const float randfac = RNA_float_get(op->ptr, "ratio");
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
RNG *rng;
@@ -3750,8 +3750,7 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance)
}
}
else {
- /* compute position as if hair was standing up straight.
- * */
+ /* Compute position as if hair was standing up straight. */
float length;
copy_v3_v3(co_prev, co);
copy_v3_v3(co, key->co);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 6cf8515bdbb..e30149fde73 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -200,6 +200,11 @@ static bool check_engine_supports_preview(Scene *scene)
return (type->flag & RE_USE_PREVIEW) != 0;
}
+static bool preview_method_is_render(int pr_method)
+{
+ return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER, PR_NODE_RENDER);
+}
+
void ED_preview_free_dbase(void)
{
if (G_pr_main) {
@@ -1352,13 +1357,12 @@ static void common_preview_startjob(void *customdata,
*/
static void other_id_types_preview_render(IconPreview *ip,
IconPreviewSize *cur_size,
- const bool is_deferred,
+ const int pr_method,
short *stop,
short *do_update,
float *progress)
{
ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
- const bool is_render = !is_deferred;
/* These types don't use the ShaderPreview mess, they have their own types and functions. */
BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB));
@@ -1368,7 +1372,7 @@ static void other_id_types_preview_render(IconPreview *ip,
sp->owner = ip->owner;
sp->sizex = cur_size->sizex;
sp->sizey = cur_size->sizey;
- sp->pr_method = is_render ? PR_ICON_RENDER : PR_ICON_DEFERRED;
+ sp->pr_method = pr_method;
sp->pr_rect = cur_size->rect;
sp->id = ip->id;
sp->id_copy = ip->id_copy;
@@ -1376,7 +1380,7 @@ static void other_id_types_preview_render(IconPreview *ip,
sp->own_id_copy = false;
Material *ma = NULL;
- if (is_render) {
+ if (sp->pr_method == PR_ICON_RENDER) {
BLI_assert(ip->id);
/* grease pencil use its own preview file */
@@ -1424,6 +1428,8 @@ static void icon_preview_startjob_all_sizes(void *customdata,
for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) {
PreviewImage *prv = ip->owner;
+ /* Is this a render job or a deferred loading job? */
+ const int pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED : PR_ICON_RENDER;
if (*stop) {
break;
@@ -1434,7 +1440,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
continue;
}
- if (!check_engine_supports_preview(ip->scene)) {
+ if (preview_method_is_render(pr_method) && !check_engine_supports_preview(ip->scene)) {
continue;
}
@@ -1450,8 +1456,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
object_preview_render(ip, cur_size);
}
else {
- other_id_types_preview_render(
- ip, cur_size, (prv->tag & PRV_TAG_DEFFERED), stop, do_update, progress);
+ other_id_types_preview_render(ip, cur_size, pr_method, stop, do_update, progress);
}
}
}
@@ -1634,7 +1639,7 @@ void ED_preview_shader_job(const bContext *C,
/* Use workspace render only for buttons Window,
* since the other previews are related to the datablock. */
- if (!check_engine_supports_preview(scene)) {
+ if (preview_method_is_render(method) && !check_engine_supports_preview(scene)) {
return;
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 581169d823e..2c71345699f 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -141,13 +141,15 @@ void ED_region_pixelspace(ARegion *region)
}
/* only exported for WM */
-void ED_region_do_listen(
- wmWindow *win, ScrArea *area, ARegion *region, wmNotifier *note, const Scene *scene)
+void ED_region_do_listen(wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *notifier = params->notifier;
+
/* generic notes first */
- switch (note->category) {
+ switch (notifier->category) {
case NC_WM:
- if (note->data == ND_FILEREAD) {
+ if (notifier->data == ND_FILEREAD) {
ED_region_tag_redraw(region);
}
break;
@@ -157,16 +159,16 @@ void ED_region_do_listen(
}
if (region->type && region->type->listener) {
- region->type->listener(win, area, region, note, scene);
+ region->type->listener(params);
}
}
/* only exported for WM */
-void ED_area_do_listen(wmWindow *win, ScrArea *area, wmNotifier *note, Scene *scene)
+void ED_area_do_listen(wmSpaceTypeListenerParams *params)
{
/* no generic notes? */
- if (area->type && area->type->listener) {
- area->type->listener(win, area, note, scene);
+ if (params->area->type && params->area->type->listener) {
+ params->area->type->listener(params);
}
}
@@ -289,7 +291,15 @@ static void region_draw_azone_tab_arrow(ScrArea *area, ARegion *region, AZone *a
float alpha = WM_region_use_viewport(area, region) ? 0.6f : 0.4f;
const float color[4] = {0.05f, 0.05f, 0.05f, alpha};
UI_draw_roundbox_aa(
- true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, color);
+ &(const rctf){
+ .xmin = (float)az->x1,
+ .xmax = (float)az->x2,
+ .ymin = (float)az->y1,
+ .ymax = (float)az->y2,
+ },
+ true,
+ 4.0f,
+ color);
draw_azone_arrow((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, az->edge);
}
@@ -373,7 +383,16 @@ static void region_draw_status_text(ScrArea *area, ARegion *region)
float color[4] = {0.0f, 0.0f, 0.0f, 0.5f};
UI_GetThemeColor3fv(TH_BACK, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(true, x1, y1, x2, y2, 4.0f, color);
+ UI_draw_roundbox_aa(
+ &(const rctf){
+ .xmin = x1,
+ .xmax = x2,
+ .ymin = y1,
+ .ymax = y2,
+ },
+ true,
+ 4.0f,
+ color);
UI_FontThemeColor(fontid, TH_TEXT);
}
@@ -418,16 +437,13 @@ void ED_area_do_msg_notify_tag_refresh(
ED_area_tag_refresh(area);
}
-void ED_area_do_mgs_subscribe_for_tool_header(
- /* Follow ARegionType.message_subscribe */
- const struct bContext *UNUSED(C),
- struct WorkSpace *workspace,
- struct Scene *UNUSED(scene),
- struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(area),
- struct ARegion *region,
- struct wmMsgBus *mbus)
+/* Follow ARegionType.message_subscribe */
+void ED_area_do_mgs_subscribe_for_tool_header(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ WorkSpace *workspace = params->workspace;
+ ARegion *region = params->region;
+
BLI_assert(region->regiontype == RGN_TYPE_TOOL_HEADER);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
@@ -438,16 +454,12 @@ void ED_area_do_mgs_subscribe_for_tool_header(
mbus, &workspace->id, workspace, WorkSpace, tools, &msg_sub_value_region_tag_redraw);
}
-void ED_area_do_mgs_subscribe_for_tool_ui(
- /* Follow ARegionType.message_subscribe */
- const struct bContext *UNUSED(C),
- struct WorkSpace *workspace,
- struct Scene *UNUSED(scene),
- struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(area),
- struct ARegion *region,
- struct wmMsgBus *mbus)
+void ED_area_do_mgs_subscribe_for_tool_ui(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ WorkSpace *workspace = params->workspace;
+ ARegion *region = params->region;
+
BLI_assert(region->regiontype == RGN_TYPE_UI);
const char *panel_category_tool = "Tool";
const char *category = UI_panel_category_active_get(region, false);
@@ -634,7 +646,16 @@ void ED_region_do_draw(bContext *C, ARegion *region)
WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_region_tag_redraw, __func__);
}
- ED_region_message_subscribe(C, workspace, scene, screen, area, region, mbus);
+ wmRegionMessageSubscribeParams message_subscribe_params = {
+ .context = C,
+ .message_bus = mbus,
+ .workspace = workspace,
+ .scene = scene,
+ .screen = screen,
+ .area = area,
+ .region = region,
+ };
+ ED_region_message_subscribe(&message_subscribe_params);
}
}
@@ -4027,14 +4048,12 @@ void ED_region_cache_draw_cached_segments(
/**
* Generate subscriptions for this region.
*/
-void ED_region_message_subscribe(bContext *C,
- struct WorkSpace *workspace,
- struct Scene *scene,
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus)
+void ED_region_message_subscribe(wmRegionMessageSubscribeParams *params)
{
+ ARegion *region = params->region;
+ const bContext *C = params->context;
+ struct wmMsgBus *mbus = params->message_bus;
+
if (region->gizmo_map != NULL) {
WM_gizmomap_message_subscribe(C, region->gizmo_map, region, mbus);
}
@@ -4044,7 +4063,7 @@ void ED_region_message_subscribe(bContext *C,
}
if (region->type->message_subscribe != NULL) {
- region->type->message_subscribe(C, workspace, scene, screen, area, region, mbus);
+ region->type->message_subscribe(params);
}
}
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index 075759f1120..b784a4b0056 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -22,6 +22,8 @@
#include "DNA_userdef_types.h"
+#include "BKE_screen.h"
+
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -42,14 +44,11 @@
/**
* Callback for #ARegionType.message_subscribe
*/
-void ED_region_generic_tools_region_message_subscribe(const struct bContext *UNUSED(C),
- struct WorkSpace *UNUSED(workspace),
- struct Scene *UNUSED(scene),
- struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(area),
- struct ARegion *region,
- struct wmMsgBus *mbus)
+void ED_region_generic_tools_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ ARegion *region = params->region;
+
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 33b918e6d4d..a88afecd064 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -57,11 +57,12 @@ static void immDrawPixelsTexSetupAttributes(IMMDrawPixelsTexState *state)
vert_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
}
-/* To be used before calling immDrawPixelsTex
- * Default shader is GPU_SHADER_2D_IMAGE_COLOR
- * You can still set uniforms with :
- * GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0);
- * */
+/**
+ * To be used before calling #immDrawPixelsTex
+ * Default shader is #GPU_SHADER_2D_IMAGE_COLOR
+ * You can still set uniforms with:
+ * `GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0);`
+ */
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
{
IMMDrawPixelsTexState state;
@@ -77,10 +78,11 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
return state;
}
-/* Use the currently bound shader.
+/**
+ * Use the currently bound shader.
*
- * Use immDrawPixelsTexSetup to bind the shader you
- * want before calling immDrawPixelsTex.
+ * Use #immDrawPixelsTexSetup to bind the shader you
+ * want before calling #immDrawPixelsTex.
*
* If using a special shader double check it uses the same
* attributes "pos" "texCoord" and uniform "image".
@@ -89,7 +91,7 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
*
* Be also aware that this function unbinds the shader when
* it's finished.
- * */
+ */
void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
float x,
float y,
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 1dfe606be78..627a67358f2 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -866,7 +866,7 @@ static eContextResult screen_ctx_editable_gpencil_strokes(const bContext *C,
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
if (ED_gpencil_stroke_can_use_direct(area, gps)) {
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) {
continue;
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index be52874ed0b..0868d5a5fe9 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -871,6 +871,11 @@ static void screen_global_area_refresh(wmWindow *win,
const short height_min,
const short height_max)
{
+ /* Full-screens shouldn't have global areas. Don't touch them. */
+ if (screen->state == SCREENFULL) {
+ return;
+ }
+
ScrArea *area = NULL;
LISTBASE_FOREACH (ScrArea *, area_iter, &win->global_areas.areabase) {
if (area_iter->spacetype == space_type) {
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 6e6386b24aa..27726b8370e 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -2415,9 +2415,10 @@ static bool IsectPT2Df_limit(
(area_tri_v2(v1, v2, v3))) < limit;
}
-/* Clip the face by a bucket and set the uv-space bucket_bounds_uv
+/**
+ * Clip the face by a bucket and set the uv-space bucket_bounds_uv
* so we have the clipped UV's to do pixel intersection tests with
- * */
+ */
static int float_z_sort_flip(const void *p1, const void *p2)
{
return (((float *)p1)[2] < ((float *)p2)[2] ? 1 : -1);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index ff0201f9702..691287a543f 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -305,12 +305,11 @@ static void action_header_region_draw(const bContext *C, ARegion *region)
ED_region_header(C, region);
}
-static void action_channel_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void action_channel_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
@@ -356,14 +355,13 @@ static void action_channel_region_listener(wmWindow *UNUSED(win),
}
}
-static void saction_channel_region_message_subscribe(const struct bContext *UNUSED(C),
- struct WorkSpace *UNUSED(workspace),
- struct Scene *UNUSED(scene),
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus)
+static void saction_channel_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ bScreen *screen = params->screen;
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
+
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, area->spacedata.first, &ptr);
@@ -401,12 +399,11 @@ static void saction_channel_region_message_subscribe(const struct bContext *UNUS
}
}
-static void action_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void action_main_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
@@ -460,14 +457,14 @@ static void action_main_region_listener(wmWindow *UNUSED(win),
}
}
-static void saction_main_region_message_subscribe(const struct bContext *C,
- struct WorkSpace *workspace,
- struct Scene *scene,
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus)
+static void saction_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ Scene *scene = params->scene;
+ bScreen *screen = params->screen;
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
+
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, area->spacedata.first, &ptr);
@@ -502,15 +499,14 @@ static void saction_main_region_message_subscribe(const struct bContext *C,
}
/* Now run the general "channels region" one - since channels and main should be in sync */
- saction_channel_region_message_subscribe(C, workspace, scene, screen, area, region, mbus);
+ saction_channel_region_message_subscribe(params);
}
/* editor level listener */
-static void action_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- wmNotifier *wmn,
- Scene *UNUSED(scene))
+static void action_listener(const wmSpaceTypeListenerParams *params)
{
+ ScrArea *area = params->area;
+ wmNotifier *wmn = params->notifier;
SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* context changes */
@@ -660,12 +656,11 @@ static void action_listener(wmWindow *UNUSED(win),
}
}
-static void action_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void action_header_region_listener(const wmRegionListenerParams *params)
{
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* context changes */
@@ -737,12 +732,11 @@ static void action_buttons_area_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-static void action_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void action_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 10fa2c19919..01e57eab7c2 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -70,16 +70,13 @@
#include "io_ops.h"
-/* only call once on startup, storage is global in BKE kernel listbase */
+/* Only called once on startup. storage is global in BKE kernel listbase. */
void ED_spacetypes_init(void)
{
- const ListBase *spacetypes;
- SpaceType *type;
-
- /* UI_UNIT_X is now a variable, is used in some spacetype inits? */
+ /* UI unit is a variable, may be used in some space type inits. */
U.widget_unit = 20;
- /* create space types */
+ /* Create space types. */
ED_spacetype_outliner();
ED_spacetype_view3d();
ED_spacetype_ipo();
@@ -98,9 +95,8 @@ void ED_spacetypes_init(void)
ED_spacetype_clip();
ED_spacetype_statusbar();
ED_spacetype_topbar();
- // ...
- /* register operator types for screen and all spaces */
+ /* Register operator types for screen and all spaces. */
ED_operatortypes_userpref();
ED_operatortypes_workspace();
ED_operatortypes_scene();
@@ -132,7 +128,7 @@ void ED_spacetypes_init(void)
ED_screen_user_menu_register();
- /* gizmo types */
+ /* Gizmo types. */
ED_gizmotypes_button_2d();
ED_gizmotypes_dial_3d();
ED_gizmotypes_move_3d();
@@ -144,10 +140,10 @@ void ED_spacetypes_init(void)
ED_gizmotypes_cage_3d();
ED_gizmotypes_snap_3d();
- /* register types for operators and gizmos */
- spacetypes = BKE_spacetypes_list();
- for (type = spacetypes->first; type; type = type->next) {
- /* init gizmo types first, operator-types need them */
+ /* Register types for operators and gizmos. */
+ const ListBase *spacetypes = BKE_spacetypes_list();
+ LISTBASE_FOREACH (const SpaceType *, type, spacetypes) {
+ /* Initialize gizmo types first, operator types need them. */
if (type->gizmos) {
type->gizmos();
}
@@ -159,11 +155,8 @@ void ED_spacetypes_init(void)
void ED_spacemacros_init(void)
{
- const ListBase *spacetypes;
- SpaceType *type;
-
- /* Macros's must go last since they reference other operators.
- * We need to have them go after python operators too */
+ /* Macros must go last since they reference other operators.
+ * They need to be registered after python operators too. */
ED_operatormacros_armature();
ED_operatormacros_mesh();
ED_operatormacros_uvedit();
@@ -180,24 +173,21 @@ void ED_spacemacros_init(void)
ED_operatormacros_paint();
ED_operatormacros_gpencil();
- /* register dropboxes (can use macros) */
- spacetypes = BKE_spacetypes_list();
- for (type = spacetypes->first; type; type = type->next) {
+ /* Register dropboxes (can use macros). */
+ const ListBase *spacetypes = BKE_spacetypes_list();
+ LISTBASE_FOREACH (const SpaceType *, type, spacetypes) {
if (type->dropboxes) {
type->dropboxes();
}
}
}
-/* called in wm.c */
-/* keymap definitions are registered only once per WM initialize, usually on file read,
- * using the keymap the actual areas/regions add the handlers */
+/**
+ * \note Keymap definitions are registered only once per WM initialize,
+ * usually on file read, using the keymap the actual areas/regions add the handlers.
+ * \note Called in wm.c. */
void ED_spacetypes_keymap(wmKeyConfig *keyconf)
{
- const ListBase *spacetypes;
- SpaceType *stype;
- ARegionType *atype;
-
ED_keymap_screen(keyconf);
ED_keymap_anim(keyconf);
ED_keymap_animchannels(keyconf);
@@ -219,20 +209,20 @@ void ED_spacetypes_keymap(wmKeyConfig *keyconf)
ED_keymap_transform(keyconf);
- spacetypes = BKE_spacetypes_list();
- for (stype = spacetypes->first; stype; stype = stype->next) {
- if (stype->keymap) {
- stype->keymap(keyconf);
+ const ListBase *spacetypes = BKE_spacetypes_list();
+ LISTBASE_FOREACH (const SpaceType *, type, spacetypes) {
+ if (type->keymap) {
+ type->keymap(keyconf);
}
- for (atype = stype->regiontypes.first; atype; atype = atype->next) {
- if (atype->keymap) {
- atype->keymap(keyconf);
+ LISTBASE_FOREACH (ARegionType *, region_type, &type->regiontypes) {
+ if (region_type->keymap) {
+ region_type->keymap(keyconf);
}
}
}
}
-/* ********************** custom drawcall api ***************** */
+/* ********************** Custom Draw Call API ***************** */
typedef struct RegionDrawCB {
struct RegionDrawCB *next, *prev;
@@ -261,9 +251,7 @@ void *ED_region_draw_cb_activate(ARegionType *art,
void ED_region_draw_cb_exit(ARegionType *art, void *handle)
{
- RegionDrawCB *rdc;
-
- for (rdc = art->drawcalls.first; rdc; rdc = rdc->next) {
+ LISTBASE_FOREACH (RegionDrawCB *, rdc, &art->drawcalls) {
if (rdc == (RegionDrawCB *)handle) {
BLI_remlink(&art->drawcalls, rdc);
MEM_freeN(rdc);
@@ -274,9 +262,7 @@ void ED_region_draw_cb_exit(ARegionType *art, void *handle)
void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
{
- RegionDrawCB *rdc;
-
- for (rdc = region->type->drawcalls.first; rdc; rdc = rdc->next) {
+ LISTBASE_FOREACH (RegionDrawCB *, rdc, &region->type->drawcalls) {
if (rdc->type == type) {
rdc->draw(C, region, rdc->customdata);
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index e50ca2ec92b..07bc1d42c3f 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -514,12 +514,11 @@ static void buttons_main_region_layout(const bContext *C, ARegion *region)
sbuts->mainbo = sbuts->mainb;
}
-static void buttons_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void buttons_main_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_SCREEN:
@@ -567,15 +566,13 @@ static void buttons_header_region_draw(const bContext *C, ARegion *region)
ED_region_header(C, region);
}
-static void buttons_header_region_message_subscribe(const bContext *UNUSED(C),
- WorkSpace *UNUSED(workspace),
- Scene *UNUSED(scene),
- bScreen *UNUSED(screen),
- ScrArea *area,
- ARegion *region,
- struct wmMsgBus *mbus)
+static void buttons_header_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
SpaceProperties *sbuts = area->spacedata.first;
+
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
@@ -621,14 +618,12 @@ static void buttons_navigation_bar_region_draw(const bContext *C, ARegion *regio
ED_region_panels_draw(C, region);
}
-static void buttons_navigation_bar_region_message_subscribe(const bContext *UNUSED(C),
- WorkSpace *UNUSED(workspace),
- Scene *UNUSED(scene),
- bScreen *UNUSED(screen),
- ScrArea *UNUSED(area),
- ARegion *region,
- struct wmMsgBus *mbus)
+static void buttons_navigation_bar_region_message_subscribe(
+ const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ ARegion *region = params->region;
+
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
@@ -657,11 +652,10 @@ static void buttons_area_redraw(ScrArea *area, short buttons)
* \{ */
/* reused! */
-static void buttons_area_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- wmNotifier *wmn,
- Scene *UNUSED(scene))
+static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
{
+ ScrArea *area = params->area;
+ wmNotifier *wmn = params->notifier;
SpaceProperties *sbuts = area->spacedata.first;
/* context changes */
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index bd11a746e11..af1d082d317 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -327,118 +327,18 @@ void ED_clip_update_frame(const Main *mainp, int cfra)
}
}
-static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2])
+bool ED_clip_view_selection(const bContext *C, ARegion *UNUSED(region), bool fit)
{
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTrackingTrack *track;
- int width, height;
- bool ok = false;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- INIT_MINMAX2(min, max);
-
- ED_space_clip_get_size(sc, &width, &height);
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track)) {
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- if (marker) {
- float pos[3];
-
- pos[0] = marker->pos[0] + track->offset[0];
- pos[1] = marker->pos[1] + track->offset[1];
- pos[2] = 0.0f;
-
- /* undistortion happens for normalized coords */
- if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
- /* undistortion happens for normalized coords */
- ED_clip_point_undistorted_pos(sc, pos, pos);
- }
-
- pos[0] *= width;
- pos[1] *= height;
-
- mul_v3_m4v3(pos, sc->stabmat, pos);
-
- minmax_v2v2_v2(min, max, pos);
-
- ok = true;
- }
- }
-
- track = track->next;
- }
-
- return ok;
-}
-
-static bool selected_boundbox(const bContext *C, float min[2], float max[2])
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- if (sc->mode == SC_MODE_TRACKING) {
- return selected_tracking_boundbox(sc, min, max);
- }
-
- if (ED_mask_selected_minmax(C, min, max)) {
- MovieClip *clip = ED_space_clip_get_clip(sc);
- int width, height;
- ED_space_clip_get_size(sc, &width, &height);
- BKE_mask_coord_to_movieclip(clip, &sc->user, min, min);
- BKE_mask_coord_to_movieclip(clip, &sc->user, max, max);
- min[0] *= width;
- min[1] *= height;
- max[0] *= width;
- max[1] *= height;
- return true;
- }
- return false;
-}
-
-bool ED_clip_view_selection(const bContext *C, ARegion *region, bool fit)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- int w, h, frame_width, frame_height;
- float min[2], max[2];
-
- ED_space_clip_get_size(sc, &frame_width, &frame_height);
-
- if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) {
+ float offset_x, offset_y;
+ float zoom;
+ if (!clip_view_calculate_view_selection(C, fit, &offset_x, &offset_y, &zoom)) {
return false;
}
- if (!selected_boundbox(C, min, max)) {
- return false;
- }
-
- /* center view */
- clip_view_center_to_point(
- sc, (max[0] + min[0]) / (2 * frame_width), (max[1] + min[1]) / (2 * frame_height));
-
- w = max[0] - min[0];
- h = max[1] - min[1];
-
- /* set zoom to see all selection */
- if (w > 0 && h > 0) {
- int width, height;
- float zoomx, zoomy, newzoom, aspx, aspy;
-
- ED_space_clip_get_aspect(sc, &aspx, &aspy);
-
- width = BLI_rcti_size_x(&region->winrct) + 1;
- height = BLI_rcti_size_y(&region->winrct) + 1;
-
- zoomx = (float)width / w / aspx;
- zoomy = (float)height / h / aspy;
-
- newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy));
-
- if (fit || sc->zoom > newzoom) {
- sc->zoom = newzoom;
- }
- }
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ sc->xof = offset_x;
+ sc->yof = offset_y;
+ sc->zoom = zoom;
return true;
}
@@ -1177,3 +1077,47 @@ void clip_start_prefetch_job(const bContext *C)
/* and finally start the job */
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
+
+void ED_clip_view_lock_state_store(const bContext *C, ClipViewLockState *state)
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ BLI_assert(space_clip != NULL);
+
+ state->offset_x = space_clip->xof;
+ state->offset_y = space_clip->yof;
+ state->zoom = space_clip->zoom;
+
+ state->lock_offset_x = 0.0f;
+ state->lock_offset_y = 0.0f;
+
+ if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
+ return;
+ }
+
+ if (!clip_view_calculate_view_selection(
+ C, false, &state->offset_x, &state->offset_y, &state->zoom)) {
+ return;
+ }
+
+ state->lock_offset_x = space_clip->xlockof;
+ state->lock_offset_y = space_clip->ylockof;
+}
+
+void ED_clip_view_lock_state_restore_no_jump(const bContext *C, const ClipViewLockState *state)
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ BLI_assert(space_clip != NULL);
+
+ if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
+ return;
+ }
+
+ float offset_x, offset_y;
+ float zoom;
+ if (!clip_view_calculate_view_selection(C, false, &offset_x, &offset_y, &zoom)) {
+ return;
+ }
+
+ space_clip->xlockof = state->offset_x + state->lock_offset_x - offset_x;
+ space_clip->ylockof = state->offset_y + state->lock_offset_y - offset_y;
+}
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 4848ec72f79..202dc00e365 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -171,8 +171,15 @@ void clip_delete_plane_track(struct bContext *C,
struct MovieClip *clip,
struct MovieTrackingPlaneTrack *plane_track);
+void clip_view_offset_for_center_to_point(
+ SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y);
void clip_view_center_to_point(SpaceClip *sc, float x, float y);
+bool clip_view_calculate_view_selection(
+ const struct bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom);
+
+bool clip_view_has_locked_selection(const struct bContext *C);
+
void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene);
/* tracking_ops.c */
@@ -191,6 +198,7 @@ void CLIP_OT_clear_solution(struct wmOperatorType *ot);
void CLIP_OT_clear_track_path(struct wmOperatorType *ot);
void CLIP_OT_join_tracks(struct wmOperatorType *ot);
+void CLIP_OT_average_tracks(struct wmOperatorType *ot);
void CLIP_OT_disable_markers(struct wmOperatorType *ot);
void CLIP_OT_hide_tracks(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index cd4a1ffb526..ea2dd0cb7aa 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -125,7 +125,7 @@ static void sclip_zoom_set(const bContext *C,
dx = ((location[0] - 0.5f) * w - sc->xof) * (sc->zoom - oldzoom) / sc->zoom;
dy = ((location[1] - 0.5f) * h - sc->yof) * (sc->zoom - oldzoom) / sc->zoom;
- if (sc->flag & SC_LOCK_SELECTION) {
+ if (clip_view_has_locked_selection(C)) {
sc->xlockof += dx;
sc->ylockof += dy;
}
@@ -396,7 +396,7 @@ static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
vpd->x = event->x;
vpd->y = event->y;
- if (sc->flag & SC_LOCK_SELECTION) {
+ if (clip_view_has_locked_selection(C)) {
vpd->vec = &sc->xlockof;
}
else {
@@ -434,7 +434,7 @@ static int view_pan_exec(bContext *C, wmOperator *op)
RNA_float_get_array(op->ptr, "offset", offset);
- if (sc->flag & SC_LOCK_SELECTION) {
+ if (clip_view_has_locked_selection(C)) {
sc->xlockof += offset[0];
sc->ylockof += offset[1];
}
@@ -1840,8 +1840,16 @@ void CLIP_OT_cursor_set(wmOperatorType *ot)
static int lock_selection_togglee_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceClip *space_clip = CTX_wm_space_clip(C);
+
+ ClipViewLockState lock_state;
+ ED_clip_view_lock_state_store(C, &lock_state);
+
space_clip->flag ^= SC_LOCK_SELECTION;
+
+ ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
+
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index c7f2a027ba8..271ec219809 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -27,10 +27,12 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_rect.h"
#include "BLI_utildefines.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
+#include "BKE_mask.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
@@ -44,6 +46,7 @@
#include "WM_types.h"
#include "ED_clip.h"
+#include "ED_mask.h"
#include "ED_screen.h"
#include "UI_interface.h"
@@ -395,16 +398,231 @@ void clip_delete_plane_track(bContext *C, MovieClip *clip, MovieTrackingPlaneTra
DEG_id_tag_update(&clip->id, 0);
}
-void clip_view_center_to_point(SpaceClip *sc, float x, float y)
+/* Calculate space clip offset to be centered at the given point. */
+void clip_view_offset_for_center_to_point(
+ SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y)
{
int width, height;
+ ED_space_clip_get_size(sc, &width, &height);
+
float aspx, aspy;
+ ED_space_clip_get_aspect(sc, &aspx, &aspy);
+
+ *r_offset_x = (x - 0.5f) * width * aspx;
+ *r_offset_y = (y - 0.5f) * height * aspy;
+}
+
+void clip_view_center_to_point(SpaceClip *sc, float x, float y)
+{
+ clip_view_offset_for_center_to_point(sc, x, y, &sc->xof, &sc->yof);
+}
+
+static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2])
+{
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTrackingTrack *track;
+ int width, height;
+ bool ok = false;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ INIT_MINMAX2(min, max);
ED_space_clip_get_size(sc, &width, &height);
- ED_space_clip_get_aspect(sc, &aspx, &aspy);
- sc->xof = (x - 0.5f) * width * aspx;
- sc->yof = (y - 0.5f) * height * aspy;
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track)) {
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+
+ if (marker) {
+ float pos[3];
+
+ pos[0] = marker->pos[0] + track->offset[0];
+ pos[1] = marker->pos[1] + track->offset[1];
+ pos[2] = 0.0f;
+
+ /* undistortion happens for normalized coords */
+ if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
+ /* undistortion happens for normalized coords */
+ ED_clip_point_undistorted_pos(sc, pos, pos);
+ }
+
+ pos[0] *= width;
+ pos[1] *= height;
+
+ mul_v3_m4v3(pos, sc->stabmat, pos);
+
+ minmax_v2v2_v2(min, max, pos);
+
+ ok = true;
+ }
+ }
+
+ track = track->next;
+ }
+
+ return ok;
+}
+
+static bool tracking_has_selection(SpaceClip *space_clip)
+{
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ const int framenr = ED_space_clip_get_clip_frame_number(space_clip);
+
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
+ if (!TRACK_VIEW_SELECTED(space_clip, track)) {
+ continue;
+ }
+ const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+ if (marker != NULL) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool mask_has_selection(const bContext *C, bool include_handles)
+{
+ Mask *mask = CTX_data_edit_mask(C);
+ if (mask == NULL) {
+ return false;
+ }
+
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ continue;
+ }
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
+ for (int i = 0; i < spline->tot_point; i++) {
+ const MaskSplinePoint *point = &spline->points[i];
+ const BezTriple *bezt = &point->bezt;
+ if (!MASKPOINT_ISSEL_ANY(point)) {
+ continue;
+ }
+ if (bezt->f2 & SELECT) {
+ return true;
+ }
+
+ if (!include_handles) {
+ /* Ignore handles. */
+ }
+ else if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+ return true;
+ }
+ else {
+ if ((bezt->f1 & SELECT) && (bezt->h1 != HD_VECT)) {
+ return true;
+ }
+ if ((bezt->f3 & SELECT) && (bezt->h2 != HD_VECT)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool selected_boundbox(const bContext *C, float min[2], float max[2], bool include_handles)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ if (sc->mode == SC_MODE_TRACKING) {
+ return selected_tracking_boundbox(sc, min, max);
+ }
+
+ if (ED_mask_selected_minmax(C, min, max, include_handles)) {
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ int width, height;
+ ED_space_clip_get_size(sc, &width, &height);
+ BKE_mask_coord_to_movieclip(clip, &sc->user, min, min);
+ BKE_mask_coord_to_movieclip(clip, &sc->user, max, max);
+ min[0] *= width;
+ min[1] *= height;
+ max[0] *= width;
+ max[1] *= height;
+ return true;
+ }
+ return false;
+}
+
+bool clip_view_calculate_view_selection(
+ const bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+
+ int frame_width, frame_height;
+ ED_space_clip_get_size(sc, &frame_width, &frame_height);
+
+ if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) {
+ return false;
+ }
+
+ /* NOTE: The `fit` argument is set to truth when doing "View to Selected" operator, and it set to
+ * false when this function is used for Lock-to-Selection functionality. When locking to
+ * selection the handles are to be ignored. So we can derive the `include_handles` from `fit`.
+ *
+ * TODO(sergey): Make such decision more explicit. Maybe pass use-case for the calculation to
+ * tell operator from lock-to-selection apart. */
+ float min[2], max[2];
+ if (!selected_boundbox(C, min, max, fit)) {
+ return false;
+ }
+
+ /* center view */
+ clip_view_offset_for_center_to_point(sc,
+ (max[0] + min[0]) / (2 * frame_width),
+ (max[1] + min[1]) / (2 * frame_height),
+ r_offset_x,
+ r_offset_y);
+
+ const int w = max[0] - min[0];
+ const int h = max[1] - min[1];
+
+ /* set zoom to see all selection */
+ *r_zoom = sc->zoom;
+ if (w > 0 && h > 0) {
+ ARegion *region = CTX_wm_region(C);
+
+ int width, height;
+ float zoomx, zoomy, newzoom, aspx, aspy;
+
+ ED_space_clip_get_aspect(sc, &aspx, &aspy);
+
+ width = BLI_rcti_size_x(&region->winrct) + 1;
+ height = BLI_rcti_size_y(&region->winrct) + 1;
+
+ zoomx = (float)width / w / aspx;
+ zoomy = (float)height / h / aspy;
+
+ newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy));
+
+ if (fit) {
+ *r_zoom = newzoom;
+ }
+ }
+
+ return true;
+}
+
+/* Returns truth if lock-to-selection is enabled and possible.
+ * Locking to selection is not possible if there is no selection. */
+bool clip_view_has_locked_selection(const bContext *C)
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+
+ if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
+ return false;
+ }
+
+ if (space_clip->mode == SC_MODE_TRACKING) {
+ return tracking_has_selection(space_clip);
+ }
+
+ return mask_has_selection(C, false);
}
void clip_draw_sfra_efra(View2D *v2d, Scene *scene)
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 3bdf016b64c..33783f19a79 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -229,7 +229,7 @@ static void clip_scopes_check_gpencil_change(ScrArea *area)
}
}
-static void clip_area_sync_frame_from_scene(ScrArea *area, Scene *scene)
+static void clip_area_sync_frame_from_scene(ScrArea *area, const Scene *scene)
{
SpaceClip *space_clip = (SpaceClip *)area->spacedata.first;
BKE_movieclip_user_set_frame(&space_clip->user, scene->r.cfra);
@@ -334,8 +334,12 @@ static SpaceLink *clip_duplicate(SpaceLink *sl)
return (SpaceLink *)scn;
}
-static void clip_listener(wmWindow *UNUSED(win), ScrArea *area, wmNotifier *wmn, Scene *scene)
+static void clip_listener(const wmSpaceTypeListenerParams *params)
{
+ ScrArea *area = params->area;
+ wmNotifier *wmn = params->notifier;
+ const Scene *scene = params->scene;
+
/* context changes */
switch (wmn->category) {
case NC_SCENE:
@@ -514,6 +518,7 @@ static void clip_operatortypes(void)
/* clean-up */
WM_operatortype_append(CLIP_OT_clear_track_path);
WM_operatortype_append(CLIP_OT_join_tracks);
+ WM_operatortype_append(CLIP_OT_average_tracks);
WM_operatortype_append(CLIP_OT_track_copy_color);
WM_operatortype_append(CLIP_OT_clean_tracks);
@@ -988,7 +993,14 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
}
/* callback */
+ /* TODO(sergey): For being consistent with space image the projection needs to be configured
+ * the way how the commented out code does it. This works correct for tracking data, but it
+ * causes wrong aspect correction for mask editor (see T84990). */
+ // GPU_matrix_push_projection();
+ // wmOrtho2(region->v2d.cur.xmin, region->v2d.cur.xmax, region->v2d.cur.ymin,
+ // region->v2d.cur.ymax);
ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
+ // GPU_matrix_pop_projection();
/* reset view matrix */
UI_view2d_view_restore(C);
@@ -1001,12 +1013,11 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
WM_gizmomap_draw(region->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
}
-static void clip_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void clip_main_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
@@ -1137,11 +1148,7 @@ static void clip_preview_region_draw(const bContext *C, ARegion *region)
}
}
-static void clip_preview_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *UNUSED(region),
- wmNotifier *UNUSED(wmn),
- const Scene *UNUSED(scene))
+static void clip_preview_region_listener(const wmRegionListenerParams *UNUSED(params))
{
}
@@ -1182,11 +1189,7 @@ static void clip_channels_region_draw(const bContext *C, ARegion *region)
UI_view2d_view_restore(C);
}
-static void clip_channels_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *UNUSED(region),
- wmNotifier *UNUSED(wmn),
- const Scene *UNUSED(scene))
+static void clip_channels_region_listener(const wmRegionListenerParams *UNUSED(params))
{
}
@@ -1203,12 +1206,11 @@ static void clip_header_region_draw(const bContext *C, ARegion *region)
ED_region_header(C, region);
}
-static void clip_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void clip_header_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_SCENE:
@@ -1246,12 +1248,11 @@ static void clip_tools_region_draw(const bContext *C, ARegion *region)
/****************** tool properties region ******************/
-static void clip_props_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void clip_props_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_WM:
@@ -1299,12 +1300,11 @@ static void clip_properties_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-static void clip_properties_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void clip_properties_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 49313005c43..a903aeed380 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -88,17 +88,16 @@ static int add_marker_exec(bContext *C, wmOperator *op)
MovieClip *clip = ED_space_clip_get_clip(sc);
float pos[2];
+ ClipViewLockState lock_state;
+ ED_clip_view_lock_state_store(C, &lock_state);
+
RNA_float_get_array(op->ptr, "location", pos);
if (!add_marker(C, pos[0], pos[1])) {
return OPERATOR_CANCELLED;
}
- /* Reset offset from locked position, so frame jumping wouldn't be so
- * confusing.
- */
- sc->xlockof = 0;
- sc->ylockof = 0;
+ ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
@@ -244,8 +243,6 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
changed = true;
}
}
- /* Nothing selected now, unlock view so it can be scrolled nice again. */
- sc->flag &= ~SC_LOCK_SELECTION;
if (changed) {
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
}
@@ -314,11 +311,6 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- if (!has_selection) {
- /* Nothing selected now, unlock view so it can be scrolled nice again. */
- sc->flag &= ~SC_LOCK_SELECTION;
- }
-
if (!changed) {
return OPERATOR_CANCELLED;
}
@@ -1225,13 +1217,6 @@ static int hide_tracks_exec(bContext *C, wmOperator *op)
clip->tracking.act_plane_track = NULL;
}
- if (unselected == 0) {
- /* No selection on screen now, unlock view so it can be
- * scrolled nice again.
- */
- sc->flag &= ~SC_LOCK_SELECTION;
- }
-
BKE_tracking_dopesheet_tag_update(tracking);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, NULL);
@@ -1490,6 +1475,97 @@ void CLIP_OT_join_tracks(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/********************** Average tracks operator *********************/
+
+static int average_tracks_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ MovieTracking *tracking = &clip->tracking;
+
+ /* Collect source tracks. */
+ int num_source_tracks;
+ MovieTrackingTrack **source_tracks = BKE_tracking_selected_tracks_in_active_object(
+ tracking, &num_source_tracks);
+ if (num_source_tracks == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Create new empty track, which will be the averaged result.
+ * Makes it simple to average all selection to it. */
+ ListBase *tracks_list = BKE_tracking_get_active_tracks(tracking);
+ MovieTrackingTrack *result_track = BKE_tracking_track_add_empty(tracking, tracks_list);
+
+ /* Perform averaging. */
+ BKE_tracking_tracks_average(result_track, source_tracks, num_source_tracks);
+
+ const bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
+ if (!keep_original) {
+ for (int i = 0; i < num_source_tracks; i++) {
+ clip_delete_track(C, clip, source_tracks[i]);
+ }
+ }
+
+ /* Update selection, making the result track active and selected. */
+ /* TODO(sergey): Should become some sort of utility function available for all operators. */
+
+ BKE_tracking_track_select(tracks_list, result_track, TRACK_AREA_ALL, 0);
+ ListBase *plane_tracks_list = BKE_tracking_get_active_plane_tracks(tracking);
+ BKE_tracking_plane_tracks_deselect_all(plane_tracks_list);
+
+ clip->tracking.act_track = result_track;
+ clip->tracking.act_plane_track = NULL;
+
+ /* Inform the dependency graph and interface about changes. */
+ DEG_id_tag_update(&clip->id, 0);
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+
+ /* Free memory. */
+ MEM_freeN(source_tracks);
+
+ return OPERATOR_FINISHED;
+}
+
+static int average_tracks_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ PropertyRNA *prop_keep_original = RNA_struct_find_property(op->ptr, "keep_original");
+ if (!RNA_property_is_set(op->ptr, prop_keep_original)) {
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ MovieTracking *tracking = &clip->tracking;
+
+ const int num_selected_tracks = BKE_tracking_count_selected_tracks_in_active_object(tracking);
+
+ if (num_selected_tracks == 1) {
+ RNA_property_boolean_set(op->ptr, prop_keep_original, false);
+ }
+ }
+
+ return average_tracks_exec(C, op);
+}
+
+void CLIP_OT_average_tracks(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Average Tracks";
+ ot->description = "Average selected tracks into active";
+ ot->idname = "CLIP_OT_average_tracks";
+
+ /* API callbacks. */
+ ot->exec = average_tracks_exec;
+ ot->invoke = average_tracks_invoke;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Properties. */
+ PropertyRNA *prop;
+
+ prop = RNA_def_boolean(ot->srna, "keep_original", 1, "Keep Original", "Keep original tracks");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
/********************** lock tracks operator *********************/
enum {
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 063ea9592aa..558c0bec11d 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -304,6 +304,9 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const
track = find_nearest_track(sc, tracksbase, co, &distance_to_track);
plane_track = find_nearest_plane_track(sc, plane_tracks_base, co, &distance_to_plane_track);
+ ClipViewLockState lock_state;
+ ED_clip_view_lock_state_store(C, &lock_state);
+
/* Do not select beyond some reasonable distance, that is useless and
* prevents the 'deselect on nothing' behavior. */
if (distance_to_track > 0.05f) {
@@ -377,10 +380,7 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const
ED_mask_deselect_all(C);
}
- if (!extend) {
- sc->xlockof = 0.0f;
- sc->ylockof = 0.0f;
- }
+ ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
BKE_tracking_dopesheet_tag_update(tracking);
@@ -867,14 +867,16 @@ static int select_all_exec(bContext *C, wmOperator *op)
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
- int action = RNA_enum_get(op->ptr, "action");
+ const int action = RNA_enum_get(op->ptr, "action");
- bool has_selection = false;
+ ClipViewLockState lock_state;
+ ED_clip_view_lock_state_store(C, &lock_state);
+ bool has_selection = false;
ED_clip_select_all(sc, action, &has_selection);
- if (!has_selection) {
- sc->flag &= ~SC_LOCK_SELECTION;
+ if (has_selection) {
+ ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
}
BKE_tracking_dopesheet_tag_update(tracking);
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 9b8e9e0e871..6265cbdd920 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -273,13 +273,11 @@ static void console_header_region_draw(const bContext *C, ARegion *region)
ED_region_header(C, region);
}
-static void console_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void console_main_region_listener(const wmRegionListenerParams *params)
{
- // SpaceInfo *sinfo = area->spacedata.first;
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 8e9093151ba..a12c9633798 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -131,7 +131,15 @@ static void draw_tile(int sx, int sy, int width, int height, int colorid, int sh
UI_GetThemeColorShade4fv(colorid, shade, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_aa(
- true, (float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f, color);
+ &(const rctf){
+ .xmin = (float)sx,
+ .xmax = (float)(sx + width),
+ .ymin = (float)(sy - height),
+ .ymax = (float)sy,
+ },
+ true,
+ 5.0f,
+ color);
}
static void file_draw_icon(uiBlock *block,
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index d66219c7549..33c37875372 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -276,6 +276,7 @@ typedef struct FileListInternEntry {
char *redirection_path;
/** not strictly needed, but used during sorting, avoids to have to recompute it there... */
char *name;
+ bool free_name;
/**
* This is data from the current main, represented by this file. It's crucial that this is
@@ -1366,7 +1367,7 @@ static bool filelist_checkdir_main_assets(struct FileList *UNUSED(filelist),
static void filelist_entry_clear(FileDirEntry *entry)
{
- if (entry->name) {
+ if (entry->name && ((entry->flags & FILE_ENTRY_NAME_FREE) != 0)) {
MEM_freeN(entry->name);
}
if (entry->description) {
@@ -1451,7 +1452,7 @@ static void filelist_intern_entry_free(FileListInternEntry *entry)
if (entry->redirection_path) {
MEM_freeN(entry->redirection_path);
}
- if (entry->name) {
+ if (entry->name && entry->free_name) {
MEM_freeN(entry->name);
}
/* If we own the asset-data (it was generated from external file data), free it. */
@@ -1953,7 +1954,13 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in
ret->entry = rev;
ret->relpath = BLI_strdup(entry->relpath);
- ret->name = BLI_strdup(entry->name);
+ if (entry->free_name) {
+ ret->name = BLI_strdup(entry->name);
+ ret->flags |= FILE_ENTRY_NAME_FREE;
+ }
+ else {
+ ret->name = entry->name;
+ }
ret->description = BLI_strdupcat(filelist->filelist.root, entry->relpath);
memcpy(ret->uuid, entry->uuid, sizeof(ret->uuid));
ret->blentype = entry->blentype;
@@ -3175,6 +3182,7 @@ static void filelist_readjob_do(const bool do_lib,
entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//'
* added by BLI_path_rel to rel_subdir. */
entry->name = BLI_strdup(fileentry_uiname(root, entry->relpath, entry->typeflag, dir));
+ entry->free_name = true;
/* Here we decide whether current filedirentry is to be listed too, or not. */
if (max_recursion && (is_lib || (recursion_level <= max_recursion))) {
@@ -3288,7 +3296,8 @@ static void filelist_readjob_main_assets(Main *current_main,
entry = MEM_callocN(sizeof(*entry), __func__);
entry->relpath = BLI_strdup(id_code_name);
- entry->name = BLI_strdup(id_iter->name + 2);
+ entry->name = id_iter->name + 2;
+ entry->free_name = false;
entry->typeflag |= FILE_TYPE_BLENDERLIB | FILE_TYPE_ASSET;
entry->blentype = GS(id_iter->name);
*((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32(
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 7f33b0212d6..d4cd888c662 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -104,6 +104,7 @@ static ARegion *file_tool_props_region_ensure(ScrArea *area, ARegion *region_pre
BLI_insertlinkafter(&area->regionbase, region_prev, region);
region->regiontype = RGN_TYPE_TOOL_PROPS;
region->alignment = RGN_ALIGN_RIGHT;
+ region->flag = RGN_FLAG_HIDDEN;
return region;
}
@@ -246,13 +247,13 @@ static void file_ensure_valid_region_state(bContext *C,
BLI_assert(region_tools);
if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) {
- ARegion *region_execute = file_execute_region_ensure(area, region_tools);
- ARegion *region_props = file_tool_props_region_ensure(area, region_execute);
-
- /* Hide specific regions by default. */
- region_props->flag |= RGN_FLAG_HIDDEN;
- region_execute->flag |= RGN_FLAG_HIDDEN;
+ file_tool_props_region_ensure(area, region_tools);
+ ARegion *region_execute = BKE_area_find_region_type(area, RGN_TYPE_EXECUTE);
+ if (region_execute) {
+ ED_region_remove(C, area, region_execute);
+ needs_init = true;
+ }
ARegion *region_ui = BKE_area_find_region_type(area, RGN_TYPE_UI);
if (region_ui) {
ED_region_remove(C, area, region_ui);
@@ -281,11 +282,12 @@ static void file_ensure_valid_region_state(bContext *C,
ARegion *region_ui = file_ui_region_ensure(area, region_tools);
UNUSED_VARS(region_ui);
+ if (region_execute) {
+ ED_region_remove(C, area, region_execute);
+ needs_init = true;
+ }
if (region_props) {
- BLI_assert(region_execute);
-
ED_region_remove(C, area, region_props);
- ED_region_remove(C, area, region_execute);
needs_init = true;
}
}
@@ -390,11 +392,10 @@ static void file_refresh(const bContext *C, ScrArea *area)
ED_area_tag_redraw(area);
}
-static void file_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- wmNotifier *wmn,
- Scene *UNUSED(scene))
+static void file_listener(const wmSpaceTypeListenerParams *params)
{
+ ScrArea *area = params->area;
+ wmNotifier *wmn = params->notifier;
SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
/* context changes */
@@ -445,12 +446,11 @@ static void file_main_region_init(wmWindowManager *wm, ARegion *region)
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
}
-static void file_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void file_main_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_SPACE:
@@ -463,19 +463,24 @@ static void file_main_region_listener(wmWindow *UNUSED(win),
break;
}
break;
+ case NC_ID:
+ if (ELEM(wmn->action, NA_RENAME)) {
+ /* In case the filelist shows ID names. */
+ ED_region_tag_redraw(region);
+ }
+ break;
}
}
-static void file_main_region_message_subscribe(const struct bContext *UNUSED(C),
- struct WorkSpace *UNUSED(workspace),
- struct Scene *UNUSED(scene),
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus)
+static void file_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ bScreen *screen = params->screen;
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
SpaceFile *sfile = area->spacedata.first;
- FileSelectParams *params = ED_fileselect_ensure_active_params(sfile);
+
+ FileSelectParams *file_params = ED_fileselect_ensure_active_params(sfile);
/* This is a bit odd that a region owns the subscriber for an area,
* keep for now since all subscribers for WM are regions.
* May be worth re-visiting later. */
@@ -497,7 +502,7 @@ static void file_main_region_message_subscribe(const struct bContext *UNUSED(C),
/* FileSelectParams */
{
PointerRNA ptr;
- RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_FileSelectParams, file_params, &ptr);
/* All properties for this space type. */
WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__);
@@ -647,18 +652,23 @@ static void file_tools_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-static void file_tools_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *UNUSED(region),
- wmNotifier *UNUSED(wmn),
- const Scene *UNUSED(scene))
+static void file_tools_region_listener(const wmRegionListenerParams *UNUSED(params))
{
-#if 0
- /* context changes */
+}
+
+static void file_tool_props_region_listener(const wmRegionListenerParams *params)
+{
+ const wmNotifier *wmn = params->notifier;
+ ARegion *region = params->region;
+
switch (wmn->category) {
- /* pass */
+ case NC_ID:
+ if (ELEM(wmn->action, NA_RENAME)) {
+ /* In case the filelist shows ID names. */
+ ED_region_tag_redraw(region);
+ }
+ break;
}
-#endif
}
/* add handlers, stuff you only do once or on area/region changes */
@@ -715,12 +725,11 @@ static void file_execution_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-static void file_ui_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void file_ui_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_SPACE:
@@ -928,7 +937,7 @@ void ED_spacetype_file(void)
art->prefsizex = 240;
art->prefsizey = 60;
art->keymapflag = ED_KEYMAP_UI;
- art->listener = file_tools_region_listener;
+ art->listener = file_tool_props_region_listener;
art->init = file_tools_region_init;
art->draw = file_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 4cda6b34a01..0818ebe9c0a 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -505,15 +505,15 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
"Mode",
"Which mode to use for decimation");
- RNA_def_float_percentage(ot->srna,
- "remove_ratio",
- 1.0f / 3.0f,
- 0.0f,
- 1.0f,
- "Remove",
- "The percentage of keyframes to remove",
- 0.0f,
- 1.0f);
+ RNA_def_float_factor(ot->srna,
+ "remove_ratio",
+ 1.0f / 3.0f,
+ 0.0f,
+ 1.0f,
+ "Remove",
+ "The ratio of remaining keyframes after the operation",
+ 0.0f,
+ 1.0f);
RNA_def_float(ot->srna,
"remove_error_margin",
0.0f,
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 791039498e8..9f01773eadf 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -403,12 +403,11 @@ static void graph_buttons_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-static void graph_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void graph_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
@@ -470,14 +469,14 @@ static void graph_region_listener(wmWindow *UNUSED(win),
}
}
-static void graph_region_message_subscribe(const struct bContext *UNUSED(C),
- struct WorkSpace *UNUSED(workspace),
- struct Scene *scene,
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus)
+static void graph_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ Scene *scene = params->scene;
+ bScreen *screen = params->screen;
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
+
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, area->spacedata.first, &ptr);
@@ -546,11 +545,10 @@ static void graph_region_message_subscribe(const struct bContext *UNUSED(C),
}
/* editor level listener */
-static void graph_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- wmNotifier *wmn,
- Scene *UNUSED(scene))
+static void graph_listener(const wmSpaceTypeListenerParams *params)
{
+ ScrArea *area = params->area;
+ wmNotifier *wmn = params->notifier;
SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
/* context changes */
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 86e52814d6f..097e304c893 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -900,7 +900,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
}
}
else if (ED_space_image_check_show_maskedit(sima, obedit)) {
- if (!ED_mask_selected_minmax(C, min, max)) {
+ if (!ED_mask_selected_minmax(C, min, max, true)) {
return OPERATOR_CANCELLED;
}
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 776fa34d1c4..b0571d47736 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -320,8 +320,11 @@ static void image_refresh(const bContext *C, ScrArea *area)
}
}
-static void image_listener(wmWindow *win, ScrArea *area, wmNotifier *wmn, Scene *UNUSED(scene))
+static void image_listener(const wmSpaceTypeListenerParams *params)
{
+ wmWindow *win = params->window;
+ ScrArea *area = params->area;
+ wmNotifier *wmn = params->notifier;
SpaceImage *sima = (SpaceImage *)area->spacedata.first;
/* context changes */
@@ -728,12 +731,12 @@ static void image_main_region_draw(const bContext *C, ARegion *region)
draw_image_cache(C, region);
}
-static void image_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void image_main_region_listener(const wmRegionListenerParams *params)
{
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_GEOM:
@@ -843,12 +846,11 @@ static void image_buttons_region_draw(const bContext *C, ARegion *region)
ED_region_panels_draw(C, region);
}
-static void image_buttons_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void image_buttons_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_TEXTURE:
@@ -906,12 +908,11 @@ static void image_tools_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-static void image_tools_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void image_tools_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
@@ -963,12 +964,11 @@ static void image_header_region_draw(const bContext *C, ARegion *region)
ED_region_header(C, region);
}
-static void image_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void image_header_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_SCENE:
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index 8d3f21aefeb..5e44db4c791 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -204,13 +204,10 @@ static void info_header_region_draw(const bContext *C, ARegion *region)
ED_region_header(C, region);
}
-static void info_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void info_main_region_listener(const wmRegionListenerParams *params)
{
- // SpaceInfo *sinfo = area->spacedata.first;
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -223,12 +220,11 @@ static void info_main_region_listener(wmWindow *UNUSED(win),
}
}
-static void info_header_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void info_header_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_SCREEN:
@@ -259,14 +255,11 @@ static void info_header_listener(wmWindow *UNUSED(win),
}
}
-static void info_header_region_message_subscribe(const bContext *UNUSED(C),
- WorkSpace *UNUSED(workspace),
- Scene *UNUSED(scene),
- bScreen *UNUSED(screen),
- ScrArea *UNUSED(area),
- ARegion *region,
- struct wmMsgBus *mbus)
+static void info_header_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ ARegion *region = params->region;
+
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index a489216afd1..ef5d9c0aab0 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -225,13 +225,16 @@ static bool textview_draw_string(TextViewDrawState *tds,
rgba_uchar_to_float(col, icon_bg);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(true,
- hpadding,
- line_top - bg_size - vpadding,
- bg_size + hpadding,
- line_top - vpadding,
- 4 * UI_DPI_FAC,
- col);
+ UI_draw_roundbox_aa(
+ &(const rctf){
+ .xmin = hpadding,
+ .xmax = bg_size + hpadding,
+ .ymin = line_top - bg_size - vpadding,
+ .ymax = line_top - vpadding,
+ },
+ true,
+ 4 * UI_DPI_FAC,
+ col);
}
if (icon) {
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 6fe980cf657..eea81e425c2 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -493,7 +493,18 @@ static void nla_draw_strip(SpaceNla *snla,
/* strip is in normal track */
UI_draw_roundbox_corner_set(UI_CNR_ALL); /* all corners rounded */
- UI_draw_roundbox_shade_x(true, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1, color);
+ UI_draw_roundbox_shade_x(
+ &(const rctf){
+ .xmin = strip->start,
+ .xmax = strip->end,
+ .ymin = yminc,
+ .ymax = ymaxc,
+ },
+ true,
+ 0.0,
+ 0.5,
+ 0.1,
+ color);
/* restore current vertex format & program (roundbox trashes it) */
shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -547,7 +558,18 @@ static void nla_draw_strip(SpaceNla *snla,
}
else {
/* non-muted - draw solid, rounded outline */
- UI_draw_roundbox_shade_x(false, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1, color);
+ UI_draw_roundbox_shade_x(
+ &(const rctf){
+ .xmin = strip->start,
+ .xmax = strip->end,
+ .ymin = yminc,
+ .ymax = ymaxc,
+ },
+ false,
+ 0.0,
+ 0.0,
+ 0.1,
+ color);
/* restore current vertex format & program (roundbox trashes it) */
shdr_pos = nla_draw_use_dashed_outlines(color, muted);
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index c6fe1b8539e..efe851c64ed 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -324,12 +324,11 @@ static void nla_buttons_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-static void nla_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void nla_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
@@ -364,12 +363,11 @@ static void nla_region_listener(wmWindow *UNUSED(win),
}
}
-static void nla_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void nla_main_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
@@ -423,14 +421,14 @@ static void nla_main_region_listener(wmWindow *UNUSED(win),
}
}
-static void nla_main_region_message_subscribe(const struct bContext *UNUSED(C),
- struct WorkSpace *UNUSED(workspace),
- struct Scene *scene,
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus)
+static void nla_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ Scene *scene = params->scene;
+ bScreen *screen = params->screen;
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
+
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_SpaceNLA, area->spacedata.first, &ptr);
@@ -465,12 +463,11 @@ static void nla_main_region_message_subscribe(const struct bContext *UNUSED(C),
}
}
-static void nla_channel_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void nla_channel_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
@@ -508,14 +505,13 @@ static void nla_channel_region_listener(wmWindow *UNUSED(win),
}
}
-static void nla_channel_region_message_subscribe(const struct bContext *UNUSED(C),
- struct WorkSpace *UNUSED(workspace),
- struct Scene *UNUSED(scene),
- struct bScreen *screen,
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus)
+static void nla_channel_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ bScreen *screen = params->screen;
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
+
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_SpaceNLA, area->spacedata.first, &ptr);
@@ -543,11 +539,11 @@ static void nla_channel_region_message_subscribe(const struct bContext *UNUSED(C
}
/* editor level listener */
-static void nla_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- wmNotifier *wmn,
- Scene *UNUSED(scene))
+static void nla_listener(const wmSpaceTypeListenerParams *params)
{
+ ScrArea *area = params->area;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index f2ee94af9b3..7905483fac9 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -441,7 +441,7 @@ static void node_draw_frame(const bContext *C,
const rctf *rct = &node->totr;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
+ UI_draw_roundbox_aa(rct, true, BASIS_RAD, color);
/* outline active and selected emphasis */
if (node->flag & SELECT) {
@@ -452,11 +452,11 @@ static void node_draw_frame(const bContext *C,
UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color);
}
- UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
+ UI_draw_roundbox_aa(rct, false, BASIS_RAD, color);
}
/* label */
- node_draw_frame_label(ntree, node, snode->aspect);
+ node_draw_frame_label(ntree, node, snode->runtime->aspect);
UI_block_end(C, node->block);
UI_block_draw(C, node->block);
@@ -3166,13 +3166,80 @@ static void node_geometry_buts_random_attribute(uiLayout *layout,
uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
}
+static bool node_attribute_math_operation_use_input_b(const NodeMathOperation operation)
+{
+ switch (operation) {
+ case NODE_MATH_ADD:
+ case NODE_MATH_SUBTRACT:
+ case NODE_MATH_MULTIPLY:
+ case NODE_MATH_DIVIDE:
+ case NODE_MATH_POWER:
+ case NODE_MATH_LOGARITHM:
+ case NODE_MATH_MINIMUM:
+ case NODE_MATH_MAXIMUM:
+ case NODE_MATH_LESS_THAN:
+ case NODE_MATH_GREATER_THAN:
+ case NODE_MATH_MODULO:
+ case NODE_MATH_ARCTAN2:
+ case NODE_MATH_SNAP:
+ case NODE_MATH_WRAP:
+ case NODE_MATH_COMPARE:
+ case NODE_MATH_MULTIPLY_ADD:
+ case NODE_MATH_PINGPONG:
+ case NODE_MATH_SMOOTH_MIN:
+ case NODE_MATH_SMOOTH_MAX:
+ return true;
+ case NODE_MATH_SINE:
+ case NODE_MATH_COSINE:
+ case NODE_MATH_TANGENT:
+ case NODE_MATH_ARCSINE:
+ case NODE_MATH_ARCCOSINE:
+ case NODE_MATH_ARCTANGENT:
+ case NODE_MATH_ROUND:
+ case NODE_MATH_ABSOLUTE:
+ case NODE_MATH_FLOOR:
+ case NODE_MATH_CEIL:
+ case NODE_MATH_FRACTION:
+ case NODE_MATH_SQRT:
+ case NODE_MATH_INV_SQRT:
+ case NODE_MATH_SIGN:
+ case NODE_MATH_EXPONENT:
+ case NODE_MATH_RADIANS:
+ case NODE_MATH_DEGREES:
+ case NODE_MATH_SINH:
+ case NODE_MATH_COSH:
+ case NODE_MATH_TANH:
+ case NODE_MATH_TRUNC:
+ return false;
+ }
+ BLI_assert(false);
+ return false;
+}
+
static void node_geometry_buts_attribute_math(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
+ bNode *node = (bNode *)ptr->data;
+ NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage;
+ NodeMathOperation operation = (NodeMathOperation)node_storage->operation;
+
uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
uiItemR(layout, ptr, "input_type_a", DEFAULT_FLAGS, IFACE_("Type A"), ICON_NONE);
- uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE);
+
+ /* These "use input b / c" checks are copied from the node's code.
+ * They could be de-duplicated if the drawing code was moved to the node's file. */
+ if (node_attribute_math_operation_use_input_b(operation)) {
+ uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE);
+ }
+ if (ELEM(operation,
+ NODE_MATH_MULTIPLY_ADD,
+ NODE_MATH_SMOOTH_MIN,
+ NODE_MATH_SMOOTH_MAX,
+ NODE_MATH_WRAP,
+ NODE_MATH_COMPARE)) {
+ uiItemR(layout, ptr, "input_type_c", DEFAULT_FLAGS, IFACE_("Type C"), ICON_NONE);
+ }
}
static void node_geometry_buts_attribute_vector_math(uiLayout *layout,
@@ -3290,6 +3357,23 @@ static void node_geometry_buts_object_info(uiLayout *layout, bContext *UNUSED(C)
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
+static void node_geometry_buts_attribute_sample_texture(uiLayout *layout,
+ bContext *C,
+ PointerRNA *ptr)
+{
+ uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL);
+}
+
+static void node_geometry_buts_points_to_volume(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "resolution_mode", DEFAULT_FLAGS, IFACE_("Resolution"), ICON_NONE);
+ uiItemR(layout, ptr, "input_type_radius", DEFAULT_FLAGS, IFACE_("Radius"), ICON_NONE);
+}
+
static void node_geometry_set_butfunc(bNodeType *ntype)
{
switch (ntype->type) {
@@ -3344,6 +3428,12 @@ static void node_geometry_set_butfunc(bNodeType *ntype)
case GEO_NODE_OBJECT_INFO:
ntype->draw_buttons = node_geometry_buts_object_info;
break;
+ case GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE:
+ ntype->draw_buttons = node_geometry_buts_attribute_sample_texture;
+ break;
+ case GEO_NODE_POINTS_TO_VOLUME:
+ ntype->draw_buttons = node_geometry_buts_points_to_volume;
+ break;
}
}
@@ -3828,18 +3918,18 @@ void draw_nodespace_back_pix(const bContext *C,
}
/* return quadratic beziers points for a given nodelink and clip if v2d is not NULL. */
-static bool node_link_bezier_handles(View2D *v2d,
- SpaceNode *snode,
- bNodeLink *link,
+static bool node_link_bezier_handles(const View2D *v2d,
+ const SpaceNode *snode,
+ const bNodeLink *link,
float vec[4][2])
{
float cursor[2] = {0.0f, 0.0f};
/* this function can be called with snode null (via cut_links_intersect) */
- /* XXX map snode->cursor back to view space */
+ /* XXX map snode->runtime->cursor back to view space */
if (snode) {
- cursor[0] = snode->cursor[0] * UI_DPI_FAC;
- cursor[1] = snode->cursor[1] * UI_DPI_FAC;
+ cursor[0] = snode->runtime->cursor[0] * UI_DPI_FAC;
+ cursor[1] = snode->runtime->cursor[1] * UI_DPI_FAC;
}
/* in v0 and v3 we put begin/end points */
@@ -3923,8 +4013,11 @@ static bool node_link_bezier_handles(View2D *v2d,
}
/* if v2d not NULL, it clips and returns 0 if not visible */
-bool node_link_bezier_points(
- View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol)
+bool node_link_bezier_points(const View2D *v2d,
+ const SpaceNode *snode,
+ const bNodeLink *link,
+ float coord_array[][2],
+ const int resol)
{
float vec[4][2];
@@ -4087,7 +4180,7 @@ static char nodelink_get_color_id(int th_col)
return 0;
}
-static void nodelink_batch_draw(SpaceNode *snode)
+static void nodelink_batch_draw(const SpaceNode *snode)
{
if (g_batch_link.count == 0) {
return;
@@ -4107,7 +4200,7 @@ static void nodelink_batch_draw(SpaceNode *snode)
GPU_batch_program_set_builtin(g_batch_link.batch, GPU_SHADER_2D_NODELINK_INST);
GPU_batch_uniform_4fv_array(g_batch_link.batch, "colors", 6, colors);
- GPU_batch_uniform_1f(g_batch_link.batch, "expandSize", snode->aspect * LINK_WIDTH);
+ GPU_batch_uniform_1f(g_batch_link.batch, "expandSize", snode->runtime->aspect * LINK_WIDTH);
GPU_batch_uniform_1f(g_batch_link.batch, "arrowSize", ARROW_SIZE);
GPU_batch_draw(g_batch_link.batch);
@@ -4127,7 +4220,7 @@ void nodelink_batch_end(SpaceNode *snode)
g_batch_link.enabled = false;
}
-static void nodelink_batch_add_link(SpaceNode *snode,
+static void nodelink_batch_add_link(const SpaceNode *snode,
const float p0[2],
const float p1[2],
const float p2[2],
@@ -4159,8 +4252,12 @@ static void nodelink_batch_add_link(SpaceNode *snode,
}
/* don't do shadows if th_col3 is -1. */
-void node_draw_link_bezier(
- View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int th_col2, int th_col3)
+void node_draw_link_bezier(const View2D *v2d,
+ const SpaceNode *snode,
+ const bNodeLink *link,
+ int th_col1,
+ int th_col2,
+ int th_col3)
{
float vec[4][2];
@@ -4190,7 +4287,7 @@ void node_draw_link_bezier(
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK);
GPU_batch_uniform_2fv_array(batch, "bezierPts", 4, vec);
GPU_batch_uniform_4fv_array(batch, "colors", 3, colors);
- GPU_batch_uniform_1f(batch, "expandSize", snode->aspect * LINK_WIDTH);
+ GPU_batch_uniform_1f(batch, "expandSize", snode->runtime->aspect * LINK_WIDTH);
GPU_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE);
GPU_batch_uniform_1i(batch, "doArrow", drawarrow);
GPU_batch_draw(batch);
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 508c0a47e21..e665f7b1d52 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -104,9 +104,8 @@ static bool add_reroute_intersect_check(bNodeLink *link,
if (node_link_bezier_points(NULL, NULL, link, coord_array, NODE_LINK_RESOL)) {
for (int i = 0; i < tot - 1; i++) {
for (int b = 0; b < NODE_LINK_RESOL; b++) {
- if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0) {
- result[0] = (mcoords[i][0] + mcoords[i + 1][0]) / 2.0f;
- result[1] = (mcoords[i][1] + mcoords[i + 1][1]) / 2.0f;
+ if (isect_seg_seg_v2_point(
+ mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1], result) > 0) {
return true;
}
}
@@ -312,6 +311,13 @@ void NODE_OT_add_reroute(wmOperatorType *ot)
/* ****************** Add File Node Operator ******************* */
+static bool node_add_file_poll(bContext *C)
+{
+ const SpaceNode *snode = CTX_wm_space_node(C);
+ return ED_operator_node_editable(C) &&
+ ELEM(snode->nodetree->type, NTREE_SHADER, NTREE_TEXTURE, NTREE_COMPOSIT);
+}
+
static int node_add_file_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -341,7 +347,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- node = node_add_node(C, NULL, type, snode->cursor[0], snode->cursor[1]);
+ node = node_add_node(C, NULL, type, snode->runtime->cursor[0], snode->runtime->cursor[1]);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
@@ -370,11 +376,14 @@ static int node_add_file_invoke(bContext *C, wmOperator *op, const wmEvent *even
SpaceNode *snode = CTX_wm_space_node(C);
/* convert mouse coordinates to v2d space */
- UI_view2d_region_to_view(
- &region->v2d, event->mval[0], event->mval[1], &snode->cursor[0], &snode->cursor[1]);
+ UI_view2d_region_to_view(&region->v2d,
+ event->mval[0],
+ event->mval[1],
+ &snode->runtime->cursor[0],
+ &snode->runtime->cursor[1]);
- snode->cursor[0] /= UI_DPI_FAC;
- snode->cursor[1] /= UI_DPI_FAC;
+ snode->runtime->cursor[0] /= UI_DPI_FAC;
+ snode->runtime->cursor[1] /= UI_DPI_FAC;
if (RNA_struct_property_is_set(op->ptr, "filepath") ||
RNA_struct_property_is_set(op->ptr, "name")) {
@@ -393,7 +402,7 @@ void NODE_OT_add_file(wmOperatorType *ot)
/* callbacks */
ot->exec = node_add_file_exec;
ot->invoke = node_add_file_invoke;
- ot->poll = ED_operator_node_editable;
+ ot->poll = node_add_file_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -435,7 +444,8 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- node = node_add_node(C, NULL, CMP_NODE_MASK, snode->cursor[0], snode->cursor[1]);
+ node = node_add_node(
+ C, NULL, CMP_NODE_MASK, snode->runtime->cursor[0], snode->runtime->cursor[1]);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add a mask node");
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index d3fec7257f5..037587809b0 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -317,14 +317,14 @@ static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
}
}
-void node_to_view(struct bNode *node, float x, float y, float *rx, float *ry)
+void node_to_view(const bNode *node, float x, float y, float *rx, float *ry)
{
nodeToView(node, x, y, rx, ry);
*rx *= UI_DPI_FAC;
*ry *= UI_DPI_FAC;
}
-void node_to_updated_rect(struct bNode *node, rctf *r_rect)
+void node_to_updated_rect(const bNode *node, rctf *r_rect)
{
node_to_view(node, node->offsetx, node->offsety, &r_rect->xmin, &r_rect->ymax);
node_to_view(node,
@@ -334,7 +334,7 @@ void node_to_updated_rect(struct bNode *node, rctf *r_rect)
&r_rect->ymin);
}
-void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry)
+void node_from_view(const bNode *node, float x, float y, float *rx, float *ry)
{
x /= UI_DPI_FAC;
y /= UI_DPI_FAC;
@@ -689,11 +689,11 @@ int node_get_colorid(bNode *node)
/* note: in cmp_util.c is similar code, for node_compo_pass_on()
* the same goes for shader and texture nodes. */
/* note: in node_edit.c is similar code, for untangle node */
-static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
+static void node_draw_mute_line(const View2D *v2d, const SpaceNode *snode, const bNode *node)
{
GPU_blend(GPU_BLEND_ALPHA);
- LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
+ LISTBASE_FOREACH (const bNodeLink *, link, &node->internal_links) {
node_draw_link_bezier(v2d, snode, link, TH_REDALERT, TH_REDALERT, -1);
}
@@ -947,14 +947,14 @@ static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_
WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, NULL);
}
-void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha)
+void node_draw_shadow(const SpaceNode *snode, const bNode *node, float radius, float alpha)
{
- rctf *rct = &node->totr;
+ const rctf *rct = &node->totr;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- ui_draw_dropshadow(rct, radius, snode->aspect, alpha, node->flag & SELECT);
+ ui_draw_dropshadow(rct, radius, snode->runtime->aspect, alpha, node->flag & SELECT);
}
-void node_draw_sockets(View2D *v2d,
+void node_draw_sockets(const View2D *v2d,
const bContext *C,
bNodeTree *ntree,
bNode *node,
@@ -1118,8 +1118,8 @@ void node_draw_sockets(View2D *v2d,
}
static void node_draw_basis(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
+ const View2D *v2d,
+ const SpaceNode *snode,
bNodeTree *ntree,
bNode *node,
bNodeInstanceKey key)
@@ -1127,8 +1127,6 @@ static void node_draw_basis(const bContext *C,
/* float socket_size = NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
float iconbutw = 0.8f * UI_UNIT_X;
- View2D *v2d = &region->v2d;
-
/* skip if out of view */
if (BLI_rctf_isect(&node->totr, &v2d->cur, NULL) == false) {
UI_block_end(C, node->block);
@@ -1157,7 +1155,15 @@ static void node_draw_basis(const bContext *C,
rctf *rct = &node->totr;
UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
UI_draw_roundbox_aa(
- true, rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD, color);
+ &(const rctf){
+ .xmin = rct->xmin,
+ .xmax = rct->xmax,
+ .ymin = rct->ymax - NODE_DY,
+ .ymax = rct->ymax,
+ },
+ true,
+ BASIS_RAD,
+ color);
/* show/hide icons */
float iconofs = rct->xmax - 0.35f * U.widget_unit;
@@ -1308,7 +1314,15 @@ static void node_draw_basis(const bContext *C,
UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
UI_draw_roundbox_aa(
- true, rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD, color);
+ &(const rctf){
+ .xmin = rct->xmin,
+ .xmax = rct->xmax,
+ .ymin = rct->ymin,
+ .ymax = rct->ymax - NODE_DY,
+ },
+ true,
+ BASIS_RAD,
+ color);
/* outline active and selected emphasis */
if (node->flag & SELECT) {
@@ -1316,7 +1330,16 @@ static void node_draw_basis(const bContext *C,
(node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
+ UI_draw_roundbox_aa(
+ &(const rctf){
+ .xmin = rct->xmin,
+ .xmax = rct->xmax,
+ .ymin = rct->ymin,
+ .ymax = rct->ymax,
+ },
+ false,
+ BASIS_RAD,
+ color);
}
/* disable lines */
@@ -1343,8 +1366,8 @@ static void node_draw_basis(const bContext *C,
}
static void node_draw_hidden(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
+ const View2D *v2d,
+ const SpaceNode *snode,
bNodeTree *ntree,
bNode *node,
bNodeInstanceKey UNUSED(key))
@@ -1353,8 +1376,6 @@ static void node_draw_hidden(const bContext *C,
float centy = BLI_rctf_cent_y(rct);
float hiddenrad = BLI_rctf_size_y(rct) / 2.0f;
- View2D *v2d = &region->v2d;
-
float scale;
UI_view2d_scale_get(v2d, &scale, NULL);
@@ -1373,14 +1394,14 @@ static void node_draw_hidden(const bContext *C,
UI_GetThemeColor4fv(color_id, color);
}
- UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color);
+ UI_draw_roundbox_aa(rct, true, hiddenrad, color);
/* outline active and selected emphasis */
if (node->flag & SELECT) {
UI_GetThemeColorShadeAlpha4fv(
(node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
- UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color);
+ UI_draw_roundbox_aa(rct, false, hiddenrad, color);
}
/* custom color inline */
@@ -1388,14 +1409,17 @@ static void node_draw_hidden(const bContext *C,
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
- UI_draw_roundbox_3fv_alpha(false,
- rct->xmin + 1,
- rct->ymin + 1,
- rct->xmax - 1,
- rct->ymax - 1,
- hiddenrad,
- node->color,
- 1.0f);
+ UI_draw_roundbox_3fv_alpha(
+ &(const rctf){
+ .xmin = rct->xmin + 1,
+ .xmax = rct->xmax - 1,
+ .ymin = rct->ymin + 1,
+ .ymax = rct->ymax - 1,
+ },
+ false,
+ hiddenrad,
+ node->color,
+ 1.0f);
GPU_line_smooth(false);
GPU_blend(GPU_BLEND_NONE);
@@ -1438,7 +1462,7 @@ static void node_draw_hidden(const bContext *C,
/* disable lines */
if (node->flag & NODE_MUTED) {
- node_draw_mute_line(&region->v2d, snode, node);
+ node_draw_mute_line(v2d, snode, node);
}
char showname[128]; /* 128 is used below */
@@ -1477,19 +1501,19 @@ static void node_draw_hidden(const bContext *C,
immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
- immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f);
- immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
+ immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy - 4.0f);
+ immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy + 4.0f);
immEnd();
immUniformThemeColorShade(color_id, 30);
- dx -= snode->aspect;
+ dx -= snode->runtime->aspect;
immBegin(GPU_PRIM_LINES, 4);
immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
- immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f);
- immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
+ immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy - 4.0f);
+ immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy + 4.0f);
immEnd();
immUnbindProgram();
@@ -1550,11 +1574,12 @@ void node_draw_default(const bContext *C,
bNode *node,
bNodeInstanceKey key)
{
+ const View2D *v2d = &region->v2d;
if (node->flag & NODE_HIDDEN) {
- node_draw_hidden(C, region, snode, ntree, node, key);
+ node_draw_hidden(C, v2d, snode, ntree, node, key);
}
else {
- node_draw_basis(C, region, snode, ntree, node, key);
+ node_draw_basis(C, v2d, snode, ntree, node, key);
}
}
@@ -1607,8 +1632,7 @@ void node_draw_nodetree(const bContext *C,
#endif
/* draw background nodes, last nodes in front */
- int a = 0;
- LISTBASE_FOREACH_INDEX (bNode *, node, &ntree->nodes, a) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
#ifdef USE_DRAW_TOT_UPDATE
/* unrelated to background nodes, update the v2d->tot,
* can be anywhere before we draw the scroll bars */
@@ -1635,8 +1659,7 @@ void node_draw_nodetree(const bContext *C,
GPU_blend(GPU_BLEND_NONE);
/* draw foreground nodes, last nodes in front */
- a = 0;
- LISTBASE_FOREACH_INDEX (bNode *, node, &ntree->nodes, a) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & NODE_BACKGROUND) {
continue;
}
@@ -1666,7 +1689,7 @@ static void snode_setup_v2d(SpaceNode *snode, ARegion *region, const float cente
UI_view2d_view_ortho(v2d);
/* aspect+font, set each time */
- snode->aspect = BLI_rctf_size_x(&v2d->cur) / (float)region->winx;
+ snode->runtime->aspect = BLI_rctf_size_x(&v2d->cur) / (float)region->winx;
// XXX snode->curfont = uiSetCurFont_ext(snode->aspect);
}
@@ -1686,8 +1709,8 @@ static void draw_nodetree(const bContext *C,
/* shade the parent node group and add a uiBlock to clip mouse events */
static void draw_group_overlay(const bContext *C, ARegion *region)
{
- View2D *v2d = &region->v2d;
- rctf rect = v2d->cur;
+ const View2D *v2d = &region->v2d;
+ const rctf rect = v2d->cur;
float color[4];
/* shade node groups to separate them visually */
@@ -1695,7 +1718,7 @@ static void draw_group_overlay(const bContext *C, ARegion *region)
UI_GetThemeColorShadeAlpha4fv(TH_NODE_GROUP, 0, 0, color);
UI_draw_roundbox_corner_set(UI_CNR_NONE);
- UI_draw_roundbox_4fv(true, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0, color);
+ UI_draw_roundbox_4fv(&rect, true, 0, color);
GPU_blend(GPU_BLEND_NONE);
/* set the block bounds to clip mouse events from underlying nodes */
@@ -1722,14 +1745,15 @@ void node_draw_space(const bContext *C, ARegion *region)
GPU_depth_test(GPU_DEPTH_NONE);
GPU_scissor_test(true);
- /* XXX snode->cursor set in coordspace for placing new nodes, used for drawing noodles too */
+ /* XXX snode->runtime->cursor set in coordspace for placing new nodes, used for drawing noodles
+ * too */
UI_view2d_region_to_view(&region->v2d,
win->eventstate->x - region->winrct.xmin,
win->eventstate->y - region->winrct.ymin,
- &snode->cursor[0],
- &snode->cursor[1]);
- snode->cursor[0] /= UI_DPI_FAC;
- snode->cursor[1] /= UI_DPI_FAC;
+ &snode->runtime->cursor[0],
+ &snode->runtime->cursor[1]);
+ snode->runtime->cursor[0] /= UI_DPI_FAC;
+ snode->runtime->cursor[1] /= UI_DPI_FAC;
int grid_levels = UI_GetThemeValueType(TH_NODE_GRID_LEVELS, SPACE_NODE);
@@ -1819,7 +1843,7 @@ void node_draw_space(const bContext *C, ARegion *region)
/* temporary links */
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
- LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->linkdrag) {
+ LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
node_draw_link(v2d, snode, (bNodeLink *)linkdata->data);
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 30eee416b12..ced81401874 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -880,8 +880,8 @@ static void node_resize_init(
NodeSizeWidget *nsw = MEM_callocN(sizeof(NodeSizeWidget), "size widget op data");
op->customdata = nsw;
- nsw->mxstart = snode->cursor[0] * UI_DPI_FAC;
- nsw->mystart = snode->cursor[1] * UI_DPI_FAC;
+ nsw->mxstart = snode->runtime->cursor[0] * UI_DPI_FAC;
+ nsw->mystart = snode->runtime->cursor[1] * UI_DPI_FAC;
/* store old */
nsw->oldlocx = node->locx;
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index aa59b7293a3..a2b04fa9665 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -37,6 +37,7 @@ struct bContext;
struct bNode;
struct bNodeLink;
struct bNodeSocket;
+struct NodeInsertOfsData;
struct wmGizmoGroupType;
struct wmKeyConfig;
struct wmWindow;
@@ -53,6 +54,23 @@ typedef struct bNodeLinkDrag {
int in_out;
} bNodeLinkDrag;
+typedef struct SpaceNode_Runtime {
+ float aspect;
+
+ /** Mouse position for drawing socket-less links and adding nodes. */
+ float cursor[2];
+
+ /** For auto compositing. */
+ bool recalc;
+
+ /** Temporary data for modal linking operator. */
+ struct ListBase linkdrag;
+
+ /* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */
+ /** Temporary data for node insert offset (in UI called Auto-offset). */
+ struct NodeInsertOfsData *iofsd;
+} SpaceNode_Runtime;
+
/* space_node.c */
/* transform between View2Ds in the tree path */
@@ -61,14 +79,17 @@ void space_node_group_offset(struct SpaceNode *snode, float *x, float *y);
/* node_draw.c */
int node_get_colorid(struct bNode *node);
int node_get_resize_cursor(int directions);
-void node_draw_shadow(struct SpaceNode *snode, struct bNode *node, float radius, float alpha);
+void node_draw_shadow(const struct SpaceNode *snode,
+ const struct bNode *node,
+ float radius,
+ float alpha);
void node_draw_default(const struct bContext *C,
struct ARegion *region,
struct SpaceNode *snode,
struct bNodeTree *ntree,
struct bNode *node,
bNodeInstanceKey key);
-void node_draw_sockets(struct View2D *v2d,
+void node_draw_sockets(const struct View2D *v2d,
const struct bContext *C,
struct bNodeTree *ntree,
struct bNode *node,
@@ -92,9 +113,9 @@ void node_draw_space(const bContext *C, ARegion *region);
void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode, float cursor[2]);
/* DPI scaled coords */
-void node_to_view(struct bNode *node, float x, float y, float *rx, float *ry);
-void node_to_updated_rect(struct bNode *node, rctf *r_rect);
-void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry);
+void node_to_view(const struct bNode *node, float x, float y, float *rx, float *ry);
+void node_to_updated_rect(const struct bNode *node, rctf *r_rect);
+void node_from_view(const struct bNode *node, float x, float y, float *rx, float *ry);
/* node_buttons.c */
void node_buttons_register(struct ARegionType *art);
@@ -145,17 +166,17 @@ void nodelink_batch_start(struct SpaceNode *snode);
void nodelink_batch_end(struct SpaceNode *snode);
void node_draw_link(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link);
-void node_draw_link_bezier(struct View2D *v2d,
- struct SpaceNode *snode,
- struct bNodeLink *link,
+void node_draw_link_bezier(const struct View2D *v2d,
+ const struct SpaceNode *snode,
+ const struct bNodeLink *link,
int th_col1,
int th_col2,
int th_col3);
-bool node_link_bezier_points(struct View2D *v2d,
- struct SpaceNode *snode,
- struct bNodeLink *link,
+bool node_link_bezier_points(const struct View2D *v2d,
+ const struct SpaceNode *snode,
+ const struct bNodeLink *link,
float coord_array[][2],
- int resol);
+ const int resol);
void draw_nodespace_back_pix(const struct bContext *C,
struct ARegion *region,
struct SpaceNode *snode,
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index ba1e752e276..ee7c8bca2f8 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -58,7 +58,7 @@
static bool ntree_has_drivers(bNodeTree *ntree)
{
- AnimData *adt = BKE_animdata_from_id(&ntree->id);
+ const AnimData *adt = BKE_animdata_from_id(&ntree->id);
if (adt == NULL) {
return false;
}
@@ -663,7 +663,7 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
snode_dag_update(C, snode);
}
- BLI_remlink(&snode->linkdrag, nldrag);
+ BLI_remlink(&snode->runtime->linkdrag, nldrag);
/* links->data pointers are either held by the tree or freed already */
BLI_freelistN(&nldrag->links);
MEM_freeN(nldrag);
@@ -903,7 +903,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (nldrag) {
op->customdata = nldrag;
- BLI_addtail(&snode->linkdrag, nldrag);
+ BLI_addtail(&snode->runtime->linkdrag, nldrag);
/* add modal handler */
WM_event_add_modal_handler(C, op);
@@ -918,7 +918,7 @@ static void node_link_cancel(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeLinkDrag *nldrag = op->customdata;
- BLI_remlink(&snode->linkdrag, nldrag);
+ BLI_remlink(&snode->runtime->linkdrag, nldrag);
BLI_freelistN(&nldrag->links);
MEM_freeN(nldrag);
@@ -1798,7 +1798,7 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
- NodeInsertOfsData *iofsd = snode->iofsd;
+ NodeInsertOfsData *iofsd = snode->runtime->iofsd;
bool redraw = false;
if (!snode || event->type != TIMER || iofsd == NULL || iofsd->anim_timer != event->customdata) {
@@ -1837,7 +1837,7 @@ static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const w
node->anim_init_locx = node->anim_ofsx = 0.0f;
}
- snode->iofsd = NULL;
+ snode->runtime->iofsd = NULL;
MEM_freeN(iofsd);
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
@@ -1851,7 +1851,7 @@ static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const w
static int node_insert_offset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const SpaceNode *snode = CTX_wm_space_node(C);
- NodeInsertOfsData *iofsd = snode->iofsd;
+ NodeInsertOfsData *iofsd = snode->runtime->iofsd;
if (!iofsd || !iofsd->insert) {
return OPERATOR_CANCELLED;
@@ -1927,7 +1927,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
iofsd->prev = link->fromnode;
iofsd->next = node;
- snode->iofsd = iofsd;
+ snode->runtime->iofsd = iofsd;
}
ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 5060ac0db8a..a41f99afb4c 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -62,14 +62,15 @@
#include "node_intern.h" /* own include */
-/* Function to detect if there is a visible view3d that uses workbench in texture mode.
+/**
+ * Function to detect if there is a visible view3d that uses workbench in texture mode.
* This function is for fixing T76970 for Blender 2.83. The actual fix should add a mechanism in
* the depsgraph that can be used by the draw engines to check if they need to be redrawn.
*
* We don't want to add these risky changes this close before releasing 2.83 without good testing
* hence this workaround. There are still cases were too many updates happen. For example when you
* have both a Cycles and workbench with textures viewport.
- * */
+ */
static bool has_workbench_in_texture_color(const wmWindowManager *wm,
const Scene *scene,
const Object *ob)
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index ad7632377a3..94915022ce9 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -321,18 +321,25 @@ static void node_free(SpaceLink *sl)
LISTBASE_FOREACH_MUTABLE (bNodeTreePath *, path, &snode->treepath) {
MEM_freeN(path);
}
+
+ MEM_SAFE_FREE(snode->runtime);
}
/* spacetype; init callback */
-static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
+static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area)
{
+ SpaceNode *snode = (SpaceNode *)area->spacedata.first;
+
+ if (snode->runtime == NULL) {
+ snode->runtime = MEM_callocN(sizeof(SpaceNode_Runtime), __func__);
+ }
}
-static void node_area_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- wmNotifier *wmn,
- Scene *UNUSED(scene))
+static void node_area_listener(const wmSpaceTypeListenerParams *params)
{
+ ScrArea *area = params->area;
+ wmNotifier *wmn = params->notifier;
+
/* note, ED_area_tag_refresh will re-execute compositor */
SpaceNode *snode = area->spacedata.first;
/* shaderfrom is only used for new shading nodes, otherwise all shaders are from objects */
@@ -362,7 +369,7 @@ static void node_area_listener(wmWindow *UNUSED(win),
case ND_TRANSFORM_DONE:
if (ED_node_is_compositor(snode)) {
if (snode->flag & SNODE_AUTO_RENDER) {
- snode->recalc = 1;
+ snode->runtime->recalc = true;
ED_area_tag_refresh(area);
}
}
@@ -521,8 +528,8 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area)
Scene *scene = (Scene *)snode->id;
if (scene->use_nodes) {
/* recalc is set on 3d view changes for auto compo */
- if (snode->recalc) {
- snode->recalc = 0;
+ if (snode->runtime->recalc) {
+ snode->runtime->recalc = false;
node_render_changed_exec((struct bContext *)C, NULL);
}
else {
@@ -546,8 +553,10 @@ static SpaceLink *node_duplicate(SpaceLink *sl)
BLI_duplicatelist(&snoden->treepath, &snode->treepath);
- /* clear or remove stuff from old */
- BLI_listbase_clear(&snoden->linkdrag);
+ if (snode->runtime != NULL) {
+ snoden->runtime = MEM_dupallocN(snode->runtime);
+ BLI_listbase_clear(&snoden->runtime->linkdrag);
+ }
/* Note: no need to set node tree user counts,
* the editor only keeps at least 1 (id_us_ensure_real),
@@ -589,6 +598,16 @@ static void node_toolbar_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
+void ED_node_cursor_location_get(const SpaceNode *snode, float value[2])
+{
+ copy_v2_v2(value, snode->runtime->cursor);
+}
+
+void ED_node_cursor_location_set(SpaceNode *snode, const float value[2])
+{
+ copy_v2_v2(snode->runtime->cursor, value);
+}
+
static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region)
{
SpaceNode *snode = area->spacedata.first;
@@ -597,15 +616,15 @@ static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region)
UI_view2d_region_to_view(&region->v2d,
win->eventstate->x - region->winrct.xmin,
win->eventstate->y - region->winrct.ymin,
- &snode->cursor[0],
- &snode->cursor[1]);
+ &snode->runtime->cursor[0],
+ &snode->runtime->cursor[1]);
- /* here snode->cursor is used to detect the node edge for sizing */
- node_set_cursor(win, snode, snode->cursor);
+ /* here snode->runtime->cursor is used to detect the node edge for sizing */
+ node_set_cursor(win, snode, snode->runtime->cursor);
- /* XXX snode->cursor is in placing new nodes space */
- snode->cursor[0] /= UI_DPI_FAC;
- snode->cursor[1] /= UI_DPI_FAC;
+ /* XXX snode->runtime->cursor is in placing new nodes space */
+ snode->runtime->cursor[0] /= UI_DPI_FAC;
+ snode->runtime->cursor[1] /= UI_DPI_FAC;
}
/* Initialize main region, setting handlers. */
@@ -645,7 +664,7 @@ static bool node_ima_drop_poll(bContext *UNUSED(C),
/* rule might not work? */
return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE));
}
- return WM_drag_get_local_ID(drag, ID_IM) != NULL;
+ return WM_drag_is_ID_type(drag, ID_IM);
}
static bool node_mask_drop_poll(bContext *UNUSED(C),
@@ -653,19 +672,19 @@ static bool node_mask_drop_poll(bContext *UNUSED(C),
const wmEvent *UNUSED(event),
const char **UNUSED(r_tooltip))
{
- return WM_drag_get_local_ID(drag, ID_MSK) != NULL;
+ return WM_drag_is_ID_type(drag, ID_MSK);
}
static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = WM_drag_get_local_ID(drag, 0);
+ ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = WM_drag_get_local_ID(drag, 0);
+ ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
if (id) {
RNA_string_set(drop->ptr, "name", id->name + 2);
@@ -703,12 +722,10 @@ static void node_header_region_draw(const bContext *C, ARegion *region)
}
/* used for header + main region */
-static void node_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void node_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
wmGizmoMap *gzmap = region->gizmo_map;
/* context changes */
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index ab515c0c3a8..467802d181b 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -140,6 +140,11 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
TreeElement *te_hovered;
float view_mval[2];
+ /* Emtpy tree, e.g. while filtered. */
+ if (BLI_listbase_is_empty(&space_outliner->tree)) {
+ return NULL;
+ }
+
UI_view2d_region_to_view(
&region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
te_hovered = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 8104c1e0d58..d424bb2319a 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -314,7 +314,7 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
/**
* Object properties.
- * */
+ */
static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
Object *ob = poin;
@@ -324,7 +324,7 @@ static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void
/**
* Base properties.
- * */
+ */
static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
Base *base = poin;
@@ -697,13 +697,13 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
break;
}
default:
- WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
break;
}
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
+
/* Check the library target exists */
if (te->idcode == ID_LI) {
Library *lib = (Library *)tselem->id;
@@ -2695,13 +2695,16 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
float offset_x = (float)offsx + UI_UNIT_X * 0.35f;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(true,
- offset_x + ufac,
- (float)ys - UI_UNIT_Y * 0.2f + ufac,
- offset_x + UI_UNIT_X - ufac,
- (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac,
- (float)UI_UNIT_Y / 2.0f - ufac,
- color);
+ UI_draw_roundbox_aa(
+ &(const rctf){
+ .xmin = offset_x + ufac,
+ .xmax = offset_x + UI_UNIT_X - ufac,
+ .ymin = (float)ys - UI_UNIT_Y * 0.2f + ufac,
+ .ymax = (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac,
+ },
+ true,
+ (float)UI_UNIT_Y / 2.0f - ufac,
+ color);
/* Now the numbers. */
uchar text_col[4];
@@ -2751,8 +2754,26 @@ static void outliner_draw_active_indicator(const float minx,
const float radius = UI_UNIT_Y / 4.0f;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(true, minx, miny + ufac, maxx, maxy - ufac, radius, icon_color);
- UI_draw_roundbox_aa(false, minx, miny + ufac, maxx, maxy - ufac, radius, icon_border);
+ UI_draw_roundbox_aa(
+ &(const rctf){
+ .xmin = minx,
+ .xmax = maxx,
+ .ymin = miny + ufac,
+ .ymax = maxy - ufac,
+ },
+ true,
+ radius,
+ icon_color);
+ UI_draw_roundbox_aa(
+ &(const rctf){
+ .xmin = minx,
+ .xmax = maxx,
+ .ymin = miny + ufac,
+ .ymax = maxy - ufac,
+ },
+ false,
+ radius,
+ icon_border);
GPU_blend(GPU_BLEND_ALPHA); /* Roundbox disables. */
}
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 600047c4b11..1ef5735d7d2 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -1543,7 +1543,7 @@ static bool outliner_is_co_within_active_mode_column(bContext *C,
* Action to run when clicking in the outliner,
*
* May expend/collapse branches or activate items.
- * */
+ */
static int outliner_item_do_activate_from_cursor(bContext *C,
const int mval[2],
const bool extend,
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index acfeccca175..7df6115cb06 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -167,8 +167,6 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
static void check_persistent(
SpaceOutliner *space_outliner, TreeElement *te, ID *id, short type, short nr)
{
- TreeStoreElem *tselem;
-
if (space_outliner->treestore == NULL) {
/* if treestore was not created in readfile.c, create it here */
space_outliner->treestore = BLI_mempool_create(
@@ -181,7 +179,8 @@ static void check_persistent(
/* find any unused tree element in treestore and mark it as used
* (note that there may be multiple unused elements in case of linked objects) */
- tselem = BKE_outliner_treehash_lookup_unused(space_outliner->runtime->treehash, type, nr, id);
+ TreeStoreElem *tselem = BKE_outliner_treehash_lookup_unused(
+ space_outliner->runtime->treehash, type, nr, id);
if (tselem) {
te->store_elem = tselem;
tselem->used = 1;
@@ -204,8 +203,7 @@ static void check_persistent(
void outliner_free_tree(ListBase *tree)
{
- for (TreeElement *element = tree->first, *element_next; element; element = element_next) {
- element_next = element->next;
+ LISTBASE_FOREACH_MUTABLE (TreeElement *, element, tree) {
outliner_free_tree_element(element, tree);
}
}
@@ -271,8 +269,8 @@ static void outliner_add_bone(SpaceOutliner *space_outliner,
te->name = curBone->name;
te->directdata = curBone;
- for (curBone = curBone->childbase.first; curBone; curBone = curBone->next) {
- outliner_add_bone(space_outliner, &te->subtree, id, curBone, te, a);
+ LISTBASE_FOREACH (Bone *, child_bone, &curBone->childbase) {
+ outliner_add_bone(space_outliner, &te->subtree, id, child_bone, te, a);
}
}
@@ -381,35 +379,30 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
if (ob->pose) {
bArmature *arm = ob->data;
- bPoseChannel *pchan;
TreeElement *tenla = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_POSE_BASE, 0);
-
tenla->name = IFACE_("Pose");
/* channels undefined in editmode, but we want the 'tenla' pose icon itself */
if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) {
- TreeElement *ten;
- int a = 0, const_index = 1000; /* ensure unique id for bone constraints */
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, a++) {
- ten = outliner_add_element(
+ int const_index = 1000; /* ensure unique id for bone constraints */
+ int a;
+ LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, a) {
+ TreeElement *ten = outliner_add_element(
space_outliner, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a);
ten->name = pchan->name;
ten->directdata = pchan;
pchan->temp = (void *)ten;
- if (pchan->constraints.first) {
+ if (!BLI_listbase_is_empty(&pchan->constraints)) {
/* Object *target; */
- bConstraint *con;
- TreeElement *ten1;
TreeElement *tenla1 = outliner_add_element(
space_outliner, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
+ tenla1->name = IFACE_("Constraints");
/* char *str; */
- tenla1->name = IFACE_("Constraints");
- for (con = pchan->constraints.first; con; con = con->next, const_index++) {
- ten1 = outliner_add_element(
+ LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
+ TreeElement *ten1 = outliner_add_element(
space_outliner, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
#if 0 /* disabled as it needs to be reworked for recoded constraints system */
target = get_constraint_target(con, &str);
@@ -427,15 +420,16 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
ten1->directdata = con;
/* possible add all other types links? */
}
+ const_index++;
}
}
/* make hierarchy */
- ten = tenla->subtree.first;
+ TreeElement *ten = tenla->subtree.first;
while (ten) {
TreeElement *nten = ten->next, *par;
tselem = TREESTORE(ten);
if (tselem->type == TSE_POSE_CHANNEL) {
- pchan = (bPoseChannel *)ten->directdata;
+ bPoseChannel *pchan = (bPoseChannel *)ten->directdata;
if (pchan->parent) {
BLI_remlink(&tenla->subtree, ten);
par = (TreeElement *)pchan->parent->temp;
@@ -448,17 +442,15 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
/* Pose Groups */
- if (ob->pose->agroups.first) {
- bActionGroup *agrp;
+ if (!BLI_listbase_is_empty(&ob->pose->agroups)) {
TreeElement *ten_bonegrp = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
- int a = 0;
-
ten_bonegrp->name = IFACE_("Bone Groups");
- for (agrp = ob->pose->agroups.first; agrp; agrp = agrp->next, a++) {
- TreeElement *ten;
- ten = outliner_add_element(
- space_outliner, &ten_bonegrp->subtree, ob, ten_bonegrp, TSE_POSEGRP, a);
+
+ int index;
+ LISTBASE_FOREACH_INDEX (bActionGroup *, agrp, &ob->pose->agroups, index) {
+ TreeElement *ten = outliner_add_element(
+ space_outliner, &ten_bonegrp->subtree, ob, ten_bonegrp, TSE_POSEGRP, index);
ten->name = agrp->name;
ten->directdata = agrp;
}
@@ -469,18 +461,15 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, 0, a);
}
- if (ob->constraints.first) {
- /* Object *target; */
- bConstraint *con;
- TreeElement *ten;
+ if (!BLI_listbase_is_empty(&ob->constraints)) {
TreeElement *tenla = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
- /* char *str; */
- int a;
-
tenla->name = IFACE_("Constraints");
- for (con = ob->constraints.first, a = 0; con; con = con->next, a++) {
- ten = outliner_add_element(space_outliner, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a);
+
+ int index;
+ LISTBASE_FOREACH_INDEX (bConstraint *, con, &ob->constraints, index) {
+ TreeElement *ten = outliner_add_element(
+ space_outliner, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, index);
#if 0 /* disabled due to constraints system targets recode... code here needs review */
target = get_constraint_target(con, &str);
if (str && str[0]) {
@@ -499,14 +488,13 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
}
- if (ob->modifiers.first) {
- ModifierData *md;
+ if (!BLI_listbase_is_empty(&ob->modifiers)) {
TreeElement *ten_mod = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
- int index;
-
ten_mod->name = IFACE_("Modifiers");
- for (index = 0, md = ob->modifiers.first; md; index++, md = md->next) {
+
+ int index;
+ LISTBASE_FOREACH_INDEX (ModifierData *, md, &ob->modifiers, index) {
TreeElement *ten = outliner_add_element(
space_outliner, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index);
ten->name = md->name;
@@ -559,8 +547,8 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
if (!BLI_listbase_is_empty(&ob->greasepencil_modifiers)) {
TreeElement *ten_mod = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
-
ten_mod->name = IFACE_("Modifiers");
+
int index;
LISTBASE_FOREACH_INDEX (GpencilModifierData *, md, &ob->greasepencil_modifiers, index) {
TreeElement *ten = outliner_add_element(
@@ -599,8 +587,8 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
if (!BLI_listbase_is_empty(&ob->shader_fx)) {
TreeElement *ten_fx = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_GPENCIL_EFFECT_BASE, 0);
-
ten_fx->name = IFACE_("Effects");
+
int index;
LISTBASE_FOREACH_INDEX (ShaderFxData *, fx, &ob->shader_fx, index) {
TreeElement *ten = outliner_add_element(
@@ -620,16 +608,15 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
/* vertex groups */
- if (ob->defbase.first) {
- bDeformGroup *defgroup;
- TreeElement *ten;
+ if (!BLI_listbase_is_empty(&ob->defbase)) {
TreeElement *tenla = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
- int a;
-
tenla->name = IFACE_("Vertex Groups");
- for (defgroup = ob->defbase.first, a = 0; defgroup; defgroup = defgroup->next, a++) {
- ten = outliner_add_element(space_outliner, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a);
+
+ int index;
+ LISTBASE_FOREACH_INDEX (bDeformGroup *, defgroup, &ob->defbase, index) {
+ TreeElement *ten = outliner_add_element(
+ space_outliner, &tenla->subtree, ob, tenla, TSE_DEFGROUP, index);
ten->name = defgroup->name;
ten->directdata = defgroup;
}
@@ -694,14 +681,13 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_ME: {
Mesh *me = (Mesh *)id;
- int a;
if (outliner_animdata_test(me->adt)) {
outliner_add_element(space_outliner, &te->subtree, me, te, TSE_ANIM_DATA, 0);
}
outliner_add_element(space_outliner, &te->subtree, me->key, te, 0, 0);
- for (a = 0; a < me->totcol; a++) {
+ for (int a = 0; a < me->totcol; a++) {
outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, 0, a);
}
/* could do tfaces with image links, but the images are not grouped nicely.
@@ -710,33 +696,30 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_CU: {
Curve *cu = (Curve *)id;
- int a;
if (outliner_animdata_test(cu->adt)) {
outliner_add_element(space_outliner, &te->subtree, cu, te, TSE_ANIM_DATA, 0);
}
- for (a = 0; a < cu->totcol; a++) {
+ for (int a = 0; a < cu->totcol; a++) {
outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, 0, a);
}
break;
}
case ID_MB: {
MetaBall *mb = (MetaBall *)id;
- int a;
if (outliner_animdata_test(mb->adt)) {
outliner_add_element(space_outliner, &te->subtree, mb, te, TSE_ANIM_DATA, 0);
}
- for (a = 0; a < mb->totcol; a++) {
+ for (int a = 0; a < mb->totcol; a++) {
outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, 0, a);
}
break;
}
case ID_MA: {
Material *ma = (Material *)id;
-
if (outliner_animdata_test(ma->adt)) {
outliner_add_element(space_outliner, &te->subtree, ma, te, TSE_ANIM_DATA, 0);
}
@@ -744,7 +727,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_TE: {
Tex *tex = (Tex *)id;
-
if (outliner_animdata_test(tex->adt)) {
outliner_add_element(space_outliner, &te->subtree, tex, te, TSE_ANIM_DATA, 0);
}
@@ -753,7 +735,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_CA: {
Camera *ca = (Camera *)id;
-
if (outliner_animdata_test(ca->adt)) {
outliner_add_element(space_outliner, &te->subtree, ca, te, TSE_ANIM_DATA, 0);
}
@@ -761,7 +742,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_CF: {
CacheFile *cache_file = (CacheFile *)id;
-
if (outliner_animdata_test(cache_file->adt)) {
outliner_add_element(space_outliner, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0);
}
@@ -770,7 +750,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_LA: {
Light *la = (Light *)id;
-
if (outliner_animdata_test(la->adt)) {
outliner_add_element(space_outliner, &te->subtree, la, te, TSE_ANIM_DATA, 0);
}
@@ -778,7 +757,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_SPK: {
Speaker *spk = (Speaker *)id;
-
if (outliner_animdata_test(spk->adt)) {
outliner_add_element(space_outliner, &te->subtree, spk, te, TSE_ANIM_DATA, 0);
}
@@ -786,7 +764,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_LP: {
LightProbe *prb = (LightProbe *)id;
-
if (outliner_animdata_test(prb->adt)) {
outliner_add_element(space_outliner, &te->subtree, prb, te, TSE_ANIM_DATA, 0);
}
@@ -794,7 +771,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_WO: {
World *wrld = (World *)id;
-
if (outliner_animdata_test(wrld->adt)) {
outliner_add_element(space_outliner, &te->subtree, wrld, te, TSE_ANIM_DATA, 0);
}
@@ -802,7 +778,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_KE: {
Key *key = (Key *)id;
-
if (outliner_animdata_test(key->adt)) {
outliner_add_element(space_outliner, &te->subtree, key, te, TSE_ANIM_DATA, 0);
}
@@ -815,27 +790,25 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_AR: {
bArmature *arm = (bArmature *)id;
- int a = 0;
if (outliner_animdata_test(arm->adt)) {
outliner_add_element(space_outliner, &te->subtree, arm, te, TSE_ANIM_DATA, 0);
}
if (arm->edbo) {
- EditBone *ebone;
- TreeElement *ten;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next, a++) {
- ten = outliner_add_element(space_outliner, &te->subtree, id, te, TSE_EBONE, a);
+ int a = 0;
+ LISTBASE_FOREACH_INDEX (EditBone *, ebone, arm->edbo, a) {
+ TreeElement *ten = outliner_add_element(
+ space_outliner, &te->subtree, id, te, TSE_EBONE, a);
ten->directdata = ebone;
ten->name = ebone->name;
ebone->temp.p = ten;
}
/* make hierarchy */
- ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
+ TreeElement *ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
while (ten) {
TreeElement *nten = ten->next, *par;
- ebone = (EditBone *)ten->directdata;
+ EditBone *ebone = (EditBone *)ten->directdata;
if (ebone->parent) {
BLI_remlink(&te->subtree, ten);
par = ebone->parent->temp.p;
@@ -852,9 +825,9 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
/* pass */
}
else {
- Bone *curBone;
- for (curBone = arm->bonebase.first; curBone; curBone = curBone->next) {
- outliner_add_bone(space_outliner, &te->subtree, id, curBone, te, &a);
+ int a = 0;
+ LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
+ outliner_add_bone(space_outliner, &te->subtree, id, bone, te, &a);
}
}
}
@@ -862,13 +835,12 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_LS: {
FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id;
- int a;
if (outliner_animdata_test(linestyle->adt)) {
outliner_add_element(space_outliner, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0);
}
- for (a = 0; a < MAX_MTEX; a++) {
+ for (int a = 0; a < MAX_MTEX; a++) {
if (linestyle->mtex[a]) {
outliner_add_element(space_outliner, &te->subtree, linestyle->mtex[a]->tex, te, 0, a);
}
@@ -877,17 +849,16 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
case ID_GD: {
bGPdata *gpd = (bGPdata *)id;
- bGPDlayer *gpl;
- int a = 0;
if (outliner_animdata_test(gpd->adt)) {
outliner_add_element(space_outliner, &te->subtree, gpd, te, TSE_ANIM_DATA, 0);
}
/* TODO: base element for layers? */
- for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
- outliner_add_element(space_outliner, &te->subtree, gpl, te, TSE_GP_LAYER, a);
- a++;
+ int index = 0;
+ LISTBASE_FOREACH_BACKWARD (bGPDlayer *, gpl, &gpd->layers) {
+ outliner_add_element(space_outliner, &te->subtree, gpl, te, TSE_GP_LAYER, index);
+ index++;
}
break;
}
@@ -957,8 +928,6 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
short type,
short index)
{
- TreeElement *te;
- TreeStoreElem *tselem;
ID *id = idv;
if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
@@ -985,12 +954,12 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
BLI_assert(TREESTORE_ID_TYPE(id));
}
- te = MEM_callocN(sizeof(TreeElement), "tree elem");
+ TreeElement *te = MEM_callocN(sizeof(TreeElement), __func__);
/* add to the visual tree */
BLI_addtail(lb, te);
/* add to the storage */
check_persistent(space_outliner, te, id, type, index);
- tselem = TREESTORE(te);
+ TreeStoreElem *tselem = TREESTORE(te);
/* if we are searching for something expand to see child elements */
if (SEARCHING_OUTLINER(space_outliner)) {
@@ -1062,7 +1031,6 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
}
else if (type == TSE_SEQUENCE) {
Sequence *seq = (Sequence *)idv;
- Sequence *p;
/*
* The idcode is a little hack, but the outliner
@@ -1081,10 +1049,8 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
*/
if (seq->type == SEQ_TYPE_META) {
- p = seq->seqbase.first;
- while (p) {
+ LISTBASE_FOREACH (Sequence *, p, &seq->seqbase) {
outliner_add_element(space_outliner, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
- p = p->next;
}
}
else {
@@ -1112,17 +1078,13 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->name = seq->strip->stripdata->name;
}
else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
- PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv;
- PropertyRNA *prop, *iterprop;
- PropertyType proptype;
+ PointerRNA *ptr = (PointerRNA *)idv;
/* Don't display arrays larger, weak but index is stored as a short,
* also the outliner isn't intended for editing such large data-sets. */
BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!")
const int tot_limit = SHRT_MAX;
- int a, tot;
-
/* we do lazy build, for speed and to avoid infinite recursion */
if (ptr->data == NULL) {
@@ -1144,8 +1106,8 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
tselem->flag &= ~TSE_CHILDSEARCH;
}
- iterprop = RNA_struct_iterator_property(ptr->type);
- tot = RNA_property_collection_length(ptr, iterprop);
+ PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
+ int tot = RNA_property_collection_length(ptr, iterprop);
CLAMP_MAX(tot, tot_limit);
/* auto open these cases */
@@ -1156,7 +1118,8 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
}
if (TSELEM_OPEN(tselem, space_outliner)) {
- for (a = 0; a < tot; a++) {
+ for (int a = 0; a < tot; a++) {
+ PointerRNA propptr;
RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr);
if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) {
outliner_add_element(
@@ -1172,11 +1135,12 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
}
else if (type == TSE_RNA_PROPERTY) {
/* property */
- iterprop = RNA_struct_iterator_property(ptr->type);
+ PointerRNA propptr;
+ PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
- prop = propptr.data;
- proptype = RNA_property_type(prop);
+ PropertyRNA *prop = propptr.data;
+ PropertyType proptype = RNA_property_type(prop);
te->name = RNA_property_ui_name(prop);
te->directdata = prop;
@@ -1188,7 +1152,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
}
if (proptype == PROP_POINTER) {
- pptr = RNA_property_pointer_get(ptr, prop);
+ PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
if (pptr.data) {
if (TSELEM_OPEN(tselem, space_outliner)) {
@@ -1201,11 +1165,12 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
}
}
else if (proptype == PROP_COLLECTION) {
- tot = RNA_property_collection_length(ptr, prop);
+ int tot = RNA_property_collection_length(ptr, prop);
CLAMP_MAX(tot, tot_limit);
if (TSELEM_OPEN(tselem, space_outliner)) {
- for (a = 0; a < tot; a++) {
+ for (int a = 0; a < tot; a++) {
+ PointerRNA pptr;
RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
outliner_add_element(
space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a);
@@ -1216,11 +1181,11 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
}
}
else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
- tot = RNA_property_array_length(ptr, prop);
+ int tot = RNA_property_array_length(ptr, prop);
CLAMP_MAX(tot, tot_limit);
if (TSELEM_OPEN(tselem, space_outliner)) {
- for (a = 0; a < tot; a++) {
+ for (int a = 0; a < tot; a++) {
outliner_add_element(
space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a);
}
@@ -1231,15 +1196,13 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
}
}
else if (type == TSE_RNA_ARRAY_ELEM) {
- char c;
-
- prop = parent->directdata;
+ PropertyRNA *prop = parent->directdata;
te->directdata = prop;
te->rnaptr = *ptr;
te->index = index;
- c = RNA_property_array_item_char(prop, index);
+ char c = RNA_property_array_item_char(prop, index);
te->name = MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName");
if (c) {
@@ -1253,16 +1216,14 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
}
else if (type == TSE_KEYMAP) {
wmKeyMap *km = (wmKeyMap *)idv;
- wmKeyMapItem *kmi;
char opname[OP_MAX_TYPENAME];
te->directdata = idv;
te->name = km->idname;
if (TSELEM_OPEN(tselem, space_outliner)) {
- int a = 0;
-
- for (kmi = km->items.first; kmi; kmi = kmi->next, a++) {
+ int a;
+ LISTBASE_FOREACH_INDEX (wmKeyMapItem *, kmi, &km->items, a) {
const char *key = WM_key_event_string(kmi->type, false);
if (key[0]) {
@@ -1344,21 +1305,18 @@ static TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outli
/* make sure elements are correctly nested */
void outliner_make_object_parent_hierarchy(ListBase *lb)
{
- TreeElement *te, *ten, *tep;
- TreeStoreElem *tselem;
-
/* build hierarchy */
/* XXX also, set extents here... */
- te = lb->first;
+ TreeElement *te = lb->first;
while (te) {
- ten = te->next;
- tselem = TREESTORE(te);
+ TreeElement *ten = te->next;
+ TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
if (ob->parent && ob->parent->id.newid) {
BLI_remlink(lb, te);
- tep = (TreeElement *)ob->parent->id.newid;
+ TreeElement *tep = (TreeElement *)ob->parent->id.newid;
BLI_addtail(&tep->subtree, te);
te->parent = tep;
}
@@ -1380,10 +1338,9 @@ typedef struct tTreeSort {
static int treesort_alpha_ob(const void *v1, const void *v2)
{
const tTreeSort *x1 = v1, *x2 = v2;
- int comp;
/* first put objects last (hierarchy) */
- comp = (x1->idcode == ID_OB);
+ int comp = (x1->idcode == ID_OB);
if (x2->idcode == ID_OB) {
comp += 2;
}
@@ -1432,9 +1389,8 @@ static int treesort_child_not_in_collection(const void *v1, const void *v2)
static int treesort_alpha(const void *v1, const void *v2)
{
const tTreeSort *x1 = v1, *x2 = v2;
- int comp;
- comp = BLI_strcasecmp_natural(x1->name, x2->name);
+ int comp = BLI_strcasecmp_natural(x1->name, x2->name);
if (comp > 0) {
return 1;
@@ -1489,14 +1445,11 @@ static int treesort_obtype_alpha(const void *v1, const void *v2)
/* sort happens on each subtree individual */
static void outliner_sort(ListBase *lb)
{
- TreeElement *te;
- TreeStoreElem *tselem;
-
- te = lb->last;
+ TreeElement *te = lb->last;
if (te == NULL) {
return;
}
- tselem = TREESTORE(te);
+ TreeStoreElem *tselem = TREESTORE(te);
/* sorting rules; only object lists, ID lists, or deformgroups */
if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
@@ -1558,14 +1511,11 @@ static void outliner_sort(ListBase *lb)
static void outliner_collections_children_sort(ListBase *lb)
{
- TreeElement *te;
- TreeStoreElem *tselem;
-
- te = lb->last;
+ TreeElement *te = lb->last;
if (te == NULL) {
return;
}
- tselem = TREESTORE(te);
+ TreeStoreElem *tselem = TREESTORE(te);
/* Sorting rules: only object lists. */
if (tselem->type == 0 && te->idcode == ID_OB) {
@@ -1687,8 +1637,7 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner
const float view_co,
const float view_co_limit)
{
- TreeElement *te, *te_sub;
- te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_co);
+ TreeElement *te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_co);
bool (*callback_test)(TreeElement *);
if ((space_outliner->outlinevis == SO_VIEW_LAYER) &&
@@ -1700,7 +1649,7 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner
}
while (te != NULL) {
- te_sub = outliner_find_first_desired_element_at_y_recursive(
+ TreeElement *te_sub = outliner_find_first_desired_element_at_y_recursive(
space_outliner, te, view_co_limit, callback_test);
if (te_sub != NULL) {
/* Skip the element if it was not visible to start with. */
@@ -1742,12 +1691,12 @@ static void outliner_store_scrolling_position(SpaceOutliner *space_outliner,
ARegion *region,
OutlinerTreeElementFocus *focus)
{
- TreeElement *te;
float limit = region->v2d.cur.ymin;
outliner_set_coordinates(region, space_outliner);
- te = outliner_find_first_desired_element_at_y(space_outliner, region->v2d.cur.ymax, limit);
+ TreeElement *te = outliner_find_first_desired_element_at_y(
+ space_outliner, region->v2d.cur.ymax, limit);
if (te != NULL) {
focus->tselem = TREESTORE(te);
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 6c9d4433abd..88e88ab0c66 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -102,12 +102,11 @@ static void outliner_main_region_free(ARegion *UNUSED(region))
{
}
-static void outliner_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void outliner_main_region_listener(const wmRegionListenerParams *params)
{
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
SpaceOutliner *space_outliner = area->spacedata.first;
/* context changes */
@@ -264,15 +263,13 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
}
}
-static void outliner_main_region_message_subscribe(const struct bContext *UNUSED(C),
- struct WorkSpace *UNUSED(workspace),
- struct Scene *UNUSED(scene),
- struct bScreen *UNUSED(screen),
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus)
+static void outliner_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
SpaceOutliner *space_outliner = area->spacedata.first;
+
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
@@ -301,12 +298,11 @@ static void outliner_header_region_free(ARegion *UNUSED(region))
{
}
-static void outliner_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void outliner_header_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_SCENE:
diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c
index 3330ba14530..47de18e8faf 100644
--- a/source/blender/editors/space_script/space_script.c
+++ b/source/blender/editors/space_script/space_script.c
@@ -156,13 +156,8 @@ static void script_header_region_draw(const bContext *C, ARegion *region)
ED_region_header(C, region);
}
-static void script_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *UNUSED(region),
- wmNotifier *UNUSED(wmn),
- const Scene *UNUSED(scene))
+static void script_main_region_listener(const wmRegionListenerParams *UNUSED(params))
{
-/* context changes */
/* XXX - Todo, need the ScriptSpace accessible to get the python script to run. */
#if 0
BPY_run_script_space_listener()
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index f9076145f2f..516d3bba16f 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -1069,6 +1069,9 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
else if (seq->type == SEQ_TYPE_TEXT) {
seq->blend_mode = SEQ_TYPE_ALPHAOVER;
}
+ else if (SEQ_effect_get_num_inputs(seq->type) == 1) {
+ seq->blend_mode = seq1->blend_mode;
+ }
/* Set channel. If unset, use lowest free one above strips. */
if (!RNA_struct_property_is_set(op->ptr, "channel")) {
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 72c3e43185b..201df1ceed6 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -1447,15 +1447,24 @@ static void sequencer_draw_borders_overlay(const SpaceSeq *sseq,
if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) {
immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f);
- UI_draw_safe_areas(
- shdr_pos, x1, x2, y1, y2, scene->safe_areas.title, scene->safe_areas.action);
+ UI_draw_safe_areas(shdr_pos,
+ &(const rctf){
+ .xmin = x1,
+ .xmax = x2,
+ .ymin = y1,
+ .ymax = y2,
+ },
+ scene->safe_areas.title,
+ scene->safe_areas.action);
if (sseq->flag & SEQ_SHOW_SAFE_CENTER) {
UI_draw_safe_areas(shdr_pos,
- x1,
- x2,
- y1,
- y2,
+ &(const rctf){
+ .xmin = x1,
+ .xmax = x2,
+ .ymin = y1,
+ .ymax = y2,
+ },
scene->safe_areas.title_center,
scene->safe_areas.action_center);
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index b11e2a32b87..51c2d3ebdf1 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -334,11 +334,11 @@ static SpaceLink *sequencer_duplicate(SpaceLink *sl)
return (SpaceLink *)sseqn;
}
-static void sequencer_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- wmNotifier *wmn,
- Scene *UNUSED(scene))
+static void sequencer_listener(const wmSpaceTypeListenerParams *params)
{
+ ScrArea *area = params->area;
+ wmNotifier *wmn = params->notifier;
+
/* Context changes. */
switch (wmn->category) {
case NC_SCENE:
@@ -534,12 +534,11 @@ static void sequencer_main_region_draw_overlay(const bContext *C, ARegion *regio
draw_timeline_seq_display(C, region);
}
-static void sequencer_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void sequencer_main_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* Context changes. */
switch (wmn->category) {
case NC_SCENE:
@@ -579,14 +578,12 @@ static void sequencer_main_region_listener(wmWindow *UNUSED(win),
}
}
-static void sequencer_main_region_message_subscribe(const struct bContext *UNUSED(C),
- struct WorkSpace *UNUSED(workspace),
- struct Scene *scene,
- struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(area),
- struct ARegion *region,
- struct wmMsgBus *mbus)
+static void sequencer_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ Scene *scene = params->scene;
+ ARegion *region = params->region;
+
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
@@ -746,12 +743,11 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *region)
}
}
-static void sequencer_preview_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void sequencer_preview_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* Context changes. */
switch (wmn->category) {
case NC_GPENCIL:
@@ -816,12 +812,11 @@ static void sequencer_buttons_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-static void sequencer_buttons_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void sequencer_buttons_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* Context changes. */
switch (wmn->category) {
case NC_GPENCIL:
diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c
index ae56b111360..e877cf8ffcf 100644
--- a/source/blender/editors/space_statusbar/space_statusbar.c
+++ b/source/blender/editors/space_statusbar/space_statusbar.c
@@ -95,12 +95,11 @@ static void statusbar_keymap(struct wmKeyConfig *UNUSED(keyconf))
{
}
-static void statusbar_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void statusbar_header_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_SCREEN:
@@ -131,14 +130,11 @@ static void statusbar_header_region_listener(wmWindow *UNUSED(win),
}
}
-static void statusbar_header_region_message_subscribe(const bContext *UNUSED(C),
- WorkSpace *UNUSED(workspace),
- Scene *UNUSED(scene),
- bScreen *UNUSED(screen),
- ScrArea *UNUSED(area),
- ARegion *region,
- struct wmMsgBus *mbus)
+static void statusbar_header_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ ARegion *region = params->region;
+
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 0f5ac5abe1d..045305e0f5d 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -122,11 +122,10 @@ static SpaceLink *text_duplicate(SpaceLink *sl)
return (SpaceLink *)stextn;
}
-static void text_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- wmNotifier *wmn,
- Scene *UNUSED(scene))
+static void text_listener(const wmSpaceTypeListenerParams *params)
{
+ ScrArea *area = params->area;
+ wmNotifier *wmn = params->notifier;
SpaceText *st = area->spacedata.first;
/* context changes */
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 849766851aa..b38f92402b3 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -1010,13 +1010,16 @@ static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back)
BLI_rcti_size_y(&st->runtime.scroll_region_select));
UI_GetThemeColor3fv(TH_HILITE, col);
col[3] = 0.18f;
- UI_draw_roundbox_aa(true,
- st->runtime.scroll_region_select.xmin + 1,
- st->runtime.scroll_region_select.ymin,
- st->runtime.scroll_region_select.xmax - 1,
- st->runtime.scroll_region_select.ymax,
- rad,
- col);
+ UI_draw_roundbox_aa(
+ &(const rctf){
+ .xmin = st->runtime.scroll_region_select.xmin + 1,
+ .xmax = st->runtime.scroll_region_select.xmax - 1,
+ .ymin = st->runtime.scroll_region_select.ymin,
+ .ymax = st->runtime.scroll_region_select.ymax,
+ },
+ true,
+ rad,
+ col);
}
/*********************** draw documentation *******************************/
@@ -1180,7 +1183,14 @@ static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc
}
/* not needed but stands out nicer */
- UI_draw_box_shadow(220, x, y - boxh, x + boxw, y);
+ UI_draw_box_shadow(
+ &(const rctf){
+ .xmin = x,
+ .xmax = x + boxw,
+ .ymin = y - boxh,
+ .ymax = y,
+ },
+ 220);
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index dc357cdd355..6a7439df6e3 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -129,12 +129,11 @@ static void topbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *regi
ED_region_header_init(region);
}
-static void topbar_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void topbar_main_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_WM:
@@ -160,12 +159,11 @@ static void topbar_main_region_listener(wmWindow *UNUSED(win),
}
}
-static void topbar_header_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void topbar_header_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_WM:
@@ -191,14 +189,12 @@ static void topbar_header_listener(wmWindow *UNUSED(win),
}
}
-static void topbar_header_region_message_subscribe(const struct bContext *UNUSED(C),
- struct WorkSpace *workspace,
- struct Scene *UNUSED(scene),
- struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(area),
- struct ARegion *region,
- struct wmMsgBus *mbus)
+static void topbar_header_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ WorkSpace *workspace = params->workspace;
+ ARegion *region = params->region;
+
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index 3efdee9cec9..d4692f156d3 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -183,46 +183,20 @@ static void userpref_execute_region_init(wmWindowManager *wm, ARegion *region)
region->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y;
}
-static void userpref_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *UNUSED(region),
- wmNotifier *UNUSED(wmn),
- const Scene *UNUSED(scene))
+static void userpref_main_region_listener(const wmRegionListenerParams *UNUSED(params))
{
- /* context changes */
}
-static void userpref_header_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *UNUSED(region),
- wmNotifier *UNUSED(wmn),
- const Scene *UNUSED(scene))
+static void userpref_header_listener(const wmRegionListenerParams *UNUSED(params))
{
- /* context changes */
-#if 0
- switch (wmn->category) {
- default:
- break;
- }
-#endif
}
-static void userpref_navigation_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *UNUSED(region),
- wmNotifier *UNUSED(wmn),
- const Scene *UNUSED(scene))
+static void userpref_navigation_region_listener(const wmRegionListenerParams *UNUSED(params))
{
- /* context changes */
}
-static void userpref_execute_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *UNUSED(region),
- wmNotifier *UNUSED(wmn),
- const Scene *UNUSED(scene))
+static void userpref_execute_region_listener(const wmRegionListenerParams *UNUSED(params))
{
- /* context changes */
}
/* only called once, from space/spacetypes.c */
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 4c168c7a243..82cc499c729 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -469,16 +469,30 @@ static bool view3d_drop_in_main_region_poll(bContext *C, const wmEvent *event)
return ED_region_overlap_isect_any_xy(area, &event->x) == false;
}
-static ID *view3d_drop_id_in_main_region_poll_id(bContext *C,
- wmDrag *drag,
- const wmEvent *event,
- ID_Type id_type)
+static ID_Type view3d_drop_id_in_main_region_poll_get_id_type(bContext *C,
+ wmDrag *drag,
+ const wmEvent *event)
{
- ScrArea *area = CTX_wm_area(C);
+ const ScrArea *area = CTX_wm_area(C);
+
if (ED_region_overlap_isect_any_xy(area, &event->x)) {
- return NULL;
+ return 0;
+ }
+ if (!view3d_drop_in_main_region_poll(C, event)) {
+ return 0;
+ }
+
+ ID *local_id = WM_drag_get_local_ID(drag, 0);
+ if (local_id) {
+ return GS(local_id->name);
+ }
+
+ wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0);
+ if (asset_drag) {
+ return asset_drag->id_type;
}
- return view3d_drop_in_main_region_poll(C, event) ? WM_drag_get_local_ID(drag, id_type) : NULL;
+
+ return 0;
}
static bool view3d_drop_id_in_main_region_poll(bContext *C,
@@ -490,7 +504,7 @@ static bool view3d_drop_id_in_main_region_poll(bContext *C,
return false;
}
- return WM_drag_get_local_ID(drag, id_type) || WM_drag_get_asset_data(drag, id_type);
+ return WM_drag_is_ID_type(drag, id_type);
}
static bool view3d_ob_drop_poll(bContext *C,
@@ -522,9 +536,9 @@ static bool view3d_object_data_drop_poll(bContext *C,
const wmEvent *event,
const char **r_tooltip)
{
- ID *id = view3d_drop_id_in_main_region_poll_id(C, drag, event, 0);
- if (id != NULL) {
- if (BKE_object_obdata_to_type(id) != -1) {
+ ID_Type id_type = view3d_drop_id_in_main_region_poll_get_id_type(C, drag, event);
+ if (id_type) {
+ if (OB_DATA_SUPPORT_ID(id_type)) {
*r_tooltip = TIP_("Create object instance from object-data");
return true;
}
@@ -545,7 +559,7 @@ static bool view3d_ima_drop_poll(bContext *C,
return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE));
}
- return WM_drag_get_local_ID(drag, ID_IM) || WM_drag_get_asset_data(drag, ID_IM);
+ return WM_drag_is_ID_type(drag, ID_IM);
}
static bool view3d_ima_bg_is_camera_view(bContext *C)
@@ -629,7 +643,7 @@ static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop)
static void view3d_id_drop_copy_with_type(wmDrag *drag, wmDropBox *drop)
{
- ID *id = WM_drag_get_local_ID(drag, 0);
+ 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));
@@ -784,9 +798,13 @@ static void *view3d_main_region_duplicate(void *poin)
return NULL;
}
-static void view3d_main_region_listener(
- wmWindow *win, ScrArea *area, ARegion *region, wmNotifier *wmn, const Scene *scene)
+static void view3d_main_region_listener(const wmRegionListenerParams *params)
{
+ wmWindow *window = params->window;
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+ const Scene *scene = params->scene;
View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
wmGizmoMap *gzmap = region->gizmo_map;
@@ -1007,10 +1025,10 @@ static void view3d_main_region_listener(
ED_view3d_xr_shading_update(G_MAIN->wm.first, v3d, scene);
#endif
- ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(window);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
if (depsgraph) {
- ED_render_view3d_update(depsgraph, win, area, true);
+ ED_render_view3d_update(depsgraph, window, area, true);
}
}
ED_region_tag_redraw(region);
@@ -1048,14 +1066,13 @@ static void view3d_main_region_listener(
}
}
-static void view3d_main_region_message_subscribe(const struct bContext *C,
- struct WorkSpace *UNUSED(workspace),
- struct Scene *UNUSED(scene),
- struct bScreen *UNUSED(screen),
- struct ScrArea *area,
- struct ARegion *region,
- struct wmMsgBus *mbus)
+static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ const bContext *C = params->context;
+ ScrArea *area = params->area;
+ ARegion *region = params->region;
+
/* Developer note: there are many properties that impact 3D view drawing,
* so instead of subscribing to individual properties, just subscribe to types
* accepting some redundant redraws.
@@ -1170,12 +1187,11 @@ static void view3d_header_region_draw(const bContext *C, ARegion *region)
ED_region_header(C, region);
}
-static void view3d_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void view3d_header_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_SCENE:
@@ -1240,14 +1256,11 @@ static void view3d_header_region_listener(wmWindow *UNUSED(win),
#endif
}
-static void view3d_header_region_message_subscribe(const struct bContext *UNUSED(C),
- struct WorkSpace *UNUSED(workspace),
- struct Scene *UNUSED(scene),
- struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(area),
- struct ARegion *region,
- struct wmMsgBus *mbus)
+static void view3d_header_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
+ struct wmMsgBus *mbus = params->message_bus;
+ ARegion *region = params->region;
+
wmMsgParams_RNA msg_key_params = {{0}};
/* Only subscribe to types. */
@@ -1385,12 +1398,11 @@ static void view3d_buttons_region_layout(const bContext *C, ARegion *region)
ED_view3d_buttons_region_layout_ex(C, region, NULL);
}
-static void view3d_buttons_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(area),
- ARegion *region,
- wmNotifier *wmn,
- const Scene *UNUSED(scene))
+static void view3d_buttons_region_listener(const wmRegionListenerParams *params)
{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
@@ -1509,11 +1521,10 @@ static void view3d_tools_region_draw(const bContext *C, ARegion *region)
}
/* area (not region) level listener */
-static void space_view3d_listener(wmWindow *UNUSED(win),
- ScrArea *area,
- struct wmNotifier *wmn,
- Scene *UNUSED(scene))
+static void space_view3d_listener(const wmSpaceTypeListenerParams *params)
{
+ ScrArea *area = params->area;
+ wmNotifier *wmn = params->notifier;
View3D *v3d = area->spacedata.first;
/* context changes */
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 8ae0e3b94fe..3c970781448 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -723,15 +723,24 @@ static void drawviewborder(Scene *scene, Depsgraph *depsgraph, ARegion *region,
}
if (ca->flag & CAM_SHOW_SAFE_MARGINS) {
- UI_draw_safe_areas(
- shdr_pos, x1, x2, y1, y2, scene->safe_areas.title, scene->safe_areas.action);
+ UI_draw_safe_areas(shdr_pos,
+ &(const rctf){
+ .xmin = x1,
+ .xmax = x2,
+ .ymin = y1,
+ .ymax = y2,
+ },
+ scene->safe_areas.title,
+ scene->safe_areas.action);
if (ca->flag & CAM_SHOW_SAFE_CENTER) {
UI_draw_safe_areas(shdr_pos,
- x1,
- x2,
- y1,
- y2,
+ &(const rctf){
+ .xmin = x1,
+ .xmax = x2,
+ .ymin = y1,
+ .ymax = y2,
+ },
scene->safe_areas.title_center,
scene->safe_areas.action_center);
}
@@ -1953,13 +1962,13 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
/* XXX(jbakker): `do_color_management` should be controlled by the caller. Currently when doing a
* viewport render animation and saving to an 8bit file format, color management would be applied
* twice. Once here, and once when saving the saving to disk. In this case the Save As Render
- * option cannot be controlled either. But when doing an offscreen render you want to do the
+ * option cannot be controlled either. But when doing an off-screen render you want to do the
* color management here.
*
- * This option was added here to increase the performance when rendering for a playblast. When
- * using workbench the color differences haven't been reported as a bug. But users also use the
- * viewport rendering to render Eevee scenes. In the later situation the saved colors
- * are totally wrong. */
+ * This option was added here to increase the performance for quick view-port preview renders.
+ * When using workbench the color differences haven't been reported as a bug. But users also use
+ * the viewport rendering to render Eevee scenes. In the later situation the saved colors are
+ * totally wrong. */
const bool do_color_management = (ibuf->rect_float == NULL);
ED_view3d_draw_offscreen(depsgraph,
scene,
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
index 7a201d8841c..c145497fa09 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
@@ -45,14 +45,17 @@
/** \name View3D Navigation Gizmo Group
* \{ */
-/* Offset from screen edge. */
-#define GIZMO_OFFSET_FAC 1.2f
/* Size of main icon. */
-#define GIZMO_SIZE 80
-/* Factor for size of smaller button. */
-#define GIZMO_MINI_FAC 0.35f
-/* How much mini buttons offset from the primary. */
-#define GIZMO_MINI_OFFSET_FAC 0.38f
+#define GIZMO_SIZE U.gizmo_size_navigate_v3d
+
+/* Main gizmo offset from screen edges in unscaled pixels. */
+#define GIZMO_OFFSET 10.0f
+
+/* Width of smaller buttons in unscaled pixels. */
+#define GIZMO_MINI_SIZE 28.0f
+
+/* Margin around the smaller buttons. */
+#define GIZMO_MINI_OFFSET 2.0f
enum {
GZ_INDEX_MOVE = 0,
@@ -174,7 +177,7 @@ static void WIDGETGROUP_navigate_setup(const bContext *C, wmGizmoGroup *gzgroup)
}
/* may be overwritten later */
- gz->scale_basis = (GIZMO_SIZE * GIZMO_MINI_FAC) / 2;
+ gz->scale_basis = GIZMO_MINI_SIZE / 2.0f;
if (info->icon != 0) {
PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
RNA_property_enum_set(gz->ptr, prop, info->icon);
@@ -212,7 +215,7 @@ static void WIDGETGROUP_navigate_setup(const bContext *C, wmGizmoGroup *gzgroup)
{
wmGizmo *gz = navgroup->gz_array[GZ_INDEX_ROTATE];
- gz->scale_basis = GIZMO_SIZE / 2;
+ gz->scale_basis = GIZMO_SIZE / 2.0f;
const char mapping[6] = {
RV3D_VIEW_LEFT,
RV3D_VIEW_RIGHT,
@@ -263,9 +266,8 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
const bool show_navigate = (U.uiflag & USER_SHOW_GIZMO_NAVIGATE) != 0;
const bool show_rotate_gizmo = (U.mini_axis_type == USER_MINI_AXIS_TYPE_GIZMO);
- const float icon_size = GIZMO_SIZE;
- const float icon_offset = (icon_size * 0.52f) * GIZMO_OFFSET_FAC * UI_DPI_FAC;
- const float icon_offset_mini = icon_size * GIZMO_MINI_OFFSET_FAC * UI_DPI_FAC;
+ const float icon_offset = ((GIZMO_SIZE / 2.0f) + GIZMO_OFFSET) * UI_DPI_FAC;
+ const float icon_offset_mini = (GIZMO_MINI_SIZE + GIZMO_MINI_OFFSET) * UI_DPI_FAC;
const float co_rotate[2] = {
rect_visible->xmax - icon_offset,
rect_visible->ymax - icon_offset,
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
index 8f3d40584aa..4ac16e8fbe8 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -40,6 +40,8 @@
#include "GPU_matrix.h"
#include "GPU_state.h"
+#include "BLF_api.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -53,169 +55,34 @@
#include "view3d_intern.h"
-#define USE_AXIS_FONT
-#define USE_FADE_BACKGROUND
-
-#ifdef USE_AXIS_FONT
-# include "BLF_api.h"
-#endif
-
-#define DIAL_RESOLUTION 32
-
-/* Sizes of axis spheres containing XYZ characters. */
-#define AXIS_HANDLE_SIZE_FG 0.19f
-/* When pointing away from the view. */
-#define AXIS_HANDLE_SIZE_BG 0.15f
-/* How far axis handles are away from the center. */
-#define AXIS_HANDLE_OFFSET (1.0f - AXIS_HANDLE_SIZE_FG)
-
-struct AxisDrawInfo {
- /* Matrix is needed for screen-aligned font drawing. */
-#ifdef USE_AXIS_FONT
- float matrix_final[4][4];
-#endif
-#ifdef USE_FADE_BACKGROUND
- float color_bg[3];
-#endif
-};
-
-#ifndef USE_AXIS_FONT
-/**
- * \param viewmat_local_unit: is typically the 'rv3d->viewmatob'
- * copied into a 3x3 matrix and normalized.
- */
-static void draw_xyz_wire(
- uint pos_id, const float viewmat_local_unit[3][3], const float c[3], float size, int axis)
-{
- int line_type;
- float buffer[4][3];
- int n = 0;
-
- float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f};
- float dim = size * 0.1f;
- float dx[3], dy[3];
-
- dx[0] = dim;
- dx[1] = 0.0f;
- dx[2] = 0.0f;
- dy[0] = 0.0f;
- dy[1] = dim;
- dy[2] = 0.0f;
-
- switch (axis) {
- case 0: /* x axis */
- line_type = GPU_PRIM_LINES;
-
- /* bottom left to top right */
- negate_v3_v3(v1, dx);
- sub_v3_v3(v1, dy);
- copy_v3_v3(v2, dx);
- add_v3_v3(v2, dy);
-
- copy_v3_v3(buffer[n++], v1);
- copy_v3_v3(buffer[n++], v2);
-
- /* top left to bottom right */
- mul_v3_fl(dy, 2.0f);
- add_v3_v3(v1, dy);
- sub_v3_v3(v2, dy);
-
- copy_v3_v3(buffer[n++], v1);
- copy_v3_v3(buffer[n++], v2);
-
- break;
- case 1: /* y axis */
- line_type = GPU_PRIM_LINES;
-
- /* bottom left to top right */
- mul_v3_fl(dx, 0.75f);
- negate_v3_v3(v1, dx);
- sub_v3_v3(v1, dy);
- copy_v3_v3(v2, dx);
- add_v3_v3(v2, dy);
-
- copy_v3_v3(buffer[n++], v1);
- copy_v3_v3(buffer[n++], v2);
-
- /* top left to center */
- mul_v3_fl(dy, 2.0f);
- add_v3_v3(v1, dy);
- zero_v3(v2);
-
- copy_v3_v3(buffer[n++], v1);
- copy_v3_v3(buffer[n++], v2);
-
- break;
- case 2: /* z axis */
- line_type = GPU_PRIM_LINE_STRIP;
-
- /* start at top left */
- negate_v3_v3(v1, dx);
- add_v3_v3(v1, dy);
-
- copy_v3_v3(buffer[n++], v1);
-
- mul_v3_fl(dx, 2.0f);
- add_v3_v3(v1, dx);
+/* Radius of the entire background. */
+#define WIDGET_RADIUS ((U.gizmo_size_navigate_v3d / 2.0f) * UI_DPI_FAC)
- copy_v3_v3(buffer[n++], v1);
+/* Sizes of axis spheres containing XYZ characters in relation to above. */
+#define AXIS_HANDLE_SIZE 0.20f
- mul_v3_fl(dy, 2.0f);
- sub_v3_v3(v1, dx);
- sub_v3_v3(v1, dy);
+#define AXIS_LINE_WIDTH ((U.gizmo_size_navigate_v3d / 40.0f) * U.pixelsize)
+#define AXIS_RING_WIDTH ((U.gizmo_size_navigate_v3d / 60.0f) * U.pixelsize)
+#define AXIS_TEXT_SIZE (WIDGET_RADIUS * AXIS_HANDLE_SIZE * 1.25f)
- copy_v3_v3(buffer[n++], v1);
+/* distance within this from center is considered positive. */
+#define AXIS_DEPTH_BIAS 0.01f
- add_v3_v3(v1, dx);
-
- copy_v3_v3(buffer[n++], v1);
-
- break;
- default:
- BLI_assert(0);
- return;
- }
-
- for (int i = 0; i < n; i++) {
- mul_transposed_m3_v3((float(*)[3])viewmat_local_unit, buffer[i]);
- add_v3_v3(buffer[i], c);
- }
-
- immBegin(line_type, n);
- for (int i = 0; i < n; i++) {
- immVertex3fv(pos_id, buffer[i]);
- }
- immEnd();
-}
-#endif /* !USE_AXIS_FONT */
-
-/**
- * \param draw_info: Extra data needed for drawing.
- */
-static void axis_geom_draw(const wmGizmo *gz,
- const float color[4],
- const bool select,
- const struct AxisDrawInfo *draw_info)
+static void gizmo_axis_draw(const bContext *C, wmGizmo *gz)
{
- float viewport[4];
- GPU_viewport_size_get_f(viewport);
-
- GPUVertFormat *format = immVertexFormat();
- const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
-
struct {
float depth;
char index;
char axis;
+ char axis_opposite;
bool is_pos;
} axis_order[6] = {
- {-gz->matrix_offset[0][2], 0, 0, false},
- {+gz->matrix_offset[0][2], 1, 0, true},
- {-gz->matrix_offset[1][2], 2, 1, false},
- {+gz->matrix_offset[1][2], 3, 1, true},
- {-gz->matrix_offset[2][2], 4, 2, false},
- {+gz->matrix_offset[2][2], 5, 2, true},
+ {-gz->matrix_offset[0][2], 0, 0, 1, false},
+ {+gz->matrix_offset[0][2], 1, 0, 0, true},
+ {-gz->matrix_offset[1][2], 2, 1, 3, false},
+ {+gz->matrix_offset[1][2], 3, 1, 2, true},
+ {-gz->matrix_offset[2][2], 4, 2, 5, false},
+ {+gz->matrix_offset[2][2], 5, 2, 4, true},
};
int axis_align = -1;
@@ -226,25 +93,35 @@ static void axis_geom_draw(const wmGizmo *gz,
}
}
- /* Show backwards pointing highlight on-top (else we can't see it at all). */
- if ((select == false) && (gz->highlight_part > 0) && (axis_align != -1)) {
- if (axis_order[gz->highlight_part - 1].is_pos == false) {
- axis_order[gz->highlight_part - 1].depth = FLT_MAX;
- }
- }
-
qsort(&axis_order, ARRAY_SIZE(axis_order), sizeof(axis_order[0]), BLI_sortutil_cmp_float);
- static const float axis_highlight[4] = {1, 1, 1, 1};
- static const float axis_black[4] = {0, 0, 0, 1};
- static float axis_color[3][4];
+ /* When the cursor is over any of the gizmos (show circle backdrop). */
+ const bool is_active = ((gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0);
- const float axis_depth_bias = 0.01f;
- const float sphere_scale = 1.15f;
- /* TODO(fclem): Is there a way to get the widget radius? */
- const float widget_pix_size = 40.0f * U.dpi_fac;
+ /* Background color of the View3D, used to mix colors. */
+ float view_color[4];
+ ED_view3d_background_color_get(CTX_data_scene(C), CTX_wm_view3d(C), view_color);
+ view_color[3] = 1.0f;
+
+ float matrix_screen[4][4];
+ float matrix_unit[4][4];
+ unit_m4(matrix_unit);
+ WM_gizmo_calc_matrix_final_params(gz,
+ &((struct WM_GizmoMatrixParams){
+ .matrix_offset = matrix_unit,
+ }),
+ matrix_screen);
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix_screen);
+
+ GPUVertFormat *format = immVertexFormat();
+ const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ const uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+
+ static float axis_color[3][4];
-#ifdef USE_AXIS_FONT
struct {
float matrix[4][4];
float matrix_m3[3][3];
@@ -252,38 +129,29 @@ static void axis_geom_draw(const wmGizmo *gz,
int id;
} font;
- if (select == false) {
- font.id = blf_mono_font;
- BLF_disable(font.id, BLF_ROTATION | BLF_SHADOW | BLF_MATRIX | BLF_ASPECT | BLF_WORD_WRAP);
- BLF_color4fv(font.id, axis_black);
- BLF_size(font.id, 12 * U.dpi_fac, 72);
-
- /* The view matrix is used to position the text. */
- BLF_position(font.id, 0, 0, 0);
-
- /* Calculate the inverse of the (matrix_final * matrix_offset).
- * This allows us to use the final location, while reversing the rotation so fonts
- * show without any rotation. */
- float m3[3][3];
- float m3_offset[3][3];
- copy_m3_m4(m3, draw_info->matrix_final);
- copy_m3_m4(m3_offset, gz->matrix_offset);
- mul_m3_m3m3(m3, m3, m3_offset);
- copy_m3_m3(font.matrix_m3_invert, m3);
- invert_m3(m3);
- copy_m3_m3(font.matrix_m3, m3);
- copy_m4_m3(font.matrix, m3);
- }
-#endif
-
- /* When the cursor is over any of the gizmos (show circle backdrop). */
- const bool is_active = (color[3] != 0.0f);
-
- const float clip_range = gz->scale_final * sphere_scale;
- bool use_project_matrix = (clip_range >= -GPU_MATRIX_ORTHO_CLIP_NEAR_DEFAULT);
+ font.id = BLF_default();
+ BLF_disable(font.id, BLF_ROTATION | BLF_SHADOW | BLF_MATRIX | BLF_ASPECT | BLF_WORD_WRAP);
+ BLF_enable(font.id, BLF_BOLD);
+ BLF_size(font.id, AXIS_TEXT_SIZE, 72);
+ BLF_position(font.id, 0, 0, 0);
+
+ /* Calculate the inverse of the (matrix_final * matrix_offset).
+ * This allows us to use the final location, while reversing the rotation so fonts
+ * show without any rotation. */
+ float m3[3][3];
+ float m3_offset[3][3];
+ copy_m3_m4(m3, matrix_screen);
+ copy_m3_m4(m3_offset, gz->matrix_offset);
+ mul_m3_m3m3(m3, m3, m3_offset);
+ copy_m3_m3(font.matrix_m3_invert, m3);
+ invert_m3(m3);
+ copy_m3_m3(font.matrix_m3, m3);
+ copy_m4_m3(font.matrix, m3);
+
+ bool use_project_matrix = (gz->scale_final >= -GPU_MATRIX_ORTHO_CLIP_NEAR_DEFAULT);
if (use_project_matrix) {
GPU_matrix_push_projection();
- GPU_matrix_ortho_set_z(-clip_range, clip_range);
+ GPU_matrix_ortho_set_z(-gz->scale_final, gz->scale_final);
}
UI_draw_roundbox_corner_set(UI_CNR_ALL);
@@ -291,263 +159,161 @@ static void axis_geom_draw(const wmGizmo *gz,
/* Circle defining active area. */
if (is_active) {
- immUnbindProgram();
-
- float rad = widget_pix_size;
+ const float rad = WIDGET_RADIUS;
GPU_matrix_push();
GPU_matrix_scale_1f(1.0f / rad);
-
- UI_draw_roundbox_4fv(true, -rad, -rad, rad, rad, rad, color);
-
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = -rad,
+ .xmax = rad,
+ .ymin = -rad,
+ .ymax = rad,
+ },
+ true,
+ rad,
+ gz->color_hi);
GPU_matrix_pop();
-
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
}
- GPU_matrix_push();
GPU_matrix_mul(gz->matrix_offset);
for (int axis_index = 0; axis_index < ARRAY_SIZE(axis_order); axis_index++) {
const int index = axis_order[axis_index].index;
const int axis = axis_order[axis_index].axis;
const bool is_pos = axis_order[axis_index].is_pos;
- const bool is_highlight = index + 1 == gz->highlight_part;
+ const float depth = axis_order[axis_index].depth;
+ const bool is_behind = (depth <= (AXIS_DEPTH_BIAS * (is_pos ? -1 : 1)));
+ bool is_aligned_front = (axis_align != -1 && axis_align == axis && !is_behind);
+ bool is_aligned_back = (axis_align != -1 && axis_align == axis && is_behind);
+
+ const float v[3] = {0, 0, (1.0f - AXIS_HANDLE_SIZE) * (is_pos ? 1 : -1)};
+ const float v_final[3] = {v[(axis + 2) % 3], v[(axis + 1) % 3], v[axis]};
+
+ bool is_highlight = index + 1 == gz->highlight_part;
+ /* Check if highlight part is the other side when axis aligned. */
+ if (is_aligned_front && (axis_order[axis_index].axis_opposite + 1 == gz->highlight_part)) {
+ is_highlight = true;
+ }
UI_GetThemeColor3fv(TH_AXIS_X + axis, axis_color[axis]);
axis_color[axis][3] = 1.0f;
- const int index_z = axis;
- const int index_y = (axis + 1) % 3;
- const int index_x = (axis + 2) % 3;
-
- bool ok = true;
-
- /* Skip view align axis when selecting (allows to switch to opposite side). */
- if (select && ((axis_align == axis) && (gz->matrix_offset[axis][2] > 0.0f) == is_pos)) {
- ok = false;
+ /* Color that is full at front, but 50% view background when in back. */
+ float fading_color[4];
+ interp_v4_v4v4(fading_color, view_color, axis_color[axis], ((depth + 1) * 0.25) + 0.5);
+
+ /* Color that is midway between front and back. */
+ float middle_color[4];
+ interp_v4_v4v4(middle_color, view_color, axis_color[axis], 0.75f);
+
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ /* Axis Line. */
+ if (is_pos || axis_align != -1) {
+
+ /* Extend slightly to meet better at the center. */
+ float v_start[3] = {0.0f, 0.0f, 0.0f};
+ mul_v3_v3fl(v_start, v_final, -(AXIS_LINE_WIDTH / WIDGET_RADIUS * 0.66f));
+
+ /* Decrease length of line by ball radius. */
+ float v_end[3] = {0.0f, 0.0f, 0.0f};
+ mul_v3_v3fl(v_end, v_final, 1.0f - AXIS_HANDLE_SIZE);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR);
+ immUniform2fv("viewportSize", &viewport_size[2]);
+ immUniform1f("lineWidth", AXIS_LINE_WIDTH);
+ immBegin(GPU_PRIM_LINES, 2);
+ immAttr4fv(color_id, middle_color);
+ immVertex3fv(pos_id, v_start);
+ immAttr4fv(color_id, fading_color);
+ immVertex3fv(pos_id, v_end);
+ immEnd();
+ immUnbindProgram();
}
- if (ok) {
- /* Check aligned, since the front axis won't display in this case,
- * and we want to make sure all 3 axes have a character at all times. */
- const bool show_axis_char = (is_pos || (axis == axis_align));
- const float v[3] = {0, 0, AXIS_HANDLE_OFFSET * (is_pos ? 1 : -1)};
- const float v_final[3] = {v[index_x], v[index_y], v[index_z]};
- const float *color_current = is_highlight ? axis_highlight : axis_color[axis];
- float color_current_fade[4];
-
- /* Flip the faded state when axis aligned, since we're hiding the front-mode axis
- * otherwise we see the color for the back-most axis, which is useful for
- * click-to-rotate 180d but not useful to visualize.
- *
- * Use depth bias so axis-aligned views show the positive axis as being in-front.
- * This is a detail so primary axes show as dominant.
- */
- const bool is_pos_color = (axis_order[axis_index].depth >
- (axis_depth_bias * (is_pos ? -1 : 1)));
-
- if (select == false) {
-#ifdef USE_FADE_BACKGROUND
- interp_v3_v3v3(
- color_current_fade, draw_info->color_bg, color_current, is_highlight ? 1.0 : 0.5f);
- color_current_fade[3] = color_current[3];
-#else
- copy_v4_v4(color_current_fade, color_current);
- color_current_fade[3] *= 0.2;
-#endif
- }
- else {
- copy_v4_fl(color_current_fade, 1.0f);
- }
-
- /* Axis Line. */
- if (is_pos) {
- float v_start[3];
- immUnbindProgram();
-
- GPU_blend(GPU_BLEND_ALPHA);
-
- immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
- immUniform2fv("viewportSize", &viewport[2]);
- immUniform1f("lineWidth", 2.0f * U.pixelsize);
- immUniformColor4fv(is_pos_color ? color_current : color_current_fade);
- immBegin(GPU_PRIM_LINES, 2);
- if (axis_align == -1) {
- zero_v3(v_start);
+ /* Axis Ball. */
+ if (!is_aligned_back) {
+ float *inner_color = fading_color;
+ float *outline_color = fading_color;
+ float negative_color[4];
+ if (!is_pos) {
+ if (is_aligned_front) {
+ interp_v4_v4v4(
+ negative_color, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}, axis_color[axis], 0.5f);
+ negative_color[3] = MIN2(depth + 1, 1.0f);
+ outline_color = negative_color;
}
else {
- /* When axis aligned we don't draw the front most axis
- * (allowing us to switch to the opposite side).
- * In this case don't draw lines over axis pointing away from us
- * because it obscures character and looks noisy.
- */
- mul_v3_v3fl(v_start, v_final, 0.3f);
+ interp_v4_v4v4(negative_color, view_color, axis_color[axis], 0.25f);
+ negative_color[3] = MIN2(depth + 1, 1.0f);
+ inner_color = negative_color;
}
- immVertex3fv(pos_id, v_start);
- immVertex3fv(pos_id, v_final);
- immEnd();
-
- immUnbindProgram();
-
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
}
- /* Axis Ball. */
-#ifdef USE_AXIS_FONT
- if (select == false) {
- immUnbindProgram();
-
- GPU_matrix_push();
- GPU_matrix_translate_3fv(v_final);
- GPU_matrix_mul(font.matrix);
-
- float rad = widget_pix_size * (is_pos ? AXIS_HANDLE_SIZE_FG : AXIS_HANDLE_SIZE_BG);
-
- /* Black outlines for negative axis balls, otherwise they can be hard to see since
- * they use a faded color which can be similar to the circle backdrop in tone. */
- if (is_active && !is_highlight && !is_pos && !select && !(axis_align == axis)) {
- static const float axis_black_faded[4] = {0.0f, 0.0f, 0.0f, 0.2f};
- float outline = rad * sphere_scale;
- UI_draw_roundbox_4fv(
- true, -outline, -outline, outline, outline, outline, axis_black_faded);
- }
-
- const float *col = is_pos_color ? color_current : color_current_fade;
- UI_draw_roundbox_4fv(true, -rad, -rad, rad, rad, rad, col);
-
- GPU_matrix_pop();
-
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- }
- else
-#endif
- {
- GPU_matrix_push();
- GPU_matrix_translate_3fv(v_final);
- GPU_matrix_scale_1f(is_pos ? AXIS_HANDLE_SIZE_FG : AXIS_HANDLE_SIZE_BG);
-
- GPUBatch *sphere = GPU_batch_preset_sphere(0);
- GPU_batch_program_set_builtin(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
-
- /* Black outlines for negative axis balls, otherwise they can be hard to see since
- * they use a faded color which can be similar to the circle backdrop in tone. */
- if (is_active && !is_highlight && !is_pos && !select && !(axis_align == axis)) {
- static const float axis_black_faded[4] = {0, 0, 0, 0.2f};
- GPU_matrix_scale_1f(sphere_scale);
- GPU_batch_uniform_4fv(sphere, "color", axis_black_faded);
- GPU_batch_draw(sphere);
- GPU_matrix_scale_1f(1.0 / sphere_scale);
- }
+ GPU_matrix_push();
+ GPU_matrix_translate_3fv(v_final);
+ GPU_matrix_mul(font.matrix);
+ /* Size change from back to front: 0.92f - 1.08f. */
+ float scale = ((depth + 1) * 0.08f) + 0.92f;
+ const float rad = WIDGET_RADIUS * AXIS_HANDLE_SIZE * scale;
+ UI_draw_roundbox_4fv_ex(
+ &(const rctf){
+ .xmin = -rad,
+ .xmax = rad,
+ .ymin = -rad,
+ .ymax = rad,
+ },
+ inner_color,
+ NULL,
+ 0.0f,
+ outline_color,
+ AXIS_RING_WIDTH,
+ rad);
+ GPU_matrix_pop();
+ }
- GPU_batch_program_set_builtin(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
- GPU_batch_uniform_4fv(sphere, "color", is_pos_color ? color_current : color_current_fade);
- GPU_batch_draw(sphere);
- GPU_matrix_pop();
+ /* Axis XYZ Character. */
+ if ((is_pos || is_highlight || (axis == axis_align)) && !is_aligned_back) {
+ float axis_str_width, axis_string_height;
+ char axis_str[3] = {'X' + axis, 0, 0};
+ if (!is_pos) {
+ axis_str[0] = '-';
+ axis_str[1] = 'X' + axis;
}
-
- /* Axis XYZ Character. */
- if (show_axis_char && (select == false)) {
-#ifdef USE_AXIS_FONT
- float axis_str_size[2] = {0};
- const char axis_str[2] = {'X' + axis, 0};
- BLF_width_and_height(font.id, axis_str, 2, &axis_str_size[0], &axis_str_size[1]);
-
- /* Calculate pixel aligned location, without this text draws fuzzy. */
- float v_final_px[3];
- mul_v3_m3v3(v_final_px, font.matrix_m3_invert, v_final);
- /* Center the test and pixel align, it's important to round once
- * otherwise the characters are noticeably not-centered.
- * If this wasn't an issue we could use #BLF_position to place the text. */
- v_final_px[0] = roundf(v_final_px[0] - (axis_str_size[0] / 2.0f));
- v_final_px[1] = roundf(v_final_px[1] - (axis_str_size[1] / 2.0f));
- mul_m3_v3(font.matrix_m3, v_final_px);
-
- immUnbindProgram();
-
- GPU_matrix_push();
- GPU_matrix_translate_3fv(v_final_px);
- GPU_matrix_mul(font.matrix);
-
- BLF_draw_ascii(font.id, axis_str, 2);
- GPU_blend(GPU_BLEND_ALPHA); /* XXX, blf disables */
- GPU_matrix_pop();
-
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
-#else
- immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- GPU_line_width(1.0f);
- float m3[3][3];
- copy_m3_m4(m3, gz->matrix_offset);
- immUniformColor4fv(axis_black);
- draw_xyz_wire(pos_id, m3, v_final, 1.0, axis);
- immUnbindProgram();
-#endif
+ BLF_width_and_height(font.id, axis_str, 3, &axis_str_width, &axis_string_height);
+
+ /* Calculate pixel-aligned location, without this text draws fuzzy. */
+ float v_final_px[3];
+ mul_v3_m3v3(v_final_px, font.matrix_m3_invert, v_final);
+ /* Center the text and pixel align, it's important to round once
+ * otherwise the characters are noticeably not-centered.
+ * If this wasn't an issue we could use #BLF_position to place the text. */
+ v_final_px[0] = roundf(v_final_px[0] - (axis_str_width * (is_pos ? 0.5f : 0.55f)));
+ v_final_px[1] = roundf(v_final_px[1] - (axis_string_height / 2.0f));
+ mul_m3_v3(font.matrix_m3, v_final_px);
+ GPU_matrix_push();
+ GPU_matrix_translate_3fv(v_final_px);
+ GPU_matrix_mul(font.matrix);
+ float text_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ if (!is_highlight) {
+ zero_v4(text_color);
+ text_color[3] = is_active ? 1.0f : 0.9f;
}
+ BLF_color4fv(font.id, text_color);
+ BLF_draw_ascii(font.id, axis_str, 2);
+ GPU_matrix_pop();
}
}
- GPU_matrix_pop();
- immUnbindProgram();
-
if (use_project_matrix) {
GPU_matrix_pop_projection();
}
-}
-
-static void axis3d_draw_intern(const bContext *C,
- wmGizmo *gz,
- const bool select,
- const bool highlight)
-{
- const float *color = highlight ? gz->color_hi : gz->color;
- float matrix_final[4][4];
- float matrix_unit[4][4];
-
- unit_m4(matrix_unit);
-
- WM_gizmo_calc_matrix_final_params(gz,
- &((struct WM_GizmoMatrixParams){
- .matrix_offset = matrix_unit,
- }),
- matrix_final);
-
- GPU_matrix_push();
- GPU_matrix_mul(matrix_final);
-
- struct AxisDrawInfo draw_info;
-#ifdef USE_AXIS_FONT
- if (select == false) {
- copy_m4_m4(draw_info.matrix_final, matrix_final);
- }
-#endif
-#ifdef USE_FADE_BACKGROUND
- if (select == false) {
- ED_view3d_background_color_get(CTX_data_scene(C), CTX_wm_view3d(C), draw_info.color_bg);
- }
-#else
- UNUSED_VARS(C);
-#endif
-
- GPU_blend(GPU_BLEND_ALPHA);
- axis_geom_draw(gz, color, select, &draw_info);
GPU_blend(GPU_BLEND_NONE);
+ BLF_disable(font.id, BLF_BOLD);
GPU_matrix_pop();
}
-static void gizmo_axis_draw(const bContext *C, wmGizmo *gz)
-{
- const bool is_modal = gz->state & WM_GIZMO_STATE_MODAL;
- const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
-
- (void)is_modal;
-
- GPU_blend(GPU_BLEND_ALPHA);
- axis3d_draw_intern(C, gz, false, is_highlight);
- GPU_blend(GPU_BLEND_NONE);
-}
-
static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
{
float point_local[2] = {UNPACK2(mval)};
@@ -601,12 +367,19 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
return -1;
}
-static int gizmo_axis_cursor_get(wmGizmo *gz)
+static int gizmo_axis_cursor_get(wmGizmo *UNUSED(gz))
{
- if (gz->highlight_part > 0) {
- return WM_CURSOR_EDIT;
- }
- return WM_CURSOR_NSEW_SCROLL;
+ return WM_CURSOR_DEFAULT;
+}
+
+static void gizmo_axis_screen_bounds_get(bContext *C, wmGizmo *gz, rcti *r_bounding_box)
+{
+ ScrArea *area = CTX_wm_area(C);
+ const float rad = WIDGET_RADIUS;
+ r_bounding_box->xmin = gz->matrix_basis[3][0] + area->totrct.xmin - rad;
+ r_bounding_box->ymin = gz->matrix_basis[3][1] + area->totrct.ymin - rad;
+ r_bounding_box->xmax = r_bounding_box->xmin + rad;
+ r_bounding_box->ymax = r_bounding_box->ymin + rad;
}
void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt)
@@ -618,6 +391,7 @@ void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt)
gzt->draw = gizmo_axis_draw;
gzt->test_select = gizmo_axis_test_select;
gzt->cursor_get = gizmo_axis_cursor_get;
+ gzt->screen_bounds_get = gizmo_axis_screen_bounds_get;
gzt->struct_size = sizeof(wmGizmo);
}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 35ec4de5077..9ee6e44f825 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -2494,8 +2494,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
}
/* Pass-through allows tweaks
- * FINISHED to signal one operator worked
- * */
+ * FINISHED to signal one operator worked. */
if (retval) {
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 2b7b8255068..a6a77ecd5f7 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -224,13 +224,11 @@ void view3d_region_operator_needs_opengl(wmWindow *UNUSED(win), ARegion *region)
*/
void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
{
- float viewdist;
-
if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
return;
}
- viewdist = rv3d->dist;
+ float viewdist = rv3d->dist;
/* special exception for ortho camera (viewdist isnt used for perspective cameras) */
if (dist != 0.0f) {
@@ -248,7 +246,6 @@ bool ED_view3d_context_activate(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
- ARegion *region;
/* area can be NULL when called from python */
if (area == NULL || area->spacetype != SPACE_VIEW3D) {
@@ -259,7 +256,7 @@ bool ED_view3d_context_activate(bContext *C)
return false;
}
- region = BKE_area_find_region_active_win(area);
+ ARegion *region = BKE_area_find_region_active_win(area);
if (region == NULL) {
return false;
}
@@ -282,9 +279,7 @@ void ED_view3d_clipping_calc_from_boundbox(float clip[4][4],
const BoundBox *bb,
const bool is_flip)
{
- int val;
-
- for (val = 0; val < 4; val++) {
+ for (int val = 0; val < 4; val++) {
normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
if (UNLIKELY(is_flip)) {
negate_v3(clip[val]);
@@ -752,14 +747,12 @@ bool ED_view3d_camera_lock_autokey(View3D *v3d,
static void view3d_boxview_clip(ScrArea *area)
{
- ARegion *region;
BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
float clip[6][4];
float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
- int val;
/* create bounding box */
- for (region = area->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
@@ -794,7 +787,7 @@ static void view3d_boxview_clip(ScrArea *area)
}
}
- for (val = 0; val < 8; val++) {
+ for (int val = 0; val < 8; val++) {
if (ELEM(val, 0, 3, 4, 7)) {
bb->vec[val][0] = -x1 - ofs[0];
}
@@ -826,12 +819,12 @@ static void view3d_boxview_clip(ScrArea *area)
normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]);
/* then plane equations */
- for (val = 0; val < 6; val++) {
+ for (int val = 0; val < 6; val++) {
clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]);
}
/* create bounding box */
- for (region = area->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
@@ -950,11 +943,10 @@ void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
{
ARegion *region_sync = NULL;
RegionView3D *rv3d = region->regiondata;
- short viewlock;
/* this function copies flags from the first of the 3 other quadview
* regions to the 2 other, so it assumes this is the region whose
* properties are always being edited, weak */
- viewlock = rv3d->viewlock;
+ short viewlock = rv3d->viewlock;
if ((viewlock & RV3D_LOCK_ROTATION) == 0) {
do_clip = (viewlock & RV3D_BOXCLIP) != 0;
@@ -1015,10 +1007,7 @@ void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
static float view_autodist_depth_margin(ARegion *region, const int mval[2], int margin)
{
- ViewDepths depth_temp = {0};
rcti rect;
- float depth_close;
-
if (margin == 0) {
/* Get Z Depths, needed for perspective, nice for ortho */
rect.xmin = mval[0];
@@ -1030,8 +1019,9 @@ static float view_autodist_depth_margin(ARegion *region, const int mval[2], int
BLI_rcti_init_pt_radius(&rect, mval, margin);
}
+ ViewDepths depth_temp = {0};
view3d_update_depths_rect(region, &depth_temp, &rect);
- depth_close = view3d_depth_near(&depth_temp);
+ float depth_close = view3d_depth_near(&depth_temp);
MEM_SAFE_FREE(depth_temp.depths);
return depth_close;
}
@@ -1053,14 +1043,13 @@ bool ED_view3d_autodist(Depsgraph *depsgraph,
{
float depth_close;
int margin_arr[] = {0, 2, 4};
- int i;
bool depth_ok = false;
/* Get Z Depths, needed for perspective, nice for ortho */
ED_view3d_draw_depth(depsgraph, region, v3d, alphaoverride);
/* Attempt with low margin's first */
- i = 0;
+ int i = 0;
do {
depth_close = view_autodist_depth_margin(region, mval, margin_arr[i++] * U.pixelsize);
depth_ok = (depth_close != FLT_MAX);
@@ -1104,9 +1093,8 @@ bool ED_view3d_autodist_simple(ARegion *region,
int margin,
const float *force_depth)
{
- float depth;
-
/* Get Z Depths, needed for perspective, nice for ortho */
+ float depth;
if (force_depth) {
depth = *force_depth;
}
@@ -1237,7 +1225,6 @@ float ED_view3d_radius_to_dist(const View3D *v3d,
}
else {
float lens, sensor_size, zoom;
- float angle;
if (persp == RV3D_CAMOB) {
CameraParams params;
@@ -1259,7 +1246,7 @@ float ED_view3d_radius_to_dist(const View3D *v3d,
zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
}
- angle = focallength_to_fov(lens, sensor_size);
+ float angle = focallength_to_fov(lens, sensor_size);
/* zoom influences lens, correct this by scaling the angle as a distance
* (by the zoom-level) */
@@ -1319,14 +1306,13 @@ float ED_view3d_offset_distance(const float mat[4][4],
{
float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f};
- float dist;
mul_m4_v4(mat, pos);
add_v3_v3(pos, ofs);
mul_m4_v4(mat, dir);
normalize_v3(dir);
- dist = dot_v3v3(pos, dir);
+ float dist = dot_v3v3(pos, dir);
if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) {
dist = fallback_dist;
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 78d3f213102..09d3a991cc1 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -58,6 +58,10 @@
static void drawObjectConstraint(TransInfo *t);
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3])
{
unit_m3(r_pmtx);
@@ -79,7 +83,6 @@ static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3])
mul_m3_m3m3(r_pmtx, t->spacemtx, mat);
}
-/* ************************** CONSTRAINTS ************************* */
#define CONSTRAIN_EPSILON 0.0001f
static void constraint_plane_calc(TransInfo *t, float r_plane[4])
@@ -369,14 +372,13 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3])
add_v3_v3v3(out, in, vec);
}
-/*
+/**
* Generic callback for constant spatial constraints applied to linear motion
*
- * The IN vector in projected into the constrained space and then further
+ * The `in` vector in projected into the constrained space and then further
* projected along the view vector.
* (in perspective mode, the view vector is relative to the position on screen)
*/
-
static void applyAxisConstraintVec(
TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in[3], float out[3])
{
@@ -448,17 +450,16 @@ static void applyAxisConstraintVec(
}
}
-/*
+/**
* Generic callback for object based spatial constraints applied to linear motion
*
* At first, the following is applied without orientation
* The IN vector in projected into the constrained space and then further
* projected along the view vector.
- * (in perspective mode, the view vector is relative to the position on screen)
+ * (in perspective mode, the view vector is relative to the position on screen).
*
* Further down, that vector is mapped to each data's space.
*/
-
static void applyObjectConstraintVec(
TransInfo *t, TransDataContainer *tc, TransData *td, const float in[3], float out[3])
{
@@ -478,10 +479,9 @@ static void applyObjectConstraintVec(
}
}
-/*
- * Generic callback for constant spatial constraints applied to resize motion
+/**
+ * Generic callback for constant spatial constraints applied to resize motion.
*/
-
static void applyAxisConstraintSize(TransInfo *t,
TransDataContainer *UNUSED(tc),
TransData *td,
@@ -505,10 +505,9 @@ static void applyAxisConstraintSize(TransInfo *t,
}
}
-/*
- * Callback for object based spatial constraints applied to resize motion
+/**
+ * Callback for object based spatial constraints applied to resize motion.
*/
-
static void applyObjectConstraintSize(TransInfo *t,
TransDataContainer *tc,
TransData *td,
@@ -568,15 +567,15 @@ static void constraints_rotation_imp(TransInfo *t,
}
}
-/*
+/**
* Generic callback for constant spatial constraints applied to rotations
*
- * The rotation axis is copied into VEC.
+ * The rotation axis is copied into `vec`.
*
* In the case of single axis constraints, the rotation axis is directly the one constrained to.
* For planar constraints (2 axis), the rotation axis is the normal of the plane.
*
- * The following only applies when CON_NOFLIP is not set.
+ * The following only applies when #CON_NOFLIP is not set.
* The vector is then modified to always point away from the screen (in global space)
* This insures that the rotation is always logically following the mouse.
* (ie: not doing counterclockwise rotations when the mouse moves clockwise).
@@ -589,15 +588,15 @@ static void applyAxisConstraintRot(
}
}
-/*
+/**
* Callback for object based spatial constraints applied to rotations
*
- * The rotation axis is copied into VEC.
+ * The rotation axis is copied into `vec`.
*
* In the case of single axis constraints, the rotation axis is directly the one constrained to.
* For planar constraints (2 axis), the rotation axis is the normal of the plane.
*
- * The following only applies when CON_NOFLIP is not set.
+ * The following only applies when #CON_NOFLIP is not set.
* The vector is then modified to always point away from the screen (in global space)
* This insures that the rotation is always logically following the mouse.
* (ie: not doing counterclockwise rotations when the mouse moves clockwise).
@@ -628,7 +627,11 @@ static void applyObjectConstraintRot(
}
}
-/*--------------------- INTERNAL SETUP CALLS ------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Setup Calls
+ * \{ */
void setConstraint(TransInfo *t, int mode, const char text[])
{
@@ -663,7 +666,7 @@ void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[])
void setLocalConstraint(TransInfo *t, int mode, const char text[])
{
- if (t->flag & T_EDIT) {
+ if ((t->flag & T_EDIT) || t->data_len_all == 1) {
/* Although in edit-mode each object has its local space, use the
* orientation of the active object. */
setConstraint(t, mode, text);
@@ -673,10 +676,10 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
}
}
-/*
+/**
* Set the constraint according to the user defined orientation
*
- * ftext is a format string passed to BLI_snprintf. It will add the name of
+ * `ftext` is a format string passed to #BLI_snprintf. It will add the name of
* the orientation where %s is (logically).
*/
void setUserConstraint(TransInfo *t, int mode, const char ftext[])
@@ -691,40 +694,35 @@ void setUserConstraint(TransInfo *t, int mode, const char ftext[])
const char *spacename = transform_orientations_spacename_get(t, orientation);
BLI_snprintf(text, sizeof(text), ftext, spacename);
- if (t->modifiers & (MOD_CONSTRAINT_SELECT | MOD_CONSTRAINT_PLANE)) {
- /* Force the orientation of the active object.
- * Although possible, it is not convenient to use the local or axis constraint
- * with the modifier to select constraint.
- * This also follows the convention of older versions. */
- setConstraint(t, mode, text);
- }
- else {
- switch (orientation) {
- case V3D_ORIENT_LOCAL:
- setLocalConstraint(t, mode, text);
- break;
- case V3D_ORIENT_NORMAL:
- if (checkUseAxisMatrix(t)) {
- setAxisMatrixConstraint(t, mode, text);
- break;
- }
- ATTR_FALLTHROUGH;
- case V3D_ORIENT_GLOBAL:
- case V3D_ORIENT_VIEW:
- case V3D_ORIENT_CURSOR:
- case V3D_ORIENT_GIMBAL:
- case V3D_ORIENT_CUSTOM_MATRIX:
- case V3D_ORIENT_CUSTOM:
- default: {
- setConstraint(t, mode, text);
+ switch (orientation) {
+ case V3D_ORIENT_LOCAL:
+ setLocalConstraint(t, mode, text);
+ break;
+ case V3D_ORIENT_NORMAL:
+ if (checkUseAxisMatrix(t)) {
+ setAxisMatrixConstraint(t, mode, text);
break;
}
+ ATTR_FALLTHROUGH;
+ case V3D_ORIENT_GLOBAL:
+ case V3D_ORIENT_VIEW:
+ case V3D_ORIENT_CURSOR:
+ case V3D_ORIENT_GIMBAL:
+ case V3D_ORIENT_CUSTOM_MATRIX:
+ case V3D_ORIENT_CUSTOM:
+ default: {
+ setConstraint(t, mode, text);
+ break;
}
}
t->con.mode |= CON_USER;
}
-/*----------------- DRAWING CONSTRAINTS -------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing Constraints
+ * \{ */
void drawConstraint(TransInfo *t)
{
@@ -925,7 +923,11 @@ static void drawObjectConstraint(TransInfo *t)
}
}
-/*--------------------- START / STOP CONSTRAINTS ---------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Start / Stop Constraints
+ * \{ */
void startConstraint(TransInfo *t)
{
@@ -946,7 +948,11 @@ void stopConstraint(TransInfo *t)
t->num.idx_max = t->idx_max;
}
-/*------------------------- MMB Select -------------------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Middle Mouse Button Select
+ * \{ */
void initSelectConstraint(TransInfo *t)
{
@@ -1093,7 +1099,11 @@ void setNearestAxis(TransInfo *t)
projection_matrix_calc(t, t->con.pmtx);
}
-/*-------------- HELPER FUNCTIONS ----------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Helper Functions
+ * \{ */
int constraintModeToIndex(const TransInfo *t)
{
@@ -1134,14 +1144,13 @@ bool isLockConstraint(TransInfo *t)
return false;
}
-/*
+/**
* Returns the dimension of the constraint space.
*
* For that reason, the flags always needs to be set to properly evaluate here,
- * even if they aren't actually used in the callback function. (Which could happen
- * for weird constraints not yet designed. Along a path for example.)
+ * even if they aren't actually used in the callback function.
+ * (Which could happen for weird constraints not yet designed. Along a path for example.)
*/
-
int getConstraintSpaceDimension(TransInfo *t)
{
int n = 0;
@@ -1159,11 +1168,12 @@ int getConstraintSpaceDimension(TransInfo *t)
}
return n;
- /*
- * Someone willing to do it cryptically could do the following instead:
+ /* Someone willing to do it cryptically could do the following instead:
*
- * return t->con & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
+ * `return t->con & (CON_AXIS0|CON_AXIS1|CON_AXIS2);`
*
* Based on the assumptions that the axis flags are one after the other and start at 1
*/
}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index 0a742ec4470..17362ae65e5 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -135,7 +135,7 @@ static void createTransGPencil_curves(bContext *C,
continue;
}
/* Check if the color is editable. */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) {
continue;
}
/* Check if stroke has an editcurve */
@@ -242,7 +242,7 @@ static void createTransGPencil_curves(bContext *C,
}
/* Calculate difference matrix. */
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
copy_m3_m4(mtx, diff_mat);
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
@@ -263,7 +263,7 @@ static void createTransGPencil_curves(bContext *C,
continue;
}
/* Check if the color is editable. */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) {
continue;
}
/* Check if stroke has an editcurve */
@@ -436,7 +436,7 @@ static void createTransGPencil_strokes(bContext *C,
continue;
}
/* Check if the color is editable. */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) {
continue;
}
@@ -507,7 +507,7 @@ static void createTransGPencil_strokes(bContext *C,
}
/* Calculate difference matrix. */
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
/* Undo matrix. */
invert_m4_m4(inverse_diff_mat, diff_mat);
@@ -551,7 +551,7 @@ static void createTransGPencil_strokes(bContext *C,
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) {
continue;
}
/* What we need to include depends on proportional editing settings... */
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index b3bd6b31879..ce74c5f5a36 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -251,29 +251,55 @@ void transform_convert_mesh_islanddata_free(struct TransIslandData *island_data)
*
* \{ */
-static bool bmesh_test_dist_add(BMVert *v,
- BMVert *v_other,
+/* Propagate distance from v1 and v2 to v0. */
+static bool bmesh_test_dist_add(BMVert *v0,
+ BMVert *v1,
+ BMVert *v2,
float *dists,
- const float *dists_prev,
/* optionally track original index */
int *index,
- const int *index_prev,
const float mtx[3][3])
{
- if ((BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) &&
- (BM_elem_flag_test(v_other, BM_ELEM_HIDDEN) == 0)) {
- const int i = BM_elem_index_get(v);
- const int i_other = BM_elem_index_get(v_other);
- float vec[3];
- float dist_other;
- sub_v3_v3v3(vec, v->co, v_other->co);
- mul_m3_v3(mtx, vec);
-
- dist_other = dists_prev[i] + len_v3(vec);
- if (dist_other < dists[i_other]) {
- dists[i_other] = dist_other;
+ if ((BM_elem_flag_test(v0, BM_ELEM_SELECT) == 0) &&
+ (BM_elem_flag_test(v0, BM_ELEM_HIDDEN) == 0)) {
+ const int i0 = BM_elem_index_get(v0);
+ const int i1 = BM_elem_index_get(v1);
+
+ BLI_assert(dists[i1] != FLT_MAX);
+ if (dists[i0] <= dists[i1]) {
+ return false;
+ }
+
+ float dist0;
+
+ if (v2) {
+ /* Distance across triangle. */
+ const int i2 = BM_elem_index_get(v2);
+ BLI_assert(dists[i2] != FLT_MAX);
+ if (dists[i0] <= dists[i2]) {
+ return false;
+ }
+
+ float vm0[3], vm1[3], vm2[3];
+ mul_v3_m3v3(vm0, mtx, v0->co);
+ mul_v3_m3v3(vm1, mtx, v1->co);
+ mul_v3_m3v3(vm2, mtx, v2->co);
+
+ dist0 = geodesic_distance_propagate_across_triangle(vm0, vm1, vm2, dists[i1], dists[i2]);
+ }
+ else {
+ /* Distance along edge. */
+ float vec[3];
+ sub_v3_v3v3(vec, v1->co, v0->co);
+ mul_m3_v3(mtx, vec);
+
+ dist0 = dists[i1] + len_v3(vec);
+ }
+
+ if (dist0 < dists[i0]) {
+ dists[i0] = dist0;
if (index != NULL) {
- index[i_other] = index_prev[i];
+ index[i0] = index[i1];
}
return true;
}
@@ -292,15 +318,16 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
float *dists,
int *index)
{
- BLI_LINKSTACK_DECLARE(queue, BMVert *);
+ BLI_LINKSTACK_DECLARE(queue, BMEdge *);
- /* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */
- BLI_LINKSTACK_DECLARE(queue_next, BMVert *);
+ /* any BM_ELEM_TAG'd edge is in 'queue_next', so we don't add in twice */
+ BLI_LINKSTACK_DECLARE(queue_next, BMEdge *);
BLI_LINKSTACK_INIT(queue);
BLI_LINKSTACK_INIT(queue_next);
{
+ /* Set indexes and initial distances for selected vertices. */
BMIter viter;
BMVert *v;
int i;
@@ -308,7 +335,6 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
float dist;
BM_elem_index_set(v, i); /* set_inline */
- BM_elem_flag_disable(v, BM_ELEM_TAG);
if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
dist = FLT_MAX;
@@ -317,7 +343,6 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
}
}
else {
- BLI_LINKSTACK_PUSH(queue, v);
dist = 0.0f;
if (index != NULL) {
index[i] = i;
@@ -329,103 +354,99 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
bm->elem_index_dirty &= ~BM_VERT;
}
- /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */
- float *dists_prev = MEM_dupallocN(dists);
- int *index_prev = MEM_dupallocN(index); /* may be NULL */
+ {
+ /* Add edges with at least one selected vertex to the queue. */
+ BMIter eiter;
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ BMVert *v1 = e->v1;
+ BMVert *v2 = e->v2;
+ int i1 = BM_elem_index_get(v1);
+ int i2 = BM_elem_index_get(v2);
+
+ if (dists[i1] != FLT_MAX || dists[i2] != FLT_MAX) {
+ BLI_LINKSTACK_PUSH(queue, e);
+ }
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ }
+ }
do {
- BMVert *v;
- LinkNode *lnk;
-
- /* this is correct but slow to do each iteration,
- * instead sync the dist's while clearing BM_ELEM_TAG (below) */
-#if 0
- memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
-#endif
-
- while ((v = BLI_LINKSTACK_POP(queue))) {
- BLI_assert(dists[BM_elem_index_get(v)] != FLT_MAX);
-
- /* connected edge-verts */
- if (v->e != NULL) {
- BMEdge *e_iter, *e_first;
-
- e_iter = e_first = v->e;
-
- /* would normally use BM_EDGES_OF_VERT, but this runs so often,
- * its faster to iterate on the data directly */
- do {
-
- if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) {
+ BMEdge *e;
+
+ while ((e = BLI_LINKSTACK_POP(queue))) {
+ BMVert *v1 = e->v1;
+ BMVert *v2 = e->v2;
+ int i1 = BM_elem_index_get(v1);
+ int i2 = BM_elem_index_get(v2);
+
+ if (e->l == NULL || (dists[i1] == FLT_MAX || dists[i2] == FLT_MAX)) {
+ /* Propagate along edge from vertex with smallest to largest distance. */
+ if (dists[i1] > dists[i2]) {
+ SWAP(int, i1, i2);
+ SWAP(BMVert *, v1, v2);
+ }
- /* edge distance */
- {
- BMVert *v_other = BM_edge_other_vert(e_iter, v);
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
- BM_elem_flag_enable(v_other, BM_ELEM_TAG);
- BLI_LINKSTACK_PUSH(queue_next, v_other);
- }
- }
+ if (bmesh_test_dist_add(v2, v1, NULL, dists, index, mtx)) {
+ /* Add adjacent loose edges to the queue, or all edges if this is a loose edge.
+ * Other edges are handled by propagation across edges below. */
+ BMEdge *e_other;
+ BMIter eiter;
+ BM_ITER_ELEM (e_other, &eiter, v2, BM_EDGES_OF_VERT) {
+ if (e_other != e && BM_elem_flag_test(e_other, BM_ELEM_TAG) == 0 &&
+ (e->l == NULL || e_other->l == NULL)) {
+ BM_elem_flag_enable(e_other, BM_ELEM_TAG);
+ BLI_LINKSTACK_PUSH(queue_next, e_other);
}
+ }
+ }
+ }
- /* face distance */
- if (e_iter->l) {
- BMLoop *l_iter_radial, *l_first_radial;
- /**
- * imaginary edge diagonally across quad.
- * \note This takes advantage of the rules of winding that we
- * know 2 or more of a verts edges wont reference the same face twice.
- * Also, if the edge is hidden, the face will be hidden too.
- */
- l_iter_radial = l_first_radial = e_iter->l;
-
- do {
- if ((l_iter_radial->v == v) && (l_iter_radial->f->len == 4) &&
- (BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0)) {
- BMVert *v_other = l_iter_radial->next->next->v;
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
- BM_elem_flag_enable(v_other, BM_ELEM_TAG);
- BLI_LINKSTACK_PUSH(queue_next, v_other);
- }
- }
+ if (e->l != NULL) {
+ /* Propagate across edge to vertices in adjacent faces. */
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
+ for (BMLoop *l_other = l->next->next; l_other != l; l_other = l_other->next) {
+ BMVert *v_other = l_other->v;
+ BLI_assert(!ELEM(v_other, v1, v2));
+
+ if (bmesh_test_dist_add(v_other, v1, v2, dists, index, mtx)) {
+ /* Add adjacent edges to the queue, if they are ready to propagate across/along.
+ * Always propagate along loose edges, and for other edges only propagate across
+ * if both vertices have a known distances. */
+ BMEdge *e_other;
+ BMIter eiter;
+ BM_ITER_ELEM (e_other, &eiter, v_other, BM_EDGES_OF_VERT) {
+ if (e_other != e && BM_elem_flag_test(e_other, BM_ELEM_TAG) == 0 &&
+ (e_other->l == NULL ||
+ dists[BM_elem_index_get(BM_edge_other_vert(e_other, v_other))] != FLT_MAX)) {
+ BM_elem_flag_enable(e_other, BM_ELEM_TAG);
+ BLI_LINKSTACK_PUSH(queue_next, e_other);
}
- } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
+ }
}
}
- } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
+ }
}
}
- /* clear for the next loop */
- for (lnk = queue_next; lnk; lnk = lnk->next) {
- BMVert *v_link = lnk->link;
- const int i = BM_elem_index_get(v_link);
+ /* Clear for the next loop. */
+ for (LinkNode *lnk = queue_next; lnk; lnk = lnk->next) {
+ BMEdge *e_link = lnk->link;
- BM_elem_flag_disable(v_link, BM_ELEM_TAG);
-
- /* keep in sync, avoid having to do full memcpy each iteration */
- dists_prev[i] = dists[i];
- if (index != NULL) {
- index_prev[i] = index[i];
- }
+ BM_elem_flag_disable(e_link, BM_ELEM_TAG);
}
BLI_LINKSTACK_SWAP(queue, queue_next);
- /* none should be tagged now since 'queue_next' is empty */
- BLI_assert(BM_iter_mesh_count_flag(BM_VERTS_OF_MESH, bm, BM_ELEM_TAG, true) == 0);
-
+ /* None should be tagged now since 'queue_next' is empty. */
+ BLI_assert(BM_iter_mesh_count_flag(BM_EDGES_OF_MESH, bm, BM_ELEM_TAG, true) == 0);
} while (BLI_LINKSTACK_SIZE(queue));
BLI_LINKSTACK_FREE(queue);
BLI_LINKSTACK_FREE(queue_next);
-
- MEM_freeN(dists_prev);
- if (index_prev != NULL) {
- MEM_freeN(index_prev);
- }
}
/** \} */
@@ -1445,7 +1466,7 @@ static void mesh_customdatacorrect_apply_vert(struct TransCustomDataLayer *tcld,
*
* Interpolate from every other loop (not ideal)
* However values will only be taken from loops which overlap other mdisps.
- * */
+ */
const bool update_loop_mdisps = is_moved && do_loop_mdisps && (tcld->cd_loop_mdisp_offset != -1);
if (update_loop_mdisps) {
float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num);
diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c
index 1807e9adcd1..b1024f5efe4 100644
--- a/source/blender/editors/transform/transform_convert_mesh_skin.c
+++ b/source/blender/editors/transform/transform_convert_mesh_skin.c
@@ -55,9 +55,7 @@ static float *mesh_skin_transdata_center(const struct TransIslandData *island_da
if (island_data->center && island_index != -1) {
return island_data->center[island_index];
}
- else {
- return eve->co;
- }
+ return eve->co;
}
static void mesh_skin_transdata_create(TransDataBasic *td,
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index c3f48adca68..b25af709981 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -52,6 +52,7 @@ typedef struct TransDataTracking {
float (*smarkers)[2];
int markersnr;
+ int framenr;
MovieTrackingMarker *markers;
/* marker transformation from curves editor */
@@ -73,9 +74,25 @@ enum transDataTracking_Mode {
*
* \{ */
-static void markerToTransDataInit(TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
+typedef struct TransformInitContext {
+ SpaceClip *space_clip;
+
+ TransInfo *t;
+ TransDataContainer *tc;
+
+ /* NOTE: These pointers will be `nullptr` during counting step.
+ * This means, that the transformation data initialization functions are to increment
+ * `tc->data_len` instead of filling in the transformation data when these pointers are
+ * `nullptr`. For simplicity, check the `current.td` against `nullptr`.
+ * Do not `tc->data_len` when filling in the transformation data. */
+ struct {
+ TransData *td;
+ TransData2D *td2d;
+ TransDataTracking *tdt;
+ } current;
+} TransformInitContext;
+
+static void markerToTransDataInit(TransformInitContext *init_context,
MovieTrackingTrack *track,
MovieTrackingMarker *marker,
int area,
@@ -84,8 +101,19 @@ static void markerToTransDataInit(TransData *td,
const float off[2],
const float aspect[2])
{
+ TransData *td = init_context->current.td;
+ TransData2D *td2d = init_context->current.td2d;
+ TransDataTracking *tdt = init_context->current.tdt;
+
+ if (td == NULL) {
+ init_context->tc->data_len++;
+ return;
+ }
+
int anchor = area == TRACK_AREA_POINT && off;
+ tdt->flag = marker->flag;
+ tdt->framenr = marker->framenr;
tdt->mode = transDataTracking_ModeTracks;
if (anchor) {
@@ -143,23 +171,20 @@ static void markerToTransDataInit(TransData *td,
unit_m3(td->mtx);
unit_m3(td->smtx);
+
+ init_context->current.td++;
+ init_context->current.td2d++;
+ init_context->current.tdt++;
}
-static void trackToTransData(const int framenr,
- TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
+static void trackToTransData(TransformInitContext *init_context,
+ const int framenr,
MovieTrackingTrack *track,
const float aspect[2])
{
MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
- tdt->flag = marker->flag;
- marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED);
-
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
+ markerToTransDataInit(init_context,
track,
marker,
TRACK_AREA_POINT,
@@ -170,16 +195,14 @@ static void trackToTransData(const int framenr,
if (track->flag & SELECT) {
markerToTransDataInit(
- td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT, marker->pos, NULL, NULL, aspect);
+ init_context, track, marker, TRACK_AREA_POINT, marker->pos, NULL, NULL, aspect);
}
if (track->pat_flag & SELECT) {
int a;
for (a = 0; a < 4; a++) {
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
+ markerToTransDataInit(init_context,
track,
marker,
TRACK_AREA_PAT,
@@ -191,9 +214,7 @@ static void trackToTransData(const int framenr,
}
if (track->search_flag & SELECT) {
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
+ markerToTransDataInit(init_context,
track,
marker,
TRACK_AREA_SEARCH,
@@ -202,9 +223,7 @@ static void trackToTransData(const int framenr,
NULL,
aspect);
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
+ markerToTransDataInit(init_context,
track,
marker,
TRACK_AREA_SEARCH,
@@ -213,15 +232,43 @@ static void trackToTransData(const int framenr,
NULL,
aspect);
}
+
+ if (init_context->current.td != NULL) {
+ marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED);
+ }
}
-static void planeMarkerToTransDataInit(TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
+static void trackToTransDataIfNeeded(TransformInitContext *init_context,
+ const int framenr,
+ MovieTrackingTrack *track,
+ const float aspect[2])
+{
+ if (!TRACK_VIEW_SELECTED(init_context->space_clip, track)) {
+ return;
+ }
+ if (track->flag & TRACK_LOCKED) {
+ return;
+ }
+ trackToTransData(init_context, framenr, track, aspect);
+}
+
+static void planeMarkerToTransDataInit(TransformInitContext *init_context,
MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingPlaneMarker *plane_marker,
float corner[2],
const float aspect[2])
{
+ TransData *td = init_context->current.td;
+ TransData2D *td2d = init_context->current.td2d;
+ TransDataTracking *tdt = init_context->current.tdt;
+
+ if (td == NULL) {
+ init_context->tc->data_len++;
+ return;
+ }
+
+ tdt->flag = plane_marker->flag;
+ tdt->framenr = plane_marker->framenr;
tdt->mode = transDataTracking_ModePlaneTracks;
tdt->plane_track = plane_track;
@@ -247,24 +294,38 @@ static void planeMarkerToTransDataInit(TransData *td,
unit_m3(td->mtx);
unit_m3(td->smtx);
+
+ init_context->current.td++;
+ init_context->current.td2d++;
+ init_context->current.tdt++;
}
-static void planeTrackToTransData(const int framenr,
- TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
+static void planeTrackToTransData(TransformInitContext *init_context,
+ const int framenr,
MovieTrackingPlaneTrack *plane_track,
const float aspect[2])
{
MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
- int i;
- tdt->flag = plane_marker->flag;
- plane_marker->flag &= ~PLANE_MARKER_TRACKED;
+ for (int i = 0; i < 4; i++) {
+ planeMarkerToTransDataInit(
+ init_context, plane_track, plane_marker, plane_marker->corners[i], aspect);
+ }
- for (i = 0; i < 4; i++) {
- planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspect);
+ if (init_context->current.td != NULL) {
+ plane_marker->flag &= ~PLANE_MARKER_TRACKED;
+ }
+}
+
+static void planeTrackToTransDataIfNeeded(TransformInitContext *init_context,
+ const int framenr,
+ MovieTrackingPlaneTrack *plane_track,
+ const float aspect[2])
+{
+ if (!PLANE_TRACK_VIEW_SELECTED(plane_track)) {
+ return;
}
+ planeTrackToTransData(init_context, framenr, plane_track, aspect);
}
static void transDataTrackingFree(TransInfo *UNUSED(t),
@@ -284,101 +345,53 @@ static void transDataTrackingFree(TransInfo *UNUSED(t),
static void createTransTrackingTracksData(bContext *C, TransInfo *t)
{
- TransData *td;
- TransData2D *td2d;
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
- TransDataTracking *tdt;
- int framenr = ED_space_clip_get_clip_frame_number(sc);
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ const ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ const ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
+ const int framenr = ED_space_clip_get_clip_frame_number(space_clip);
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- /* count */
- tc->data_len = 0;
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- tc->data_len++; /* offset */
+ TransformInitContext init_context = {NULL};
+ init_context.space_clip = space_clip;
+ init_context.t = t;
+ init_context.tc = tc;
- if (track->flag & SELECT) {
- tc->data_len++;
- }
+ /* Count required tranformation data. */
- if (track->pat_flag & SELECT) {
- tc->data_len += 4;
- }
-
- if (track->search_flag & SELECT) {
- tc->data_len += 2;
- }
- }
+ tc->data_len = 0;
- track = track->next;
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
+ trackToTransDataIfNeeded(&init_context, framenr, track, t->aspect);
}
- for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
- if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- tc->data_len += 4;
- }
+ LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
+ planeTrackToTransDataIfNeeded(&init_context, framenr, plane_track, t->aspect);
}
if (tc->data_len == 0) {
return;
}
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
- "TransTracking TransData2D");
- tdt = tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
- "TransTracking TransDataTracking");
-
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransTracking TransData2D");
+ tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
+ "TransTracking TransDataTracking");
tc->custom.type.free_cb = transDataTrackingFree;
- /* create actual data */
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- trackToTransData(framenr, td, td2d, tdt, track, t->aspect);
-
- /* offset */
- td++;
- td2d++;
- tdt++;
+ init_context.current.td = tc->data;
+ init_context.current.td2d = tc->data_2d;
+ init_context.current.tdt = tc->custom.type.data;
- if (track->flag & SELECT) {
- td++;
- td2d++;
- tdt++;
- }
-
- if (track->pat_flag & SELECT) {
- td += 4;
- td2d += 4;
- tdt += 4;
- }
+ /* Create actual transformation data. */
- if (track->search_flag & SELECT) {
- td += 2;
- td2d += 2;
- tdt += 2;
- }
- }
-
- track = track->next;
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
+ trackToTransDataIfNeeded(&init_context, framenr, track, t->aspect);
}
- for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
- if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- planeTrackToTransData(framenr, td, td2d, tdt, plane_track, t->aspect);
- td += 4;
- td2d += 4;
- tdt += 4;
- }
+ LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
+ planeTrackToTransDataIfNeeded(&init_context, framenr, plane_track, t->aspect);
}
}
@@ -560,17 +573,17 @@ void createTransTrackingData(bContext *C, TransInfo *t)
static void cancelTransTracking(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- SpaceClip *sc = t->area->spacedata.first;
- int i, framenr = ED_space_clip_get_clip_frame_number(sc);
TransDataTracking *tdt_array = tc->custom.type.data;
- i = 0;
+ int i = 0;
while (i < tc->data_len) {
TransDataTracking *tdt = &tdt_array[i];
if (tdt->mode == transDataTracking_ModeTracks) {
MovieTrackingTrack *track = tdt->track;
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+ MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, tdt->framenr);
+
+ BLI_assert(marker != NULL);
marker->flag = tdt->flag;
@@ -606,7 +619,10 @@ static void cancelTransTracking(TransInfo *t)
}
else if (tdt->mode == transDataTracking_ModePlaneTracks) {
MovieTrackingPlaneTrack *plane_track = tdt->plane_track;
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get_exact(plane_track,
+ tdt->framenr);
+
+ BLI_assert(plane_marker != NULL);
plane_marker->flag = tdt->flag;
i += 3;
diff --git a/source/blender/editors/transform/transform_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c
index 84fc45e2b45..b4b28ea0ac0 100644
--- a/source/blender/editors/transform/transform_draw_cursors.c
+++ b/source/blender/editors/transform/transform_draw_cursors.c
@@ -45,103 +45,49 @@ enum eArrowDirection {
RIGHT,
};
-struct ArrowDims {
- int offset;
- int length;
- int size;
-};
-
-#define POS_INDEX 0
-/* NOTE: this --^ is a bit hackish, but simplifies GPUVertFormat usage among functions
- * private to this file - merwin
- */
+#define ARROW_WIDTH (2.0f * U.pixelsize)
+#define DASH_WIDTH (1.0f)
+#define DASH_LENGTH (8.0f * DASH_WIDTH * U.pixelsize)
-static void drawArrow(enum eArrowDirection dir, const struct ArrowDims *arrow_dims)
+static void drawArrow(const uint pos_id, const enum eArrowDirection dir)
{
- int offset = arrow_dims->offset;
- int length = arrow_dims->length;
- int size = arrow_dims->size;
+ int offset = 5.0f * UI_DPI_FAC;
+ int length = (6.0f * UI_DPI_FAC) + (4.0f * U.pixelsize);
+ int size = (3.0f * UI_DPI_FAC) + (2.0f * U.pixelsize);
+
+ /* To line up the arrow point nicely, one end has to be extended by half its width. But
+ * being on a 45 degree angle, Pythagoras says a movement of sqrt(2)/2 * (line width /2) */
+ float adjust = (M_SQRT2 * ARROW_WIDTH / 4.0f);
+
+ if (ELEM(dir, LEFT, DOWN)) {
+ offset = -offset;
+ length = -length;
+ size = -size;
+ adjust = -adjust;
+ }
immBegin(GPU_PRIM_LINES, 6);
- switch (dir) {
- case LEFT:
- offset = -offset;
- length = -length;
- size = -size;
- ATTR_FALLTHROUGH;
- case RIGHT:
- immVertex2f(POS_INDEX, offset, 0);
- immVertex2f(POS_INDEX, offset + length, 0);
- immVertex2f(POS_INDEX, offset + length, 0);
- immVertex2f(POS_INDEX, offset + length - size, -size);
- immVertex2f(POS_INDEX, offset + length, 0);
- immVertex2f(POS_INDEX, offset + length - size, size);
- break;
-
- case DOWN:
- offset = -offset;
- length = -length;
- size = -size;
- ATTR_FALLTHROUGH;
- case UP:
- immVertex2f(POS_INDEX, 0, offset);
- immVertex2f(POS_INDEX, 0, offset + length);
- immVertex2f(POS_INDEX, 0, offset + length);
- immVertex2f(POS_INDEX, -size, offset + length - size);
- immVertex2f(POS_INDEX, 0, offset + length);
- immVertex2f(POS_INDEX, size, offset + length - size);
- break;
+ if (ELEM(dir, LEFT, RIGHT)) {
+ immVertex2f(pos_id, offset, 0);
+ immVertex2f(pos_id, offset + length, 0);
+ immVertex2f(pos_id, offset + length + adjust, adjust);
+ immVertex2f(pos_id, offset + length - size, -size);
+ immVertex2f(pos_id, offset + length, 0);
+ immVertex2f(pos_id, offset + length - size, size);
}
-
- immEnd();
-}
-
-static void drawArrowHead(enum eArrowDirection dir, int size)
-{
- immBegin(GPU_PRIM_LINES, 4);
-
- switch (dir) {
- case LEFT:
- size = -size;
- ATTR_FALLTHROUGH;
- case RIGHT:
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, -size, -size);
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, -size, size);
- break;
-
- case DOWN:
- size = -size;
- ATTR_FALLTHROUGH;
- case UP:
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, -size, -size);
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, size, -size);
- break;
+ else {
+ immVertex2f(pos_id, 0, offset);
+ immVertex2f(pos_id, 0, offset + length);
+ immVertex2f(pos_id, adjust, offset + length + adjust);
+ immVertex2f(pos_id, -size, offset + length - size);
+ immVertex2f(pos_id, 0, offset + length);
+ immVertex2f(pos_id, size, offset + length - size);
}
immEnd();
}
-static void drawArc(float angle_start, float angle_end, int segments, float size)
-{
- float delta = (angle_end - angle_start) / segments;
- float angle;
- int a;
-
- immBegin(GPU_PRIM_LINE_STRIP, segments + 1);
-
- for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
- immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size);
- }
- immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size);
-
- immEnd();
-}
-
/**
* Poll callback for cursor drawing:
* #WM_paint_cursor_activate
@@ -149,11 +95,7 @@ static void drawArc(float angle_start, float angle_end, int segments, float size
bool transform_draw_cursor_poll(bContext *C)
{
ARegion *region = CTX_wm_region(C);
-
- if (region && region->regiontype == RGN_TYPE_WINDOW) {
- return 1;
- }
- return 0;
+ return (region && region->regiontype == RGN_TYPE_WINDOW) ? 1 : 0;
}
/**
@@ -164,181 +106,115 @@ void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customd
{
TransInfo *t = (TransInfo *)customdata;
- if (t->helpline != HLP_NONE) {
- struct ArrowDims arrow_dims = {
- .offset = 5 * UI_DPI_FAC,
- .length = 10 * UI_DPI_FAC,
- .size = 5 * UI_DPI_FAC,
- };
-
- float cent[2];
- const float mval[3] = {x, y, 0.0f};
- float tmval[2] = {
- (float)t->mval[0],
- (float)t->mval[1],
- };
-
- projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
- /* Offset the values for the area region. */
- const float offset[2] = {
- t->region->winrct.xmin,
- t->region->winrct.ymin,
- };
-
- for (int i = 0; i < 2; i++) {
- cent[i] += offset[i];
- tmval[i] += offset[i];
- }
-
- GPU_line_smooth(true);
- GPU_blend(GPU_BLEND_ALPHA);
-
- GPU_matrix_push();
-
- /* Dashed lines first. */
- if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
- const uint shdr_pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */
- BLI_assert(shdr_pos == POS_INDEX);
+ if (t->helpline == HLP_NONE) {
+ return;
+ }
- GPU_line_width(1.0f);
+ float cent[2];
+ const float mval[3] = {x, y, 0.0f};
+ float tmval[2] = {
+ (float)t->mval[0],
+ (float)t->mval[1],
+ };
+
+ projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
+ /* Offset the values for the area region. */
+ const float offset[2] = {
+ t->region->winrct.xmin,
+ t->region->winrct.ymin,
+ };
+
+ for (int i = 0; i < 2; i++) {
+ cent[i] += offset[i];
+ tmval[i] += offset[i];
+ }
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+
+ GPU_line_smooth(true);
+ GPU_blend(GPU_BLEND_ALPHA);
+ const uint pos_id = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ /* Dashed lines first. */
+ if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
+ GPU_line_width(DASH_WIDTH);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+ immUniform1f("dash_width", DASH_LENGTH);
+ immUniform1f("dash_factor", 0.5f);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(pos_id, cent);
+ immVertex2f(pos_id, tmval[0], tmval[1]);
+ immEnd();
+ immUnbindProgram();
+ }
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+ /* And now, solid lines. */
- immUniform1i("colors_len", 0); /* "simple" mode */
- immUniformThemeColor3(TH_VIEW_OVERLAY);
- immUniform1f("dash_width", 6.0f * UI_DPI_FAC);
- immUniform1f("dash_factor", 0.5f);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+ immUniform2fv("viewportSize", &viewport_size[2]);
+ immUniform1f("lineWidth", ARROW_WIDTH);
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2fv(POS_INDEX, cent);
- immVertex2f(POS_INDEX, tmval[0], tmval[1]);
- immEnd();
+ GPU_matrix_push();
+ GPU_matrix_translate_3fv(mval);
- immUnbindProgram();
+ switch (t->helpline) {
+ case HLP_SPRING:
+ GPU_matrix_rotate_axis(-RAD2DEGF(atan2f(cent[0] - tmval[0], cent[1] - tmval[1])), 'Z');
+ drawArrow(pos_id, UP);
+ drawArrow(pos_id, DOWN);
+ break;
+ case HLP_HARROW:
+ drawArrow(pos_id, RIGHT);
+ drawArrow(pos_id, LEFT);
+ break;
+ case HLP_VARROW:
+ drawArrow(pos_id, UP);
+ drawArrow(pos_id, DOWN);
+ break;
+ case HLP_CARROW: {
+ /* Draw arrow based on direction defined by custom-points. */
+ const int *data = t->mouse.data;
+ const float angle = -atan2f(data[2] - data[0], data[3] - data[1]);
+ GPU_matrix_rotate_axis(RAD2DEGF(angle), 'Z');
+ drawArrow(pos_id, UP);
+ drawArrow(pos_id, DOWN);
+ break;
}
-
- /* And now, solid lines. */
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- UNUSED_VARS_NDEBUG(pos); /* silence warning */
- BLI_assert(pos == POS_INDEX);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- switch (t->helpline) {
- case HLP_SPRING:
- immUniformThemeColor3(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3fv(mval);
- GPU_matrix_rotate_axis(-RAD2DEGF(atan2f(cent[0] - tmval[0], cent[1] - tmval[1])), 'Z');
-
- GPU_line_width(3.0f);
- drawArrow(UP, &arrow_dims);
- drawArrow(DOWN, &arrow_dims);
- break;
- case HLP_HARROW:
- immUniformThemeColor3(TH_VIEW_OVERLAY);
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
- drawArrow(RIGHT, &arrow_dims);
- drawArrow(LEFT, &arrow_dims);
- break;
- case HLP_VARROW:
- immUniformThemeColor3(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
- drawArrow(UP, &arrow_dims);
- drawArrow(DOWN, &arrow_dims);
- break;
- case HLP_CARROW: {
- /* Draw arrow based on direction defined by custom-points. */
- immUniformThemeColor3(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
-
- const int *data = t->mouse.data;
- const float dx = data[2] - data[0], dy = data[3] - data[1];
- const float angle = -atan2f(dx, dy);
-
- GPU_matrix_push();
-
- GPU_matrix_rotate_axis(RAD2DEGF(angle), 'Z');
-
- drawArrow(UP, &arrow_dims);
- drawArrow(DOWN, &arrow_dims);
-
- GPU_matrix_pop();
- break;
- }
- case HLP_ANGLE: {
- float dx = tmval[0] - cent[0], dy = tmval[1] - cent[1];
- float angle = atan2f(dy, dx);
- float dist = hypotf(dx, dy);
- float delta_angle = min_ff(15.0f / (dist / UI_DPI_FAC), (float)M_PI / 4.0f);
- float spacing_angle = min_ff(5.0f / (dist / UI_DPI_FAC), (float)M_PI / 12.0f);
-
- immUniformThemeColor3(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3f(cent[0] - tmval[0] + mval[0], cent[1] - tmval[1] + mval[1], 0);
-
- GPU_line_width(3.0f);
- drawArc(angle - delta_angle, angle - spacing_angle, 10, dist);
- drawArc(angle + spacing_angle, angle + delta_angle, 10, dist);
-
- GPU_matrix_push();
-
- GPU_matrix_translate_3f(
- cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
- GPU_matrix_rotate_axis(RAD2DEGF(angle - delta_angle), 'Z');
-
- drawArrowHead(DOWN, arrow_dims.size);
-
- GPU_matrix_pop();
-
- GPU_matrix_translate_3f(
- cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
- GPU_matrix_rotate_axis(RAD2DEGF(angle + delta_angle), 'Z');
-
- drawArrowHead(UP, arrow_dims.size);
- break;
- }
- case HLP_TRACKBALL: {
- uchar col[3], col2[3];
- UI_GetThemeColor3ubv(TH_GRID, col);
-
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
-
- UI_make_axis_color(col, col2, 'X');
- immUniformColor3ubv(col2);
-
- drawArrow(RIGHT, &arrow_dims);
- drawArrow(LEFT, &arrow_dims);
-
- UI_make_axis_color(col, col2, 'Y');
- immUniformColor3ubv(col2);
-
- drawArrow(UP, &arrow_dims);
- drawArrow(DOWN, &arrow_dims);
- break;
- }
+ case HLP_ANGLE: {
+ GPU_matrix_push();
+ float angle = atan2f(tmval[1] - cent[1], tmval[0] - cent[0]);
+ GPU_matrix_translate_3f(cosf(angle), sinf(angle), 0);
+ GPU_matrix_rotate_axis(RAD2DEGF(angle), 'Z');
+ drawArrow(pos_id, DOWN);
+ GPU_matrix_pop();
+ GPU_matrix_translate_3f(cosf(angle), sinf(angle), 0);
+ GPU_matrix_rotate_axis(RAD2DEGF(angle), 'Z');
+ drawArrow(pos_id, UP);
+ break;
+ }
+ case HLP_TRACKBALL: {
+ uchar col[3], col2[3];
+ UI_GetThemeColor3ubv(TH_GRID, col);
+ UI_make_axis_color(col, col2, 'X');
+ immUniformColor3ubv(col2);
+ drawArrow(pos_id, RIGHT);
+ drawArrow(pos_id, LEFT);
+ UI_make_axis_color(col, col2, 'Y');
+ immUniformColor3ubv(col2);
+ drawArrow(pos_id, UP);
+ drawArrow(pos_id, DOWN);
+ break;
}
-
- immUnbindProgram();
- GPU_matrix_pop();
-
- GPU_line_smooth(false);
- GPU_blend(GPU_BLEND_NONE);
}
+
+ GPU_matrix_pop();
+ immUnbindProgram();
+ GPU_line_smooth(false);
+ GPU_blend(GPU_BLEND_NONE);
}
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 166fded5209..5b9d73a10fe 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -704,7 +704,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
/* calculate difference matrix */
- BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat);
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) {
/* skip strokes that are invalid for current view */
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 3b39f4d06ad..6d1bb9cc0de 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -521,23 +521,19 @@ short ED_transform_calc_orientation_from_type_ex(const bContext *C,
const int pivot_point)
{
switch (orientation_type) {
- case V3D_ORIENT_GLOBAL: {
- unit_m3(r_mat);
- return V3D_ORIENT_GLOBAL;
- }
case V3D_ORIENT_GIMBAL: {
if (ob && gimbal_axis(ob, r_mat)) {
- return V3D_ORIENT_GIMBAL;
+ break;
}
- /* if not gimbal, fall through to normal */
+ /* If not gimbal, fall through to normal. */
ATTR_FALLTHROUGH;
}
case V3D_ORIENT_NORMAL: {
if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
ED_getTransformOrientationMatrix(C, ob, obedit, pivot_point, r_mat);
- return V3D_ORIENT_NORMAL;
+ break;
}
- /* no break we define 'normal' as 'local' in Object mode */
+ /* No break we define 'normal' as 'local' in Object mode. */
ATTR_FALLTHROUGH;
}
case V3D_ORIENT_LOCAL: {
@@ -552,10 +548,14 @@ short ED_transform_calc_orientation_from_type_ex(const bContext *C,
else {
transform_orientations_create_from_axis(r_mat, UNPACK3(ob->obmat));
}
- return V3D_ORIENT_LOCAL;
+ break;
}
+ /* If not local, fall through to global. */
+ ATTR_FALLTHROUGH;
+ }
+ case V3D_ORIENT_GLOBAL: {
unit_m3(r_mat);
- return V3D_ORIENT_GLOBAL;
+ break;
}
case V3D_ORIENT_VIEW: {
if (rv3d != NULL) {
@@ -565,11 +565,11 @@ short ED_transform_calc_orientation_from_type_ex(const bContext *C,
else {
unit_m3(r_mat);
}
- return V3D_ORIENT_VIEW;
+ break;
}
case V3D_ORIENT_CURSOR: {
BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat);
- return V3D_ORIENT_CURSOR;
+ break;
}
case V3D_ORIENT_CUSTOM_MATRIX: {
/* Do nothing. */;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index c19dd4598cf..508189c5d77 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -299,83 +299,93 @@ eRedrawFlag handleSnapping(TransInfo *t, const wmEvent *event)
void applyProject(TransInfo *t)
{
- /* XXX FLICKER IN OBJECT MODE */
- if ((t->tsnap.project) && activeSnap(t) && (t->flag & T_NO_PROJECT) == 0) {
- float tvec[3];
- int i;
+ if (!t->tsnap.project) {
+ return;
+ }
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- float iloc[3], loc[3], no[3];
- float mval_fl[2];
- if (td->flag & TD_SKIP) {
- continue;
- }
+ if (!activeSnap(t) || (t->flag & T_NO_PROJECT)) {
+ return;
+ }
- if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
- continue;
- }
+ if (doForceIncrementSnap(t)) {
+ return;
+ }
- copy_v3_v3(iloc, td->loc);
- if (tc->use_local_mat) {
- mul_m4_v3(tc->mat, iloc);
- }
- else if (t->flag & T_OBJECT) {
- BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
- copy_v3_v3(iloc, td->ob->obmat[3]);
- }
+ float tvec[3];
+ int i;
+
+ /* XXX FLICKER IN OBJECT MODE */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float iloc[3], loc[3], no[3];
+ float mval_fl[2];
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
+ continue;
+ }
- if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) ==
- V3D_PROJ_RET_OK) {
- if (ED_transform_snap_object_project_view3d(
- t->tsnap.object_context,
- t->depsgraph,
- SCE_SNAP_MODE_FACE,
- &(const struct SnapObjectParams){
- .snap_select = t->tsnap.modeSelect,
- .use_object_edit_cage = (t->flag & T_EDIT) != 0,
- .use_occlusion_test = false,
- .use_backface_culling = t->tsnap.use_backface_culling,
- },
- mval_fl,
- NULL,
- 0,
- loc,
- no)) {
+ copy_v3_v3(iloc, td->loc);
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->mat, iloc);
+ }
+ else if (t->flag & T_OBJECT) {
+ BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
+ copy_v3_v3(iloc, td->ob->obmat[3]);
+ }
+
+ if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) ==
+ V3D_PROJ_RET_OK) {
+ if (ED_transform_snap_object_project_view3d(
+ t->tsnap.object_context,
+ t->depsgraph,
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_select = t->tsnap.modeSelect,
+ .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ .use_occlusion_test = false,
+ .use_backface_culling = t->tsnap.use_backface_culling,
+ },
+ mval_fl,
+ NULL,
+ 0,
+ loc,
+ no)) {
#if 0
if (tc->use_local_mat) {
mul_m4_v3(tc->imat, loc);
}
#endif
- sub_v3_v3v3(tvec, loc, iloc);
+ sub_v3_v3v3(tvec, loc, iloc);
- mul_m3_v3(td->smtx, tvec);
+ mul_m3_v3(td->smtx, tvec);
- add_v3_v3(td->loc, tvec);
+ add_v3_v3(td->loc, tvec);
- if (t->tsnap.align && (t->flag & T_OBJECT)) {
- /* handle alignment as well */
- const float *original_normal;
- float mat[3][3];
+ if (t->tsnap.align && (t->flag & T_OBJECT)) {
+ /* handle alignment as well */
+ const float *original_normal;
+ float mat[3][3];
- /* In pose mode, we want to align normals with Y axis of bones... */
- original_normal = td->axismtx[2];
+ /* In pose mode, we want to align normals with Y axis of bones... */
+ original_normal = td->axismtx[2];
- rotation_between_vecs_to_mat3(mat, original_normal, no);
+ rotation_between_vecs_to_mat3(mat, original_normal, no);
- transform_data_ext_rotate(td, mat, true);
+ transform_data_ext_rotate(td, mat, true);
- /* TODO support constraints for rotation too? see ElementRotation */
- }
+ /* TODO support constraints for rotation too? see ElementRotation */
}
}
+ }
#if 0 /* TODO: sipport this? */
constraintTransLim(t, td);
#endif
- }
}
}
}
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 533416bf85e..b6001b8b014 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -70,6 +70,15 @@
/** We only need this locally. */
static CLG_LogRef LOG = {"ed.undo"};
+/**
+ * \warning Values are used in #ED_undo_gpencil_step,
+ * which should eventually be replaced with the undo-system.
+ */
+enum eUndoStepDir {
+ STEP_REDO = 1,
+ STEP_UNDO = -1,
+};
+
/* -------------------------------------------------------------------- */
/** \name Generic Undo System Access
*
@@ -169,16 +178,16 @@ void ED_undo_push(bContext *C, const char *str)
}
/**
- * \note Also check #undo_history_exec in bottom if you change notifiers.
+ * Common pre management of undo/redo (killing all running jobs, calling pre handlers, etc.).
*/
-static int ed_undo_step_impl(
- bContext *C, int step, const char *undoname, int undo_index, ReportList *reports)
+static void ed_undo_step_pre(bContext *C,
+ wmWindowManager *wm,
+ const enum eUndoStepDir undo_dir,
+ ReportList *reports)
{
- /* Mutually exclusives, ensure correct input. */
- BLI_assert(((undoname || undo_index != -1) && !step) ||
- (!(undoname || undo_index != -1) && step));
- CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step);
- wmWindowManager *wm = CTX_wm_manager(C);
+ BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO));
+
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ScrArea *area = CTX_wm_area(C);
@@ -187,18 +196,12 @@ static int ed_undo_step_impl(
WM_jobs_kill_all(wm);
if (G.debug & G_DEBUG_IO) {
- Main *bmain = CTX_data_main(C);
if (bmain->lock != NULL) {
BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* undo step");
BLO_main_validate_libraries(bmain, reports);
}
}
- /* TODO(campbell): undo_system: use undo system */
- /* grease pencil can be can be used in plenty of spaces, so check it first */
- if (ED_gpencil_session_active()) {
- return ED_undo_gpencil_step(C, step, undoname);
- }
if (area && (area->spacetype == SPACE_VIEW3D)) {
Object *obact = CTX_data_active_object(C);
if (obact && (obact->type == OB_GPENCIL)) {
@@ -206,89 +209,40 @@ static int ed_undo_step_impl(
}
}
- UndoStep *step_data_from_name = NULL;
- int step_for_callback = step;
- if (undoname != NULL) {
- step_data_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undoname);
- if (step_data_from_name == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- /* TODO(campbell), could use simple optimization. */
- /* Pointers match on redo. */
- step_for_callback = (BLI_findindex(&wm->undo_stack->steps, step_data_from_name) <
- BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ?
- 1 :
- -1;
- }
- else if (undo_index != -1) {
- step_for_callback = (undo_index <
- BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ?
- 1 :
- -1;
- }
-
/* App-Handlers (pre). */
{
/* Note: ignore grease pencil for now. */
- Main *bmain = CTX_data_main(C);
wm->op_undo_depth++;
BKE_callback_exec_id(
- bmain, &scene->id, (step_for_callback > 0) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE);
+ bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE);
wm->op_undo_depth--;
}
+}
- /* Undo System */
- {
- if (undoname) {
- BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data_from_name);
- }
- else if (undo_index != -1) {
- BKE_undosys_step_undo_from_index(wm->undo_stack, C, undo_index);
- }
- else {
- if (step == 1) {
- BKE_undosys_step_undo(wm->undo_stack, C);
- }
- else {
- BKE_undosys_step_redo(wm->undo_stack, C);
- }
- }
+/**
+ * Common post management of undo/redo (calling post handlers, adding notifiers etc.).
+ *
+ * \note Also check #undo_history_exec in bottom if you change notifiers.
+ */
+static void ed_undo_step_post(bContext *C,
+ wmWindowManager *wm,
+ const enum eUndoStepDir undo_dir,
+ ReportList *reports)
+{
+ BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO));
- /* Set special modes for grease pencil */
- if (area && (area->spacetype == SPACE_VIEW3D)) {
- Object *obact = CTX_data_active_object(C);
- if (obact && (obact->type == OB_GPENCIL)) {
- /* set cursor */
- if (ELEM(obact->mode,
- OB_MODE_PAINT_GPENCIL,
- OB_MODE_SCULPT_GPENCIL,
- OB_MODE_WEIGHT_GPENCIL,
- OB_MODE_VERTEX_GPENCIL)) {
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
- }
- else {
- ED_gpencil_toggle_brush_cursor(C, false, NULL);
- }
- /* set workspace mode */
- Base *basact = CTX_data_active_base(C);
- ED_object_base_activate(C, basact);
- }
- }
- }
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
/* App-Handlers (post). */
{
- Main *bmain = CTX_data_main(C);
- scene = CTX_data_scene(C);
wm->op_undo_depth++;
BKE_callback_exec_id(
- bmain, &scene->id, step_for_callback > 0 ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST);
+ bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST);
wm->op_undo_depth--;
}
if (G.debug & G_DEBUG_IO) {
- Main *bmain = CTX_data_main(C);
if (bmain->lock != NULL) {
BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *AFTER* undo step");
BLO_main_validate_libraries(bmain, reports);
@@ -299,30 +253,126 @@ static int ed_undo_step_impl(
WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL);
WM_toolsystem_refresh_active(C);
-
- Main *bmain = CTX_data_main(C);
WM_toolsystem_refresh_screen_all(bmain);
if (CLOG_CHECK(&LOG, 1)) {
BKE_undosys_print(wm->undo_stack);
}
-
- return OPERATOR_FINISHED;
}
-static int ed_undo_step_direction(bContext *C, int step, ReportList *reports)
+/** Undo or redo one step from current active one.
+ * May undo or redo several steps at once only if the target step is a 'skipped' one.
+ * The target step will be the one immediately before or after the active one. */
+static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports)
{
- return ed_undo_step_impl(C, step, NULL, -1, reports);
+ BLI_assert(ELEM(step, STEP_UNDO, STEP_REDO));
+
+ CLOG_INFO(&LOG, 1, "direction=%s", (step == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO");
+
+ /* TODO(campbell): undo_system: use undo system */
+ /* grease pencil can be can be used in plenty of spaces, so check it first */
+ /* FIXME: This gpencil undo effectively only supports the one step undo/redo, undo based on name
+ * or index is fully not implemented.
+ * FIXME: However, it seems to never be used in current code (`ED_gpencil_session_active` seems
+ * to always return false). */
+ if (ED_gpencil_session_active()) {
+ return ED_undo_gpencil_step(C, (int)step);
+ }
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ ed_undo_step_pre(C, wm, step, reports);
+
+ if (step == STEP_UNDO) {
+ BKE_undosys_step_undo(wm->undo_stack, C);
+ }
+ else {
+ BKE_undosys_step_redo(wm->undo_stack, C);
+ }
+
+ ed_undo_step_post(C, wm, step, reports);
+
+ return OPERATOR_FINISHED;
}
+/** Undo the step matching given name.
+ * May undo several steps at once.
+ * The target step will be the one immediately before given named one.
+ * Only supposed to undo (will assert in case given named step is after current active one). */
static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *reports)
{
- return ed_undo_step_impl(C, 0, undo_name, -1, reports);
+ BLI_assert(undo_name != NULL);
+
+ /* FIXME: See comments in `ed_undo_step_direction`. */
+ if (ED_gpencil_session_active()) {
+ BLI_assert(!"Not implemented currently.");
+ }
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ UndoStep *undo_step_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undo_name);
+ if (undo_step_from_name == NULL) {
+ CLOG_ERROR(&LOG, "Step name='%s' not found in current undo stack", undo_name);
+
+ return OPERATOR_CANCELLED;
+ }
+
+ /* TODO(campbell), could use simple optimization. */
+ /* Pointers match on redo. */
+ const int target_step_index = BLI_findindex(&wm->undo_stack->steps, undo_step_from_name);
+ const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active);
+ /* NOTE: when current and target active steps are the same, we are in undo case. */
+ const enum eUndoStepDir undo_dir = (target_step_index <= active_step_index) ? STEP_UNDO :
+ STEP_REDO;
+
+ CLOG_INFO(&LOG,
+ 1,
+ "name='%s', found direction=%s, index=%d",
+ undo_name,
+ (undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO",
+ target_step_index);
+
+ /* This function is currently not supposed to redo ever.
+ * TODO: Will be fixed in future in continuing undo code refactor effort. */
+ BLI_assert(undo_dir == STEP_UNDO);
+
+ ed_undo_step_pre(C, wm, undo_dir, reports);
+
+ BKE_undosys_step_undo_with_data(wm->undo_stack, C, undo_step_from_name);
+
+ ed_undo_step_post(C, wm, undo_dir, reports);
+
+ return OPERATOR_FINISHED;
}
-static int ed_undo_step_by_index(bContext *C, int index, ReportList *reports)
+/** Load the step matching given index in the stack.
+ * May undo or redo several steps at once.
+ * The target step will be the one indicated by the given index. */
+static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *reports)
{
- return ed_undo_step_impl(C, 0, NULL, index, reports);
+ BLI_assert(undo_index >= 0);
+
+ /* FIXME: See comments in `ed_undo_step_direction`. */
+ if (ED_gpencil_session_active()) {
+ BLI_assert(!"Not implemented currently.");
+ }
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active);
+ const enum eUndoStepDir undo_dir = (undo_index < active_step_index) ? STEP_UNDO : STEP_REDO;
+
+ CLOG_INFO(&LOG,
+ 1,
+ "index='%d', found direction=%s",
+ undo_index,
+ (undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO");
+
+ ed_undo_step_pre(C, wm, undo_dir, reports);
+
+ BKE_undosys_step_undo_from_index(wm->undo_stack, C, undo_index);
+
+ ed_undo_step_post(C, wm, undo_dir, reports);
+
+ return OPERATOR_FINISHED;
}
void ED_undo_grouped_push(bContext *C, const char *str)
@@ -340,11 +390,11 @@ void ED_undo_grouped_push(bContext *C, const char *str)
void ED_undo_pop(bContext *C)
{
- ed_undo_step_direction(C, 1, NULL);
+ ed_undo_step_direction(C, STEP_UNDO, NULL);
}
void ED_undo_redo(bContext *C)
{
- ed_undo_step_direction(C, -1, NULL);
+ ed_undo_step_direction(C, STEP_REDO, NULL);
}
void ED_undo_push_op(bContext *C, wmOperator *op)
@@ -448,7 +498,7 @@ static int ed_undo_exec(bContext *C, wmOperator *op)
{
/* "last operator" should disappear, later we can tie this with undo stack nicer */
WM_operator_stack_clear(CTX_wm_manager(C));
- int ret = ed_undo_step_direction(C, 1, op->reports);
+ int ret = ed_undo_step_direction(C, STEP_UNDO, op->reports);
if (ret & OPERATOR_FINISHED) {
/* Keep button under the cursor active. */
WM_event_add_mousemove(CTX_wm_window(C));
@@ -477,7 +527,7 @@ static int ed_undo_push_exec(bContext *C, wmOperator *op)
static int ed_redo_exec(bContext *C, wmOperator *op)
{
- int ret = ed_undo_step_direction(C, -1, op->reports);
+ int ret = ed_undo_step_direction(C, STEP_REDO, op->reports);
if (ret & OPERATOR_FINISHED) {
/* Keep button under the cursor active. */
WM_event_add_mousemove(CTX_wm_window(C));
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index 930da3ef471..a16479873e7 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -56,11 +56,6 @@ NodeGroup *BlenderFileLoader::Load()
// creation of the scene root node
_Scene = new NodeGroup;
- _viewplane_left = _re->viewplane.xmin;
- _viewplane_right = _re->viewplane.xmax;
- _viewplane_bottom = _re->viewplane.ymin;
- _viewplane_top = _re->viewplane.ymax;
-
if (_re->clip_start < 0.0f) {
// Adjust clipping start/end and set up a Z offset when the viewport preview
// is used with the orthographic view. In this case, _re->clip_start is negative,
@@ -76,14 +71,6 @@ NodeGroup *BlenderFileLoader::Load()
_z_offset = 0.0f;
}
-#if 0
- if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "Frustum: l " << _viewplane_left << " r " << _viewplane_right << " b "
- << _viewplane_bottom << " t " << _viewplane_top << " n " << _z_near << " f " << _z_far
- << endl;
- }
-#endif
-
int id = 0;
const eEvaluationMode eval_mode = DEG_get_mode(_depsgraph);
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
index 50834db3c5c..1be2fc3bc99 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
@@ -152,10 +152,6 @@ class BlenderFileLoader {
real _minEdgeSize;
#endif
bool _smooth; /* if true, face smoothness is taken into account */
- float _viewplane_left;
- float _viewplane_right;
- float _viewplane_bottom;
- float _viewplane_top;
float _z_near, _z_far;
float _z_offset;
diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.cpp b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
index 51727fd2288..d3a3d8bc76e 100644
--- a/source/blender/freestyle/intern/geometry/GeomUtils.cpp
+++ b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
@@ -435,12 +435,12 @@ bool overlapTriangleBox(Vec3r &boxcenter, Vec3r &boxhalfsize, Vec3r triverts[3])
// Tomas Möller
// Prosolvia Clarus AB
// Sweden
-// tompa@clarus.se
+// <tompa@clarus.se>
//
// Ben Trumbore
// Cornell University
// Ithaca, New York
-// wbt@graphics.cornell.edu
+// <wbt@graphics.cornell.edu>
bool intersectRayTriangle(const Vec3r &orig,
const Vec3r &dir,
const Vec3r &v0,
diff --git a/source/blender/freestyle/intern/geometry/matrix_util.cpp b/source/blender/freestyle/intern/geometry/matrix_util.cpp
index 5b5d9582e8f..95a24d85677 100644
--- a/source/blender/freestyle/intern/geometry/matrix_util.cpp
+++ b/source/blender/freestyle/intern/geometry/matrix_util.cpp
@@ -17,7 +17,7 @@
* GXML/Graphite: Geometry and Graphics Programming Library + Utilities
* Copyright (C) 2000 Bruno Levy
* Contact: Bruno Levy
- * levy@loria.fr
+ * <levy@loria.fr>
* ISA Project
* LORIA, INRIA Lorraine,
* Campus Scientifique, BP 239
diff --git a/source/blender/freestyle/intern/geometry/matrix_util.h b/source/blender/freestyle/intern/geometry/matrix_util.h
index 8a20cb31300..8c2eb799d13 100644
--- a/source/blender/freestyle/intern/geometry/matrix_util.h
+++ b/source/blender/freestyle/intern/geometry/matrix_util.h
@@ -17,7 +17,7 @@
* GXML/Graphite: Geometry and Graphics Programming Library + Utilities
* Copyright (C) 2000 Bruno Levy
* Contact: Bruno Levy
- * levy@loria.fr
+ * <levy@loria.fr>
* ISA Project
* LORIA, INRIA Lorraine,
* Campus Scientifique, BP 239
diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.cpp b/source/blender/freestyle/intern/geometry/normal_cycle.cpp
index 01d52646eb0..2310525a1e1 100644
--- a/source/blender/freestyle/intern/geometry/normal_cycle.cpp
+++ b/source/blender/freestyle/intern/geometry/normal_cycle.cpp
@@ -17,7 +17,7 @@
* OGF/Graphite: Geometry and Graphics Programming Library + Utilities
* Copyright (C) 2000 Bruno Levy
* Contact: Bruno Levy
- * levy@loria.fr
+ * <levy@loria.fr>
* ISA Project
* LORIA, INRIA Lorraine,
* Campus Scientifique, BP 239
diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.h b/source/blender/freestyle/intern/geometry/normal_cycle.h
index 6ac9779e7c2..5adef773be1 100644
--- a/source/blender/freestyle/intern/geometry/normal_cycle.h
+++ b/source/blender/freestyle/intern/geometry/normal_cycle.h
@@ -17,7 +17,7 @@
* OGF/Graphite: Geometry and Graphics Programming Library + Utilities
* Copyright (C) 2000 Bruno Levy
* Contact: Bruno Levy
- * levy@loria.fr
+ * <levy@loria.fr>
* ISA Project
* LORIA, INRIA Lorraine,
* Campus Scientifique, BP 239
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
index 0ee491a071c..1984aceb51c 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
@@ -19,7 +19,7 @@
* and:
* OGF/Graphite: Geometry and Graphics Programming Library + Utilities
* Copyright (C) 2000-2003 Bruno Levy
- * Contact: Bruno Levy levy@loria.fr
+ * Contact: Bruno Levy <levy@loria.fr>
* ISA Project
* LORIA, INRIA Lorraine,
* Campus Scientifique, BP 239
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.h b/source/blender/freestyle/intern/winged_edge/Curvature.h
index d73674d02cd..0eefc57c3a2 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.h
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.h
@@ -19,7 +19,7 @@
* and:
* OGF/Graphite: Geometry and Graphics Programming Library + Utilities
* Copyright (C) 2000-2003 Bruno Levy
- * Contact: Bruno Levy levy@loria.fr
+ * Contact: Bruno Levy <levy@loria.fr>
* ISA Project
* LORIA, INRIA Lorraine,
* Campus Scientifique, BP 239
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
index e2f4d34ff40..f80ad60eb07 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -110,11 +110,11 @@ static bool dependsOnTime(GpencilModifierData *md)
return (mmd->flag & GP_NOISE_USE_RANDOM) != 0;
}
-static float *noise_table(int len, int seed)
+static float *noise_table(int len, int offset, int seed)
{
float *table = MEM_callocN(sizeof(float) * len, __func__);
for (int i = 0; i < len; i++) {
- table[i] = BLI_hash_int_01(BLI_hash_int_2d(seed, i + 1));
+ table[i] = BLI_hash_int_01(BLI_hash_int_2d(seed, i + offset + 1));
}
return table;
}
@@ -172,11 +172,19 @@ static void deformStroke(GpencilModifierData *md,
/* Sanitize as it can create out of bound reads. */
float noise_scale = clamp_f(mmd->noise_scale, 0.0f, 1.0f);
- int len = ceilf(gps->totpoints * noise_scale) + 1;
- float *noise_table_position = (mmd->factor > 0.0f) ? noise_table(len, seed + 2) : NULL;
- float *noise_table_strength = (mmd->factor_strength > 0.0f) ? noise_table(len, seed + 3) : NULL;
- float *noise_table_thickness = (mmd->factor_thickness > 0.0f) ? noise_table(len, seed) : NULL;
- float *noise_table_uvs = (mmd->factor_uvs > 0.0f) ? noise_table(len, seed + 4) : NULL;
+ int len = ceilf(gps->totpoints * noise_scale) + 2;
+ float *noise_table_position = (mmd->factor > 0.0f) ?
+ noise_table(len, (int)floor(mmd->noise_offset), seed + 2) :
+ NULL;
+ float *noise_table_strength = (mmd->factor_strength > 0.0f) ?
+ noise_table(len, (int)floor(mmd->noise_offset), seed + 3) :
+ NULL;
+ float *noise_table_thickness = (mmd->factor_thickness > 0.0f) ?
+ noise_table(len, (int)floor(mmd->noise_offset), seed) :
+ NULL;
+ float *noise_table_uvs = (mmd->factor_uvs > 0.0f) ?
+ noise_table(len, (int)floor(mmd->noise_offset), seed + 4) :
+ NULL;
/* Calculate stroke normal. */
if (gps->totpoints > 2) {
@@ -225,24 +233,27 @@ static void deformStroke(GpencilModifierData *md,
cross_v3_v3v3(vec2, vec1, normal);
normalize_v3(vec2);
- float noise = table_sample(noise_table_position, i * noise_scale);
+ float noise = table_sample(noise_table_position,
+ i * noise_scale + fractf(mmd->noise_offset));
madd_v3_v3fl(&pt->x, vec2, (noise * 2.0f - 1.0f) * weight * mmd->factor * 0.1f);
}
if (mmd->factor_thickness > 0.0f) {
- float noise = table_sample(noise_table_thickness, i * noise_scale);
+ float noise = table_sample(noise_table_thickness,
+ i * noise_scale + fractf(mmd->noise_offset));
pt->pressure *= max_ff(1.0f + (noise * 2.0f - 1.0f) * weight * mmd->factor_thickness, 0.0f);
CLAMP_MIN(pt->pressure, GPENCIL_STRENGTH_MIN);
}
if (mmd->factor_strength > 0.0f) {
- float noise = table_sample(noise_table_strength, i * noise_scale);
+ float noise = table_sample(noise_table_strength,
+ i * noise_scale + fractf(mmd->noise_offset));
pt->strength *= max_ff(1.0f - noise * weight * mmd->factor_strength, 0.0f);
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
if (mmd->factor_uvs > 0.0f) {
- float noise = table_sample(noise_table_uvs, i * noise_scale);
+ float noise = table_sample(noise_table_uvs, i * noise_scale + fractf(mmd->noise_offset));
pt->uv_rot += (noise * 2.0f - 1.0f) * weight * mmd->factor_uvs * M_PI_2;
CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
}
@@ -292,6 +303,8 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "factor_thickness", 0, IFACE_("Thickness"), ICON_NONE);
uiItemR(col, ptr, "factor_uvs", 0, IFACE_("UV"), ICON_NONE);
uiItemR(col, ptr, "noise_scale", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "noise_offset", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "seed", 0, NULL, ICON_NONE);
gpencil_modifier_panel_end(layout, ptr);
}
@@ -316,7 +329,6 @@ static void random_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetActive(layout, RNA_boolean_get(ptr, "random"));
uiItemR(layout, ptr, "step", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "seed", 0, NULL, ICON_NONE);
}
static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h
index bb7e1d58041..c457b829bf7 100644
--- a/source/blender/gpu/GPU_platform.h
+++ b/source/blender/gpu/GPU_platform.h
@@ -34,6 +34,7 @@ typedef enum eGPUDeviceType {
GPU_DEVICE_ATI = (1 << 1),
GPU_DEVICE_INTEL = (1 << 2),
GPU_DEVICE_INTEL_UHD = (1 << 3),
+ GPU_DEVICE_APPLE = (1 << 3),
GPU_DEVICE_SOFTWARE = (1 << 4),
GPU_DEVICE_UNKNOWN = (1 << 5),
GPU_DEVICE_ANY = (0xff),
diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc
index e158601a25c..782d25747bb 100644
--- a/source/blender/gpu/intern/gpu_state.cc
+++ b/source/blender/gpu/intern/gpu_state.cc
@@ -165,6 +165,11 @@ void GPU_depth_range(float near, float far)
copy_v2_fl2(state.depth_range, near, far);
}
+/**
+ * \note By convention, this is set as needed and not reset back to 1.0.
+ * This means code that draws lines must always set the line width beforehand,
+ * but is not expected to restore it's previous value.
+ */
void GPU_line_width(float width)
{
width = max_ff(1.0f, width * PIXELSIZE);
diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc
index 014c70033fc..625ad604b7c 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.cc
+++ b/source/blender/gpu/intern/gpu_vertex_format.cc
@@ -200,7 +200,7 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias)
*
* WARNING: this function creates a lot of aliases/attributes, make sure to keep the attribute
* name short to avoid overflowing the name-buffer.
- * */
+ */
void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count)
{
/* Sanity check. Maximum can be upgraded if needed. */
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 1d76b07c966..573ae654af4 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -96,6 +96,11 @@ void GLBackend::platform_init()
GPG.device = GPU_DEVICE_SOFTWARE;
GPG.driver = GPU_DRIVER_SOFTWARE;
}
+ else if (strstr(vendor, "Apple")) {
+ /* Apple Silicon. */
+ GPG.device = GPU_DEVICE_APPLE;
+ GPG.driver = GPU_DRIVER_OFFICIAL;
+ }
else if (strstr(renderer, "Apple Software Renderer")) {
GPG.device = GPU_DEVICE_SOFTWARE;
GPG.driver = GPU_DRIVER_SOFTWARE;
@@ -244,15 +249,16 @@ static void detect_workarounds()
if (!GLEW_VERSION_4_0) {
GLContext::base_instance_support = false;
}
- /* The renderers include:
- * Mobility Radeon HD 5000;
- * Radeon HD 7500M;
- * Radeon HD 7570M;
- * Radeon HD 7600M;
- * And many others... */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) &&
(strstr(version, "4.5.13399") || strstr(version, "4.5.13417") ||
- strstr(version, "4.5.13422"))) {
+ strstr(version, "4.5.13422") || strstr(version, "4.5.13467"))) {
+ /* The renderers include:
+ * Radeon HD 5000;
+ * Radeon HD 7500M;
+ * Radeon HD 7570M;
+ * Radeon HD 7600M;
+ * Radeon R5 Graphics;
+ * And others... */
GLContext::unused_fb_slot_workaround = true;
GCaps.mip_render_workaround = true;
GCaps.shader_image_load_store_support = false;
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index 3f444172499..eb31b0e9f87 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1878,7 +1878,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
/*---------------------------------------------------
* plugin interface
- * */
+ */
void itasc_initialize_tree(struct Depsgraph *depsgraph,
struct Scene *scene,
Object *ob,
diff --git a/source/blender/imbuf/intern/IMB_allocimbuf.h b/source/blender/imbuf/intern/IMB_allocimbuf.h
index 08aa1936a6f..c92d764a104 100644
--- a/source/blender/imbuf/intern/IMB_allocimbuf.h
+++ b/source/blender/imbuf/intern/IMB_allocimbuf.h
@@ -32,7 +32,7 @@ struct ImBuf;
void imb_refcounter_lock_init(void);
void imb_refcounter_lock_exit(void);
-#ifdef WIN32
+#ifndef WIN32
void imb_mmap_lock_init(void);
void imb_mmap_lock_exit(void);
void imb_mmap_lock(void);
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 8dfb3ada7d6..bfb7bc93ac7 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -53,7 +53,7 @@ void imb_refcounter_lock_exit(void)
BLI_spin_end(&refcounter_spin);
}
-#ifdef WIN32
+#ifndef WIN32
static SpinLock mmap_spin;
void imb_mmap_lock_init(void)
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h
index 0271c7964b8..9c3d73bbb0d 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.h
+++ b/source/blender/imbuf/intern/dds/ColorBlock.h
@@ -25,7 +25,7 @@
* Original license from NVIDIA follows.
*/
-// This code is in the public domain -- castanyo@yahoo.es
+// This code is in the public domain -- <castanyo@yahoo.es>
#pragma once
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index cce264624ce..343c8cd8f64 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -425,7 +425,7 @@ static int check_pixel_assigned(
*
* When a mask is given, only effect pixels with a mask value of 1,
* defined as #BAKE_MASK_MARGIN in rendercore.c
- * */
+ */
void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
{
const int width = ibuf->x;
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index f0daa4543e1..50210650f05 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -23,13 +23,13 @@
*/
#ifdef _WIN32
-# include "mmap_win.h"
# include <io.h>
# include <stddef.h>
# include <sys/types.h>
#endif
#include "BLI_fileops.h"
+#include "BLI_mmap.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -186,20 +186,19 @@ ImBuf *IMB_loadifffile(
size = BLI_file_descriptor_size(file);
imb_mmap_lock();
- mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0);
+ BLI_mmap_file *mmap_file = BLI_mmap_open(file);
imb_mmap_unlock();
-
- if (mem == (unsigned char *)-1) {
+ if (mmap_file == NULL) {
fprintf(stderr, "%s: couldn't get mapping %s\n", __func__, descr);
return NULL;
}
+ mem = BLI_mmap_get_pointer(mmap_file);
+
ibuf = IMB_ibImageFromMemory(mem, size, flags, colorspace, descr);
imb_mmap_lock();
- if (munmap(mem, size)) {
- fprintf(stderr, "%s: couldn't unmap file %s\n", __func__, descr);
- }
+ BLI_mmap_free(mmap_file);
imb_mmap_unlock();
return ibuf;
@@ -292,14 +291,15 @@ static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int
size = BLI_file_descriptor_size(file);
imb_mmap_lock();
- mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0);
+ BLI_mmap_file *mmap_file = BLI_mmap_open(file);
imb_mmap_unlock();
-
- if (mem == (unsigned char *)-1) {
+ if (mmap_file == NULL) {
fprintf(stderr, "Couldn't get memory mapping for %s\n", ibuf->cachename);
return;
}
+ mem = BLI_mmap_get_pointer(mmap_file);
+
const ImFileType *type = IMB_file_type_from_ibuf(ibuf);
if (type != NULL) {
if (type->load_tile != NULL) {
@@ -308,9 +308,7 @@ static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int
}
imb_mmap_lock();
- if (munmap(mem, size)) {
- fprintf(stderr, "Couldn't unmap memory for %s.\n", ibuf->cachename);
- }
+ BLI_mmap_free(mmap_file);
imb_mmap_unlock();
}
diff --git a/source/blender/io/alembic/exporter/abc_archive.cc b/source/blender/io/alembic/exporter/abc_archive.cc
index 68ad2089a3e..90a4baf97bc 100644
--- a/source/blender/io/alembic/exporter/abc_archive.cc
+++ b/source/blender/io/alembic/exporter/abc_archive.cc
@@ -112,7 +112,7 @@ static OArchive *create_archive(std::ofstream *abc_ostream,
*
* If 'time_relative' is true, samples are returned as time (in seconds) from params.frame_start.
* If 'time_relative' is false, samples are returned as fractional frames from 0.
- * */
+ */
static void get_shutter_samples(double scene_fps,
const AlembicExportParams &params,
int nr_of_samples,
diff --git a/source/blender/io/common/IO_dupli_persistent_id.hh b/source/blender/io/common/IO_dupli_persistent_id.hh
index 6fabafd9d51..afc539636ac 100644
--- a/source/blender/io/common/IO_dupli_persistent_id.hh
+++ b/source/blender/io/common/IO_dupli_persistent_id.hh
@@ -41,7 +41,7 @@ class PersistentID {
PersistentID();
explicit PersistentID(const DupliObject *dupli_ob);
- /* Return true iff the persistent IDs are the same, ignoring the first digit. */
+ /* Return true if the persistent IDs are the same, ignoring the first digit. */
bool is_from_same_instancer_as(const PersistentID &other) const;
/* Construct the persistent ID of this instance's instancer. */
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 263ce2203e9..26824216337 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -193,6 +193,10 @@ enum {
IDOVERRIDE_LIBRARY_FLAG_MANDATORY = 1 << 0,
/** User cannot change that override operation. */
IDOVERRIDE_LIBRARY_FLAG_LOCKED = 1 << 1,
+
+ /** For overrides of ID pointers: this override still matches (follows) the hierarchy of the
+ * reference linked data. */
+ IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE = 1 << 8,
};
/** A single overridden property, contain all operations on this one. */
@@ -254,7 +258,7 @@ typedef struct IDOverrideLibrary {
/**
* ID is the first thing included in all serializable types. It
* provides a common handle to place all data in double-linked lists.
- * */
+ */
/* 2 characters for ID code and 64 for actual name */
#define MAX_ID_NAME 66
@@ -449,7 +453,7 @@ typedef enum ID_Type {
ID_TXT = MAKE_ID2('T', 'X'), /* Text */
ID_SPK = MAKE_ID2('S', 'K'), /* Speaker */
ID_SO = MAKE_ID2('S', 'O'), /* Sound */
- ID_GR = MAKE_ID2('G', 'R'), /* Group */
+ ID_GR = MAKE_ID2('G', 'R'), /* Collection */
ID_AR = MAKE_ID2('A', 'R'), /* bArmature */
ID_AC = MAKE_ID2('A', 'C'), /* bAction */
ID_NT = MAKE_ID2('N', 'T'), /* bNodeTree */
@@ -468,7 +472,7 @@ typedef enum ID_Type {
ID_HA = MAKE_ID2('H', 'A'), /* Hair */
ID_PT = MAKE_ID2('P', 'T'), /* PointCloud */
ID_VO = MAKE_ID2('V', 'O'), /* Volume */
- ID_SIM = MAKE_ID2('S', 'I'), /* Simulation (currently unused) */
+ ID_SIM = MAKE_ID2('S', 'I'), /* Simulation (geometry node groups) */
} ID_Type;
/* Only used as 'placeholder' in .blend files for directly linked data-blocks. */
@@ -685,7 +689,7 @@ typedef enum IDRecalcFlag {
* redraw update in that case. */
/* Selection of the ID itself or its components (for example, vertices) did
- * change, and all the drawing data is to eb updated. */
+ * change, and all the drawing data is to be updated. */
ID_RECALC_SELECT = (1 << 9),
/* Flags on the base did change, and is to be copied onto all the copies of
* corresponding objects. */
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 4b020019062..e373500a0ed 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -47,10 +47,13 @@ typedef struct BrushClone {
char _pad[4];
} BrushClone;
+#define GPENCIL_MIN_FILL_FAC 0.05f
+
typedef struct BrushGpencilSettings {
/** Amount of smoothing to apply to newly created strokes. */
float draw_smoothfac;
- char _pad2[4];
+ /** Fill zoom factor */
+ float fill_factor;
/** Amount of alpha strength to apply to newly created strokes. */
float draw_strength;
/** Amount of jitter to apply to newly created strokes. */
@@ -75,8 +78,8 @@ typedef struct BrushGpencilSettings {
float fill_threshold;
/** Number of pixel to consider the leak is too small (x 2). */
short fill_leak;
- /** Fill zoom factor */
- short fill_factor;
+ char _pad2[2];
+
int flag2;
/** Number of simplify steps. */
diff --git a/source/blender/makesdna/DNA_dynamicpaint_types.h b/source/blender/makesdna/DNA_dynamicpaint_types.h
index c8e09225432..e3dcd283efa 100644
--- a/source/blender/makesdna/DNA_dynamicpaint_types.h
+++ b/source/blender/makesdna/DNA_dynamicpaint_types.h
@@ -242,10 +242,12 @@ typedef struct DynamicPaintBrushSettings {
/** For fast RNA access. */
struct DynamicPaintModifierData *pmd;
- /* NOTE: Storing the particle system pointer here is very weak, as it prevents modfiers' data
+ /**
+ * \note Storing the particle system pointer here is very weak, as it prevents modifiers' data
* copying to be self-sufficient (extra external code needs to ensure the pointer remains valid
* when the modifier data is copied from one object to another). See e.g.
- * `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`. */
+ * `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`.
+ */
struct ParticleSystem *psys;
int flags;
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index fdb77bfd196..399bf6f0a6d 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -152,6 +152,7 @@
.factor_thickness = 0.0f, \
.factor_uvs = 0.0f, \
.noise_scale = 0.0f, \
+ .noise_offset = 0.0f, \
.step = 4, \
.layer_pass = 0, \
.seed = 1, \
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index 9ac40495887..1f7283a1c70 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -107,6 +107,8 @@ typedef struct NoiseGpencilModifierData {
float factor_uvs;
/** Noise Frequency scaling */
float noise_scale;
+ float noise_offset;
+ char _pad[4];
/** How many frames before recalculate randoms. */
int step;
/** Custom index for passes. */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 949b0bb5bf5..1dbfd547673 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -512,6 +512,11 @@ typedef struct bGPDlayer {
int act_mask;
char _pad2[4];
+ /** Layer transforms. */
+ float location[3], rotation[3], scale[3];
+ float layer_mat[4][4], layer_invmat[4][4];
+ char _pad3[4];
+
bGPDlayer_Runtime runtime;
} bGPDlayer;
@@ -574,7 +579,9 @@ typedef struct bGPdata_Runtime {
/** Temp stroke used for drawing. */
struct bGPDstroke *sbuffer_gps;
- char _pad[2];
+ /** Animation playing flag. */
+ short playing;
+
/** Material index of the stroke. */
short matid;
@@ -840,6 +847,8 @@ typedef enum eGP_DrawMode {
((flag & (GP_VERTEX_MASK_SELECTMODE_POINT | GP_VERTEX_MASK_SELECTMODE_STROKE | \
GP_VERTEX_MASK_SELECTMODE_SEGMENT)))
+#define GPENCIL_PLAY_ON(gpd) ((gpd) && ((gpd)->runtime.playing == 1))
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h
index 8601dcf76ac..860a9affb3e 100644
--- a/source/blender/makesdna/DNA_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_modifier_defaults.h
@@ -440,7 +440,7 @@
.renderlvl = 0, \
.totlvl = 0, \
.flags = eMultiresModifierFlag_UseCrease | eMultiresModifierFlag_ControlEdges, \
- .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, \
+ .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, \
.quality = 4, \
.boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL, \
}
@@ -622,7 +622,7 @@
.levels = 1, \
.renderLevels = 2, \
.flags = eSubsurfModifierFlag_UseCrease | eSubsurfModifierFlag_ControlEdges, \
- .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, \
+ .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, \
.quality = 3, \
.boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL, \
.emCache = NULL, \
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 3de4299e0bd..29421430e5d 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -984,10 +984,12 @@ enum {
typedef struct ParticleSystemModifierData {
ModifierData modifier;
- /* NOTE: Storing the particle system pointer here is very weak, as it prevents modfiers' data
+ /**
+ * \note Storing the particle system pointer here is very weak, as it prevents modifiers' data
* copying to be self-sufficient (extra external code needs to ensure the pointer remains valid
* when the modifier data is copied from one object to another). See e.g.
- * `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`. */
+ * `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`.
+ */
struct ParticleSystem *psys;
/** Final Mesh - its topology may differ from orig mesh. */
struct Mesh *mesh_final;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 7d18ff3ed58..0c92099e23b 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1089,14 +1089,15 @@ typedef struct NodeAttributeCompare {
} NodeAttributeCompare;
typedef struct NodeAttributeMath {
- /* e.g. NODE_MATH_ADD. */
+ /* NodeMathOperation. */
uint8_t operation;
/* GeometryNodeAttributeInputMode */
uint8_t input_type_a;
uint8_t input_type_b;
+ uint8_t input_type_c;
- char _pad[5];
+ char _pad[4];
} NodeAttributeMath;
typedef struct NodeAttributeMix {
@@ -1174,6 +1175,24 @@ typedef struct NodeGeometryObjectInfo {
char _pad[7];
} NodeGeometryObjectInfo;
+typedef struct NodeGeometryPointInstance {
+ /* GeometryNodePointInstanceType. */
+ uint8_t instance_type;
+ /* GeometryNodePointInstanceFlag. */
+ uint8_t flag;
+
+ char _pad[6];
+} NodeGeometryPointInstance;
+
+typedef struct NodeGeometryPointsToVolume {
+ /* GeometryNodePointsToVolumeResolutionMode */
+ uint8_t resolution_mode;
+ /* GeometryNodeAttributeInputMode */
+ uint8_t input_type_radius;
+
+ char _pad[6];
+} NodeGeometryPointsToVolume;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1369,7 +1388,7 @@ enum {
#define SHD_MATH_CLAMP 1
/* Math node operations. */
-enum {
+typedef enum NodeMathOperation {
NODE_MATH_ADD = 0,
NODE_MATH_SUBTRACT = 1,
NODE_MATH_MULTIPLY = 2,
@@ -1410,7 +1429,7 @@ enum {
NODE_MATH_PINGPONG = 37,
NODE_MATH_SMOOTH_MIN = 38,
NODE_MATH_SMOOTH_MAX = 39,
-};
+} NodeMathOperation;
/* Vector Math node operations. */
typedef enum NodeVectorMathOperation {
@@ -1586,6 +1605,10 @@ typedef enum GeometryNodePointInstanceType {
GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION = 1,
} GeometryNodePointInstanceType;
+typedef enum GeometryNodePointInstanceFlag {
+ GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION = (1 << 0),
+} GeometryNodePointInstanceFlag;
+
typedef enum GeometryNodeAttributeInputMode {
GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE = 0,
GEO_NODE_ATTRIBUTE_INPUT_FLOAT = 1,
@@ -1620,6 +1643,11 @@ typedef enum GeometryNodeTransformSpace {
GEO_NODE_TRANSFORM_SPACE_RELATIVE = 1,
} GeometryNodeTransformSpace;
+typedef enum GeometryNodePointsToVolumeResolutionMode {
+ GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT = 0,
+ GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE = 1,
+} GeometryNodePointsToVolumeResolutionMode;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 03f5d3f8d47..51f8b58da62 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -63,6 +63,9 @@ struct wmTimer;
/* Defined in `buttons_intern.h`. */
typedef struct SpaceProperties_Runtime SpaceProperties_Runtime;
+/* Defined in `node_intern.h`. */
+typedef struct SpaceNode_Runtime SpaceNode_Runtime;
+
/* -------------------------------------------------------------------- */
/** \name SpaceLink (Base)
* \{ */
@@ -1084,6 +1087,8 @@ typedef struct FileDirEntry {
struct FileDirEntry *next, *prev;
int uuid[4];
+ /* Name needs freeing if FILE_ENTRY_NAME_FREE is set. Otherwise this is a direct pointer to a
+ * name buffer. */
char *name;
char *description;
@@ -1162,6 +1167,7 @@ enum {
/* FileDirEntry.flags */
enum {
FILE_ENTRY_INVALID_PREVIEW = 1 << 0, /* The preview for this entry could not be generated. */
+ FILE_ENTRY_NAME_FREE = 1 << 1,
};
/** \} */
@@ -1518,19 +1524,17 @@ typedef struct SpaceNode {
/** Context, no need to save in file? well... pinning... */
struct ID *id, *from;
- /** Menunr: browse id block in header. */
+
short flag;
- char _pad1[2];
- /** Internal state variables. */
- float aspect;
- char _pad2[4];
+
+ /** Direction for offsetting nodes on insertion. */
+ char insert_ofs_dir;
+ char _pad1;
/** Offset for drawing the backdrop. */
float xof, yof;
/** Zoom for backdrop. */
float zoom;
- /** Mouse pos for drawing socketless link and adding nodes. */
- float cursor[2];
/**
* XXX nodetree pointer info is all in the path stack now,
@@ -1541,33 +1545,25 @@ typedef struct SpaceNode {
*/
ListBase treepath;
- struct bNodeTree *nodetree, *edittree;
+ /* The tree farthest down in the group heirarchy. */
+ struct bNodeTree *edittree;
+
+ struct bNodeTree *nodetree;
/* tree type for the current node tree */
char tree_idname[64];
/** Treetype: as same nodetree->type. */
int treetype DNA_DEPRECATED;
- char _pad3[4];
/** Texfrom object, world or brush. */
short texfrom;
/** Shader from object or world. */
short shaderfrom;
- /** Currently on 0/1, for auto compo. */
- short recalc;
-
- /** Direction for offsetting nodes on insertion. */
- char insert_ofs_dir;
- char _pad4;
-
- /** Temporary data for modal linking operator. */
- ListBase linkdrag;
- /* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */
- /** Temporary data for node insert offset (in UI called Auto-offset). */
- struct NodeInsertOfsData *iofsd;
/** Grease-pencil data. */
struct bGPdata *gpd;
+
+ SpaceNode_Runtime *runtime;
} SpaceNode;
/* SpaceNode.flag */
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index 5b6b706c83c..f08aee317a3 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -141,7 +141,7 @@ typedef struct MovieTrackingTrack {
/** Count of markers in track. */
int markersnr;
/** Most recently used marker. */
- int last_marker;
+ int _pad;
/** Markers in track. */
MovieTrackingMarker *markers;
@@ -251,8 +251,6 @@ typedef struct MovieTrackingPlaneTrack {
} MovieTrackingPlaneTrack;
typedef struct MovieTrackingSettings {
- int flag;
-
/* ** default tracker settings */
/** Model of the motion for this track. */
short default_motion_model;
@@ -309,8 +307,6 @@ typedef struct MovieTrackingSettings {
/* set object scale */
/** Distance between two bundles used for object scaling. */
float object_distance;
-
- char _pad3[4];
} MovieTrackingSettings;
typedef struct MovieTrackingStabilization {
@@ -526,12 +522,6 @@ typedef enum eTrackFrameMatch {
TRACK_MATCH_PREVIOS_FRAME = 1,
} eTrackFrameMatch;
-/* MovieTrackingSettings->flag */
-enum {
- TRACKING_SETTINGS_SHOW_DEFAULT_EXPANDED = (1 << 0),
- TRACKING_SETTINGS_SHOW_EXTRA_EXPANDED = (1 << 1),
-};
-
/* MovieTrackingSettings->motion_flag */
enum {
TRACKING_MOTION_TRIPOD = (1 << 0),
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index f620602f051..790f3423eef 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -762,8 +762,12 @@ typedef struct UserDef {
char _pad13[4];
struct SolidLight light_param[4];
float light_ambient[3];
- char _pad3[4];
- short gizmo_flag, gizmo_size;
+ char gizmo_flag;
+ /** Generic gizmo size. */
+ char gizmo_size;
+ /** Navigate gizmo size. */
+ char gizmo_size_navigate_v3d;
+ char _pad3[5];
short edit_studio_light;
short lookdev_sphere_size;
short vbotimeout, vbocollectrate;
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index eb7779213fd..db34cf83fa9 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -48,12 +48,6 @@ set(SRC
../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c
)
-if(WIN32 AND NOT UNIX)
- list(APPEND SRC
- ../../../../intern/guardedalloc/intern/mmap_win.c
- )
-endif()
-
# SRC_DNA_INC is defined in the parent dir
add_cc_flags_custom_test(makesdna)
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 54d2bc88d16..843e6935416 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -397,13 +397,11 @@ static int add_type(const char *str, int size)
}
/**
- *
* Because of the weird way of tokenizing, we have to 'cast' function
* pointers to ... (*f)(), whatever the original signature. In fact,
* we add name and type at the same time... There are two special
* cases, unfortunately. These are explicitly checked.
- *
- * */
+ */
static int add_name(const char *str)
{
char buf[255]; /* stupid limit, change it :) */
@@ -479,17 +477,16 @@ static int add_name(const char *str)
}
/*
- * Put )(void) at the end? Maybe )(). Should check this with
- * old sdna. Actually, sometimes )(), sometimes )(void...)
+ * Put `)(void)` at the end? Maybe `)()`. Should check this with
+ * old `sdna`. Actually, sometimes `)()`, sometimes `)(void...)`
* Alas.. such is the nature of brain-damage :(
*
- * Sorted it out: always do )(), except for headdraw and
- * windraw, part of ScrArea. This is important, because some
+ * Sorted it out: always do )(), except for `headdraw` and
+ * `windraw`, part of #ScrArea. This is important, because some
* linkers will treat different fp's differently when called
* !!! This has to do with interference in byte-alignment and
- * the way args are pushed on the stack.
- *
- * */
+ * the way arguments are pushed on the stack.
+ */
buf[i] = 0;
DEBUG_PRINTF(3, "Name before chomping: %s\n", buf);
if ((strncmp(buf, "(*headdraw", 10) == 0) || (strncmp(buf, "(*windraw", 9) == 0)) {
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 72cdaecb2c3..94cfd8464ae 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -189,7 +189,6 @@ set(SRC
../../../../intern/guardedalloc/intern/mallocn.c
../../../../intern/guardedalloc/intern/mallocn_guarded_impl.c
../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c
- ../../../../intern/guardedalloc/intern/mmap_win.c
# Needed for defaults.
../../../../release/datafiles/userdef/userdef_default.c
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index e9e00ff6f71..bec3db10905 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -4758,8 +4758,14 @@ static const char *cpp_classes =
"class CollectionIterator {\n"
"public:\n"
" CollectionIterator() : iter(), t(iter.ptr), init(false) { iter.valid = false; }\n"
+ " CollectionIterator(const PointerRNA &ptr) : CollectionIterator() { this->begin(ptr); }\n"
" ~CollectionIterator(void) { if (init) Tend(&iter); };\n"
"\n"
+ " CollectionIterator(const CollectionIterator &other) = delete;\n"
+ " CollectionIterator(CollectionIterator &&other) = delete;\n"
+ " CollectionIterator &operator=(const CollectionIterator &other) = delete;\n"
+ " CollectionIterator &operator=(CollectionIterator &&other) = delete;\n"
+ "\n"
" operator bool(void)\n"
" { return iter.valid != 0; }\n"
" const CollectionIterator<T, Tbegin, Tnext, Tend>& operator++() { Tnext(&iter); t = "
@@ -4777,9 +4783,6 @@ static const char *cpp_classes =
"true; }\n"
"\n"
"private:\n"
- " const CollectionIterator<T, Tbegin, Tnext, Tend>& operator = "
- "(const CollectionIterator<T, Tbegin, Tnext, Tend>& /*copy*/) {}\n"
- ""
" CollectionPropertyIterator iter;\n"
" T t;\n"
" bool init;\n"
@@ -4794,6 +4797,8 @@ static const char *cpp_classes =
"\n"
" void begin(CollectionIterator<T, Tbegin, Tnext, Tend>& iter)\n"
" { iter.begin(ptr); }\n"
+ " CollectionIterator<T, Tbegin, Tnext, Tend> begin()\n"
+ " { return CollectionIterator<T, Tbegin, Tnext, Tend>(ptr); }\n"
" CollectionIterator<T, Tbegin, Tnext, Tend> end()\n"
" { return CollectionIterator<T, Tbegin, Tnext, Tend>(); } /* test */ \n"
""
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index 1e7f5e841ba..2d6f1bbc059 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -42,6 +42,7 @@
#include "BKE_armature.h"
#include "BKE_idprop.h"
+#include "BKE_idtype.h"
#include "BKE_lib_override.h"
#include "BKE_main.h"
@@ -1178,6 +1179,17 @@ void RNA_struct_override_apply(Main *bmain,
#endif
}
}
+
+ /* Some cases (like point caches) may require additional post-processing. */
+ if (RNA_struct_is_a(ptr_dst->type, &RNA_ID)) {
+ ID *id_dst = ptr_dst->data;
+ ID *id_src = ptr_src->data;
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id_dst);
+ if (id_type->lib_override_apply_post != NULL) {
+ id_type->lib_override_apply_post(id_dst, id_src);
+ }
+ }
+
#ifdef DEBUG_OVERRIDE_TIMEIT
TIMEIT_END_AVERAGED(RNA_struct_override_apply);
#endif
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 2af6c04147c..4f98c6e8e07 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1464,13 +1464,13 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* fill factor size */
- prop = RNA_def_property(srna, "fill_factor", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "fill_factor");
- RNA_def_property_range(prop, 1, 8);
+ prop = RNA_def_property(srna, "fill_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "fill_factor");
+ RNA_def_property_range(prop, GPENCIL_MIN_FILL_FAC, 8.0f);
RNA_def_property_ui_text(
prop,
- "Resolution",
- "Multiplier for fill resolution, higher resolution is more accurate but slower");
+ "Precision",
+ "Factor for fill boundary accuracy, higher values are more accurate but slower");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index cec6a50d170..da04ac63ee3 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -4111,6 +4111,16 @@ PropertyRNA *RNA_def_float_percentage(StructOrFunctionRNA *cont_,
ASSERT_SOFT_HARD_LIMITS;
+#ifdef DEBUG
+ /* Properties with PROP_PERCENTAGE should use a range like 0 to 100, unlike PROP_FACTOR. */
+ if (hardmax < 2.0f) {
+ CLOG_WARN(&LOG,
+ "Percentage property with incorrect range: %s.%s",
+ CONTAINER_RNA_ID(cont),
+ identifier);
+ }
+#endif
+
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_float_default(prop, default_value);
if (hardmin != hardmax) {
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 81e20003d8f..209dc21d386 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -182,6 +182,16 @@ static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
+static void rna_GpencilLayerMatrix_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bGPDlayer *gpl = (bGPDlayer *)ptr->data;
+
+ loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
+ invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
+
+ rna_GPencil_update(bmain, scene, ptr);
+}
+
static void rna_GPencil_curve_edit_mode_toggle(Main *bmain, Scene *scene, PointerRNA *ptr)
{
ToolSettings *ts = scene->toolsettings;
@@ -940,7 +950,7 @@ static void rna_GPencil_frame_remove(bGPDlayer *layer, ReportList *reports, Poin
static bGPDframe *rna_GPencil_frame_copy(bGPDlayer *layer, bGPDframe *src)
{
- bGPDframe *frame = BKE_gpencil_frame_duplicate(src);
+ bGPDframe *frame = BKE_gpencil_frame_duplicate(src, true);
while (BKE_gpencil_layer_frame_find(layer, frame->framenum)) {
frame->framenum++;
@@ -2012,6 +2022,45 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Blend Mode", "Blend mode");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ /* Layer transforms. */
+ prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_float_sdna(prop, NULL, "location");
+ RNA_def_property_ui_text(prop, "Location", "Values for change location");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_update(prop, 0, "rna_GpencilLayerMatrix_update");
+
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
+ RNA_def_property_float_sdna(prop, NULL, "rotation");
+ RNA_def_property_ui_text(prop, "Rotation", "Values for changes in rotation");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_update(prop, 0, "rna_GpencilLayerMatrix_update");
+
+ prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Scale", "Values for changes in scale");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_update(prop, 0, "rna_GpencilLayerMatrix_update");
+
+ /* Layer matrix. */
+ prop = RNA_def_property(srna, "matrix_layer", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_float_sdna(prop, NULL, "layer_mat");
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Matrix Layer", "Local Layer transformation matrix");
+
+ /* Layer inverse matrix. */
+ prop = RNA_def_property(srna, "matrix_inverse_layer", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_float_sdna(prop, NULL, "layer_invmat");
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(
+ prop, "Matrix Layer Inverse", "Local Layer transformation inverse matrix");
+
/* Flags */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 89eb989a442..71d5a53adb2 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -489,7 +489,7 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_ui_text(prop, "Seed", "Random seed");
+ RNA_def_property_ui_text(prop, "Noise Seed", "Random seed");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_FACTOR);
@@ -498,6 +498,13 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Noise Scale", "Scale the noise frequency");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "noise_offset", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "noise_offset");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Noise Offset", "Offset the noise along the strokes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_CUSTOM_CURVE);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index e02e47745b0..c13f592f7fb 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1632,33 +1632,35 @@ static IDProperty *rna_NodesModifier_properties(PointerRNA *ptr, bool create)
static void rna_def_property_subdivision_common(StructRNA *srna)
{
static const EnumPropertyItem prop_uv_smooth_items[] = {
- {SUBSURF_UV_SMOOTH_NONE, "NONE", 0, "None", "UVs are not smoothed, boundaries are kept sharp"},
- {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS,
- "PRESERVE_CORNERS",
- 0,
- "Keep Corners",
- "UVs are smoothed, corners on discontinuous boundary are kept sharp"},
-# if 0
- {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS,
- "PRESERVE_CORNERS_AND_JUNCTIONS",
- 0,
- "Smooth, keep corners+junctions",
- "UVs are smoothed, corners on discontinuous boundary and "
- "junctions of 3 or more regions are kept sharp"},
- {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE,
- "PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE",
- 0,
- "Smooth, keep corners+junctions+concave",
- "UVs are smoothed, corners on discontinuous boundary, "
- "junctions of 3 or more regions and darts and concave corners are kept sharp"},
- {SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES,
- "PRESERVE_BOUNDARIES",
- 0,
- "Smooth, keep corners",
- "UVs are smoothed, boundaries are kept sharp"},
-# endif
- {SUBSURF_UV_SMOOTH_ALL, "PRESERVE_BOUNDARIES", 0, "All", "UVs and boundaries are smoothed"},
- {0, NULL, 0, NULL, NULL},
+ {SUBSURF_UV_SMOOTH_NONE,
+ "NONE",
+ 0,
+ "None",
+ "UVs are not smoothed, boundaries are kept sharp"},
+ {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS,
+ "PRESERVE_CORNERS",
+ 0,
+ "Keep Corners",
+ "UVs are smoothed, corners on discontinuous boundary are kept sharp"},
+ {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS,
+ "PRESERVE_CORNERS_AND_JUNCTIONS",
+ 0,
+ "Keep Corners, Junctions",
+ "UVs are smoothed, corners on discontinuous boundary and "
+ "junctions of 3 or more regions are kept sharp"},
+ {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE,
+ "PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE",
+ 0,
+ "Keep Corners, Junctions, Concave",
+ "UVs are smoothed, corners on discontinuous boundary, "
+ "junctions of 3 or more regions and darts and concave corners are kept sharp"},
+ {SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES,
+ "PRESERVE_BOUNDARIES",
+ 0,
+ "Keep boundaries",
+ "UVs are smoothed, boundaries are kept sharp"},
+ {SUBSURF_UV_SMOOTH_ALL, "SMOOTH_ALL", 0, "All", "UVs and boundaries are smoothed"},
+ {0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem prop_boundary_smooth_items[] = {
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 5afc892820c..a5a73d9d8ca 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -1964,22 +1964,6 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeFill_domain_itemf(
return itemf_function_check(rna_enum_attribute_domain_items, attribute_fill_domain_supported);
}
-static bool attribute_math_operation_supported(const EnumPropertyItem *item)
-{
- return ELEM(item->value,
- NODE_MATH_ADD,
- NODE_MATH_SUBTRACT,
- NODE_MATH_MULTIPLY,
- NODE_MATH_DIVIDE) &&
- (item->identifier[0] != '\0');
-}
-static const EnumPropertyItem *rna_GeometryNodeAttributeMath_operation_itemf(
- bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- *r_free = true;
- return itemf_function_check(rna_enum_node_math_items, attribute_math_operation_supported);
-}
-
/**
* This bit of ugly code makes sure the float / attribute option shows up instead of
* vector / attribute if the node uses an operation that uses a float for input B.
@@ -4741,9 +4725,10 @@ static void def_sh_tex_sky(StructRNA *srna)
RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
- prop = RNA_def_property(srna, "altitude", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "altitude", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_ui_text(prop, "Altitude", "Height from sea level");
- RNA_def_property_range(prop, 0.0f, 60.0f);
+ RNA_def_property_range(prop, 0.0f, 60000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 60000.0f, 10, 1);
RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -8563,10 +8548,9 @@ static void def_geo_attribute_math(StructRNA *srna)
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "operation");
RNA_def_property_enum_items(prop, rna_enum_node_math_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeMath_operation_itemf");
RNA_def_property_enum_default(prop, NODE_MATH_ADD);
RNA_def_property_ui_text(prop, "Operation", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_a");
@@ -8579,6 +8563,12 @@ static void def_geo_attribute_math(StructRNA *srna)
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
RNA_def_property_ui_text(prop, "Input Type B", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "input_type_c", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_c");
+ RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
+ RNA_def_property_ui_text(prop, "Input Type C", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_attribute_vector_math(StructRNA *srna)
@@ -8632,16 +8622,17 @@ static void def_geo_point_instance(StructRNA *srna)
};
PropertyRNA *prop;
+ RNA_def_struct_sdna_from(srna, "NodeGeometryPointInstance", "storage");
prop = RNA_def_property(srna, "instance_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_sdna(prop, NULL, "instance_type");
RNA_def_property_enum_items(prop, instance_type_items);
RNA_def_property_enum_default(prop, GEO_NODE_POINT_INSTANCE_TYPE_OBJECT);
RNA_def_property_ui_text(prop, "Instance Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "use_whole_collection", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "custom2", 1);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION);
RNA_def_property_ui_text(prop, "Whole Collection", "Instance entire collection on each point");
RNA_def_property_update(prop, 0, "rna_Node_socket_update");
}
@@ -8682,7 +8673,7 @@ static void def_geo_attribute_attribute_compare(StructRNA *srna)
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_node_float_compare_items);
- RNA_def_property_enum_default(prop, NODE_MATH_ADD);
+ RNA_def_property_enum_default(prop, NODE_FLOAT_COMPARE_GREATER_THAN);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
@@ -8846,6 +8837,19 @@ static void def_geo_point_translate(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_attribute_sample_texture(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "id");
+ RNA_def_property_struct_type(prop, "Texture");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Texture", "Texture to sample values from");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update_relations");
+}
+
static void def_geo_object_info(StructRNA *srna)
{
PropertyRNA *prop;
@@ -8876,6 +8880,37 @@ static void def_geo_object_info(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_geo_points_to_volume(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem resolution_mode_items[] = {
+ {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT,
+ "VOXEL_AMOUNT",
+ 0,
+ "Amount",
+ "Specify the approximate number of voxels along the diagonal"},
+ {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE,
+ "VOXEL_SIZE",
+ 0,
+ "Size",
+ "Specify the voxel side length"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryPointsToVolume", "storage");
+
+ prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, resolution_mode_items);
+ RNA_def_property_ui_text(prop, "Resolution Mode", "How the voxel size is specified");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "input_type_radius", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
+ RNA_def_property_ui_text(prop, "Radius Input Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index faa20e642cf..c418c8eb4dc 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -85,16 +85,16 @@ const EnumPropertyItem rna_enum_object_mode_items[] = {
ICON_GREASEPENCIL,
"Draw",
"Paint Grease Pencil Strokes"},
- {OB_MODE_VERTEX_GPENCIL,
- "VERTEX_GPENCIL",
- ICON_VPAINT_HLT,
- "Vertex Paint",
- "Grease Pencil Vertex Paint Strokes"},
{OB_MODE_WEIGHT_GPENCIL,
"WEIGHT_GPENCIL",
ICON_WPAINT_HLT,
"Weight Paint",
"Grease Pencil Weight Paint Strokes"},
+ {OB_MODE_VERTEX_GPENCIL,
+ "VERTEX_GPENCIL",
+ ICON_VPAINT_HLT,
+ "Vertex Paint",
+ "Grease Pencil Vertex Paint Strokes"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 3126f3e11f4..0c2860c05e7 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -848,6 +848,14 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Use Eevee Viewport", "Uses Eevee for viewport shading in LookDev shading mode");
+ prop = RNA_def_property(srna, "bl_use_custom_freestyle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_CUSTOM_FREESTYLE);
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_ui_text(
+ prop,
+ "Use Custom Freestyle",
+ "Handles freestyle rendering on its own, instead of delegating it to EEVEE");
+
prop = RNA_def_property(srna, "bl_use_gpu_context", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_GPU_CONTEXT);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index c929e3ab1aa..cad0d77607b 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -1279,12 +1279,22 @@ static int rna_property_override_diff_propptr(Main *bmain,
0);
if (is_id) {
- /* For now, once we deal with nodetrees we'll want to get rid of that one. */
- // BLI_assert(no_ownership);
+ /* Owned IDs (the ones we want to actually compare in depth, instead of just comparing pointer
+ * values) should be always properly tagged as 'virtual' overrides. */
+ ID *id = propptr_a->owner_id;
+ if (id != NULL && !ID_IS_OVERRIDE_LIBRARY(id)) {
+ id = propptr_b->owner_id;
+ if (id != NULL && !ID_IS_OVERRIDE_LIBRARY(id)) {
+ id = NULL;
+ }
+ }
+
+ BLI_assert(no_ownership || id == NULL || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id));
+ UNUSED_VARS_NDEBUG(id);
}
if (override) {
- if (no_ownership /* || is_id */ || is_null || is_type_diff || !is_valid_for_diffing) {
+ if (no_ownership || is_null || is_type_diff || !is_valid_for_diffing) {
/* In case this pointer prop does not own its data (or one is NULL), do not compare structs!
* This is a quite safe path to infinite loop, among other nasty issues.
* Instead, just compare pointers themselves. */
@@ -1304,9 +1314,9 @@ static int rna_property_override_diff_propptr(Main *bmain,
BLI_assert(op->rna_prop_type == property_type);
}
+ IDOverrideLibraryPropertyOperation *opop = NULL;
if (created || rna_itemname_a != NULL || rna_itemname_b != NULL ||
rna_itemindex_a != -1 || rna_itemindex_b != -1) {
- IDOverrideLibraryPropertyOperation *opop;
opop = BKE_lib_override_library_property_operation_get(op,
IDOVERRIDE_LIBRARY_OP_REPLACE,
rna_itemname_b,
@@ -1327,6 +1337,38 @@ static int rna_property_override_diff_propptr(Main *bmain,
else {
BKE_lib_override_library_operations_tag(op, IDOVERRIDE_LIBRARY_TAG_UNUSED, false);
}
+
+ if (is_id && no_ownership) {
+ if (opop == NULL) {
+ opop = BKE_lib_override_library_property_operation_find(op,
+ rna_itemname_b,
+ rna_itemname_a,
+ rna_itemindex_b,
+ rna_itemindex_a,
+ true,
+ NULL);
+ BLI_assert(opop != NULL);
+ }
+
+ BLI_assert(propptr_a->data == propptr_a->owner_id);
+ BLI_assert(propptr_b->data == propptr_b->owner_id);
+ ID *id_a = propptr_a->data;
+ ID *id_b = propptr_b->data;
+ if (ELEM(NULL, id_a, id_b)) {
+ /* In case one of the pointer is NULL and not the other, we consider that the
+ * override is not matching its reference anymore. */
+ opop->flag &= ~IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE;
+ }
+ else if (id_a->override_library != NULL && id_a->override_library->reference == id_b) {
+ opop->flag |= IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE;
+ }
+ else if (id_b->override_library != NULL && id_b->override_library->reference == id_a) {
+ opop->flag |= IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE;
+ }
+ else {
+ opop->flag &= ~IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE;
+ }
+ }
}
}
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 8f3b254e6e1..06757e533a2 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -2279,6 +2279,20 @@ static bool rna_SpaceNodeEditor_tree_type_poll(void *Cv, bNodeTreeType *type)
}
}
+static void rna_SpaceNodeEditor_cursor_location_get(PointerRNA *ptr, float value[2])
+{
+ const SpaceNode *snode = (SpaceNode *)ptr->data;
+
+ ED_node_cursor_location_get(snode, value);
+}
+
+static void rna_SpaceNodeEditor_cursor_location_set(PointerRNA *ptr, const float value[2])
+{
+ SpaceNode *snode = (SpaceNode *)ptr->data;
+
+ ED_node_cursor_location_set(snode, value);
+}
+
const EnumPropertyItem *RNA_enum_node_tree_types_itemf_impl(bContext *C, bool *r_free)
{
return rna_node_tree_type_itemf(C, rna_SpaceNodeEditor_tree_type_poll, r_free);
@@ -2346,9 +2360,13 @@ static void rna_SpaceNodeEditor_cursor_location_from_region(SpaceNode *snode,
{
ARegion *region = CTX_wm_region(C);
- UI_view2d_region_to_view(&region->v2d, x, y, &snode->cursor[0], &snode->cursor[1]);
- snode->cursor[0] /= UI_DPI_FAC;
- snode->cursor[1] /= UI_DPI_FAC;
+ float cursor_location[2];
+
+ UI_view2d_region_to_view(&region->v2d, x, y, &cursor_location[0], &cursor_location[1]);
+ cursor_location[0] /= UI_DPI_FAC;
+ cursor_location[1] /= UI_DPI_FAC;
+
+ ED_node_cursor_location_set(snode, cursor_location);
}
static void rna_SpaceClipEditor_clip_set(PointerRNA *ptr,
@@ -6818,11 +6836,13 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_enum_items(prop, backdrop_channels_items);
RNA_def_property_ui_text(prop, "Display Channels", "Channels of the image to draw");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
-
/* the mx/my "cursor" in the node editor is used only by operators to store the mouse position */
prop = RNA_def_property(srna, "cursor_location", PROP_FLOAT, PROP_XYZ);
RNA_def_property_array(prop, 2);
- RNA_def_property_float_sdna(prop, NULL, "cursor");
+ RNA_def_property_float_funcs(prop,
+ "rna_SpaceNodeEditor_cursor_location_get",
+ "rna_SpaceNodeEditor_cursor_location_set",
+ NULL);
RNA_def_property_ui_text(prop, "Cursor Location", "Location for adding new nodes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 1870c660efd..bcf75fb284f 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -976,22 +976,6 @@ static void rna_def_trackingSettings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, cleanup_items);
RNA_def_property_ui_text(prop, "Action", "Cleanup action to execute");
- /* ** default tracker settings ** */
- prop = RNA_def_property(srna, "show_default_expanded", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_SETTINGS_SHOW_DEFAULT_EXPANDED);
- RNA_def_property_ui_text(
- prop, "Show Expanded", "Show default options expanded in the user interface");
- RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
-
- /* ** extra tracker settings ** */
- prop = RNA_def_property(srna, "show_extra_expanded", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_SETTINGS_SHOW_EXTRA_EXPANDED);
- RNA_def_property_ui_text(
- prop, "Show Expanded", "Show extra options expanded in the user interface");
- RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
-
/* solver settings */
prop = RNA_def_property(srna, "use_tripod_solver", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 8a836eb7376..8d4578067f9 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -4762,6 +4762,11 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Gizmo Size", "Diameter of the gizmo");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "gizmo_size_navigate_v3d", PROP_INT, PROP_PIXEL);
+ RNA_def_property_range(prop, 30, 200);
+ RNA_def_property_ui_text(prop, "Navigate Gizmo Size", "The Navigate Gizmo size");
+ RNA_def_property_update(prop, 0, "rna_userdef_gizmo_update");
+
/* Lookdev */
prop = RNA_def_property(srna, "lookdev_sphere_size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "lookdev_sphere_size");
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index f3d6cf49dd6..6ce288e8ac5 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -221,18 +221,21 @@ class GeometryNodesEvaluator {
const blender::nodes::DataTypeConversions &conversions_;
const PersistentDataHandleMap &handle_map_;
const Object *self_object_;
+ Depsgraph *depsgraph_;
public:
GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data,
Vector<const DInputSocket *> group_outputs,
blender::nodes::MultiFunctionByNode &mf_by_node,
const PersistentDataHandleMap &handle_map,
- const Object *self_object)
+ const Object *self_object,
+ Depsgraph *depsgraph)
: group_outputs_(std::move(group_outputs)),
mf_by_node_(mf_by_node),
conversions_(blender::nodes::get_implicit_type_conversions()),
handle_map_(handle_map),
- self_object_(self_object)
+ self_object_(self_object),
+ depsgraph_(depsgraph)
{
for (auto item : group_input_data.items()) {
this->forward_to_inputs(*item.key, item.value);
@@ -306,7 +309,8 @@ class GeometryNodesEvaluator {
/* Execute the node. */
GValueMap<StringRef> node_outputs_map{allocator_};
- GeoNodeExecParams params{bnode, node_inputs_map, node_outputs_map, handle_map_, self_object_};
+ GeoNodeExecParams params{
+ bnode, node_inputs_map, node_outputs_map, handle_map_, self_object_, depsgraph_};
this->execute_node(node, params);
/* Forward computed outputs to linked input sockets. */
@@ -926,7 +930,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
group_outputs.append(&socket_to_compute);
GeometryNodesEvaluator evaluator{
- group_inputs, group_outputs, mf_by_node, handle_map, ctx->object};
+ group_inputs, group_outputs, mf_by_node, handle_map, ctx->object, ctx->depsgraph};
Vector<GMutablePointer> results = evaluator.execute();
BLI_assert(results.size() == 1);
GMutablePointer result = results[0];
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index ba370b401f3..b59907cc1e9 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -486,9 +486,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/*
* Normal Calculation (for face flipping)
* Sort edge verts for correct face flipping
- * NOT REALLY NEEDED but face flipping is nice.
- *
- * */
+ * NOT REALLY NEEDED but face flipping is nice. */
/* Notice!
*
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index 0fad78683eb..008e258dc7a 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -114,7 +114,12 @@ typedef struct SDefBindPoly {
float weight_dist_proj;
float weight_dist;
float weight;
+ /** Distances from the centroid to edges flanking the corner vertex, used to penalize
+ * small or long and narrow faces in favor of bigger and more square ones. */
float scales[2];
+ /** Distance weight from the corner vertex to the chord line, used to penalize
+ * cases with the three consecutive vertices being nearly in line. */
+ float scale_mid;
/** Center of `coords` */
float centroid[3];
/** Center of `coords_v2` */
@@ -123,15 +128,18 @@ typedef struct SDefBindPoly {
* The calculated normal of coords (could be shared between faces).
*/
float normal[3];
+ /** Vectors pointing from the centroid to the midpoints of the two edges
+ * flanking the corner vertex. */
float cent_edgemid_vecs_v2[2][2];
- /**
- * The unsigned angle of this face-corner in `[0.0 .. PI]` range,
- * where a small value is a thin corner. PI is a straight line.
- * Take care dividing by this value as it can approach zero.
- */
+ /** Angle between the cent_edgemid_vecs_v2 vectors. */
float edgemid_angle;
+ /** Angles between the centroid-to-point and cent_edgemid_vecs_v2 vectors.
+ * Positive values measured towards the corner; clamped non-negative. */
float point_edgemid_angles[2];
+ /** Angles between the centroid-to-corner and cent_edgemid_vecs_v2 vectors. */
float corner_edgemid_angles[2];
+ /** Weight of the bind mode based on the corner and two adjacent vertices,
+ * versus the one based on the centroid and the dominant edge. */
float dominant_angle_weight;
/** Index of the input polygon. */
uint index;
@@ -414,13 +422,14 @@ BLI_INLINE uint nearestVert(SDefBindCalcData *const data, const float point_co[3
BLI_INLINE int isPolyValid(const float coords[][2], const uint nr)
{
- float prev_co[2];
+ float prev_co[2], prev_prev_co[2];
float curr_vec[2], prev_vec[2];
if (!is_poly_convex_v2(coords, nr)) {
return MOD_SDEF_BIND_RESULT_CONCAVE_ERR;
}
+ copy_v2_v2(prev_prev_co, coords[nr - 2]);
copy_v2_v2(prev_co, coords[nr - 1]);
sub_v2_v2v2(prev_vec, prev_co, coords[nr - 2]);
normalize_v2(prev_vec);
@@ -428,15 +437,23 @@ BLI_INLINE int isPolyValid(const float coords[][2], const uint nr)
for (int i = 0; i < nr; i++) {
sub_v2_v2v2(curr_vec, coords[i], prev_co);
+ /* Check ovelap between directly adjacent vertices. */
const float curr_len = normalize_v2(curr_vec);
if (curr_len < FLT_EPSILON) {
return MOD_SDEF_BIND_RESULT_OVERLAP_ERR;
}
+ /* Check ovelap between vertices skipping one. */
+ if (len_squared_v2v2(prev_prev_co, coords[i]) < FLT_EPSILON * FLT_EPSILON) {
+ return MOD_SDEF_BIND_RESULT_OVERLAP_ERR;
+ }
+
+ /* Check for adjacent parallel edges. */
if (1.0f - dot_v2v2(prev_vec, curr_vec) < FLT_EPSILON) {
return MOD_SDEF_BIND_RESULT_CONCAVE_ERR;
}
+ copy_v2_v2(prev_prev_co, prev_co);
copy_v2_v2(prev_co, coords[i]);
copy_v2_v2(prev_vec, curr_vec);
}
@@ -460,9 +477,9 @@ static void freeBindData(SDefBindWeightData *const bwdata)
MEM_freeN(bwdata);
}
-BLI_INLINE float computeAngularWeight(const float point_angle)
+BLI_INLINE float computeAngularWeight(const float point_angle, const float edgemid_angle)
{
- return sinf(point_angle * M_PI_2);
+ return sinf(min_ff(point_angle / edgemid_angle, 1) * M_PI_2);
}
BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
@@ -603,33 +620,51 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
avg_point_dist += bpoly->weight_dist;
- /* Compute centroid to mid-edge vectors */
- mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[0],
- bpoly->coords_v2[bpoly->edge_vert_inds[0]],
- bpoly->coords_v2[bpoly->corner_ind]);
+ /* Common vertex coordinates. */
+ const float *const vert0_v2 = bpoly->coords_v2[bpoly->edge_vert_inds[0]];
+ const float *const vert1_v2 = bpoly->coords_v2[bpoly->edge_vert_inds[1]];
+ const float *const corner_v2 = bpoly->coords_v2[bpoly->corner_ind];
- mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[1],
- bpoly->coords_v2[bpoly->edge_vert_inds[1]],
- bpoly->coords_v2[bpoly->corner_ind]);
+ /* Compute centroid to mid-edge vectors */
+ mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[0], vert0_v2, corner_v2);
+ mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[1], vert1_v2, corner_v2);
sub_v2_v2(bpoly->cent_edgemid_vecs_v2[0], bpoly->centroid_v2);
sub_v2_v2(bpoly->cent_edgemid_vecs_v2[1], bpoly->centroid_v2);
- /* Compute poly scales with respect to mid-edges, and normalize the vectors */
- bpoly->scales[0] = normalize_v2(bpoly->cent_edgemid_vecs_v2[0]);
- bpoly->scales[1] = normalize_v2(bpoly->cent_edgemid_vecs_v2[1]);
+ normalize_v2(bpoly->cent_edgemid_vecs_v2[0]);
+ normalize_v2(bpoly->cent_edgemid_vecs_v2[1]);
- /* Compute the required polygon angles */
+ /* Compute poly scales with respect to the two edges. */
+ bpoly->scales[0] = dist_to_line_v2(bpoly->centroid_v2, vert0_v2, corner_v2);
+ bpoly->scales[1] = dist_to_line_v2(bpoly->centroid_v2, vert1_v2, corner_v2);
+
+ /* Compute the angle between the edge mid vectors. */
bpoly->edgemid_angle = angle_normalized_v2v2(bpoly->cent_edgemid_vecs_v2[0],
bpoly->cent_edgemid_vecs_v2[1]);
- sub_v2_v2v2(tmp_vec_v2, bpoly->coords_v2[bpoly->corner_ind], bpoly->centroid_v2);
+ /* Compute the angles between the corner and the edge mid vectors. The angles
+ * are computed signed in order to correctly clamp point_edgemid_angles later. */
+ float corner_angles[2];
+
+ sub_v2_v2v2(tmp_vec_v2, corner_v2, bpoly->centroid_v2);
normalize_v2(tmp_vec_v2);
- bpoly->corner_edgemid_angles[0] = angle_normalized_v2v2(tmp_vec_v2,
- bpoly->cent_edgemid_vecs_v2[0]);
- bpoly->corner_edgemid_angles[1] = angle_normalized_v2v2(tmp_vec_v2,
- bpoly->cent_edgemid_vecs_v2[1]);
+ corner_angles[0] = angle_signed_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[0]);
+ corner_angles[1] = angle_signed_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[1]);
+
+ bpoly->corner_edgemid_angles[0] = fabsf(corner_angles[0]);
+ bpoly->corner_edgemid_angles[1] = fabsf(corner_angles[1]);
+
+ /* Verify that the computed values are valid (the polygon isn't somehow
+ * degenerate despite having passed isPolyValid). */
+ if (bpoly->scales[0] < FLT_EPSILON || bpoly->scales[1] < FLT_EPSILON ||
+ bpoly->edgemid_angle < FLT_EPSILON || bpoly->corner_edgemid_angles[0] < FLT_EPSILON ||
+ bpoly->corner_edgemid_angles[1] < FLT_EPSILON) {
+ freeBindData(bwdata);
+ data->success = MOD_SDEF_BIND_RESULT_GENERIC_ERR;
+ return NULL;
+ }
/* Check for infinite weights, and compute angular data otherwise. */
if (bpoly->weight_dist < FLT_EPSILON) {
@@ -640,15 +675,54 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
}
else {
- float cent_point_vec[2];
+ /* Compute angles between the point and the edge mid vectors. */
+ float cent_point_vec[2], point_angles[2];
sub_v2_v2v2(cent_point_vec, bpoly->point_v2, bpoly->centroid_v2);
normalize_v2(cent_point_vec);
- bpoly->point_edgemid_angles[0] = angle_normalized_v2v2(cent_point_vec,
- bpoly->cent_edgemid_vecs_v2[0]);
- bpoly->point_edgemid_angles[1] = angle_normalized_v2v2(cent_point_vec,
- bpoly->cent_edgemid_vecs_v2[1]);
+ point_angles[0] = angle_signed_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[0]) *
+ signf(corner_angles[0]);
+ point_angles[1] = angle_signed_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[1]) *
+ signf(corner_angles[1]);
+
+ if (point_angles[0] <= 0 && point_angles[1] <= 0) {
+ /* If the point is outside the corner formed by the edge mid vectors,
+ * choose to clamp the closest side and flip the other. */
+ if (point_angles[0] < point_angles[1]) {
+ point_angles[0] = bpoly->edgemid_angle - point_angles[1];
+ }
+ else {
+ point_angles[1] = bpoly->edgemid_angle - point_angles[0];
+ }
+ }
+
+ bpoly->point_edgemid_angles[0] = max_ff(0, point_angles[0]);
+ bpoly->point_edgemid_angles[1] = max_ff(0, point_angles[1]);
+
+ /* Compute the distance scale for the corner. The base value is the orthogonal
+ * distance from the corner to the chord, scaled by sqrt(2) to preserve the old
+ * values in case of a square grid. This doesn't use the centroid because the
+ * LOOPTRI method only uses these three vertices. */
+ bpoly->scale_mid = area_tri_v2(vert0_v2, corner_v2, vert1_v2) /
+ len_v2v2(vert0_v2, vert1_v2) * sqrtf(2);
+
+ if (bpoly->inside) {
+ /* When inside, interpolate to centroid-based scale close to the center. */
+ float min_dist = min_ff(bpoly->scales[0], bpoly->scales[1]);
+
+ bpoly->scale_mid = interpf(bpoly->scale_mid,
+ (bpoly->scales[0] + bpoly->scales[1]) / 2,
+ min_ff(bpoly->weight_dist_proj / min_dist, 1));
+ }
+
+ /* Verify that the additional computed values are valid. */
+ if (bpoly->scale_mid < FLT_EPSILON ||
+ bpoly->point_edgemid_angles[0] + bpoly->point_edgemid_angles[1] < FLT_EPSILON) {
+ freeBindData(bwdata);
+ data->success = MOD_SDEF_BIND_RESULT_GENERIC_ERR;
+ return NULL;
+ }
}
}
}
@@ -688,12 +762,15 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
/* Compute angular weight component */
if (epolys->num == 1) {
- ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]]);
+ ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]],
+ bpolys[0]->edgemid_angle);
bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[0];
}
else if (epolys->num == 2) {
- ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]]);
- ang_weights[1] = computeAngularWeight(bpolys[1]->point_edgemid_angles[edge_on_poly[1]]);
+ ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]],
+ bpolys[0]->edgemid_angle);
+ ang_weights[1] = computeAngularWeight(bpolys[1]->point_edgemid_angles[edge_on_poly[1]],
+ bpolys[1]->edgemid_angle);
bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[1];
bpolys[1]->weight_angular *= ang_weights[0] * ang_weights[1];
@@ -731,6 +808,13 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
bpoly->dominant_angle_weight = corner_angle_weights[1];
}
+ /* Check for invalid weights just in case computations fail. */
+ if (bpoly->dominant_angle_weight < 0 || bpoly->dominant_angle_weight > 1) {
+ freeBindData(bwdata);
+ data->success = MOD_SDEF_BIND_RESULT_GENERIC_ERR;
+ return NULL;
+ }
+
bpoly->dominant_angle_weight = sinf(bpoly->dominant_angle_weight * M_PI_2);
/* Compute quadratic angular scale interpolation weight */
@@ -748,10 +832,15 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
inv_sqr *= inv_sqr;
scale_weight = sqr / (sqr + inv_sqr);
+ BLI_assert(scale_weight >= 0 && scale_weight <= 1);
+
/* Compute interpolated scale (no longer need the individual scales,
* so simply storing the result over the scale in index zero) */
- bpoly->scales[0] = bpoly->scales[bpoly->dominant_edge] * (1.0f - scale_weight) +
- bpoly->scales[!bpoly->dominant_edge] * scale_weight;
+ bpoly->scales[0] = interpf(bpoly->scale_mid,
+ interpf(bpoly->scales[!bpoly->dominant_edge],
+ bpoly->scales[bpoly->dominant_edge],
+ scale_weight),
+ bpoly->dominant_angle_weight);
/* Scale the point distance weights, and introduce falloff */
bpoly->weight_dist_proj /= bpoly->scales[0];
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index ed4d658eb4f..405a8dcbf46 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -146,6 +146,7 @@ set(SRC
geometry/nodes/node_geo_attribute_fill.cc
geometry/nodes/node_geo_attribute_math.cc
geometry/nodes/node_geo_attribute_mix.cc
+ geometry/nodes/node_geo_attribute_sample_texture.cc
geometry/nodes/node_geo_attribute_randomize.cc
geometry/nodes/node_geo_attribute_vector_math.cc
geometry/nodes/node_geo_boolean.cc
@@ -159,6 +160,7 @@ set(SRC
geometry/nodes/node_geo_point_scale.cc
geometry/nodes/node_geo_point_separate.cc
geometry/nodes/node_geo_point_translate.cc
+ geometry/nodes/node_geo_points_to_volume.cc
geometry/nodes/node_geo_subdivision_surface.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc
@@ -366,4 +368,11 @@ if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
+if(WITH_OPENVDB)
+ list(APPEND INC_SYS
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+ add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
+endif()
+
blender_add_lib(bf_nodes "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 523d0cfa24d..d78f76e0b52 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -47,6 +47,8 @@ void register_node_type_geo_attribute_mix(void);
void register_node_type_geo_attribute_color_ramp(void);
void register_node_type_geo_point_rotate(void);
void register_node_type_geo_align_rotation_to_vector(void);
+void register_node_type_geo_sample_texture(void);
+void register_node_type_geo_points_to_volume(void);
#ifdef __cplusplus
}
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index f278d6b4107..454c9e96246 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -24,12 +24,16 @@
#include "DNA_node_types.h"
+struct Depsgraph;
+
namespace blender::nodes {
using bke::BooleanReadAttribute;
using bke::BooleanWriteAttribute;
using bke::Color4fReadAttribute;
using bke::Color4fWriteAttribute;
+using bke::Float2ReadAttribute;
+using bke::Float2WriteAttribute;
using bke::Float3ReadAttribute;
using bke::Float3WriteAttribute;
using bke::FloatReadAttribute;
@@ -54,18 +58,21 @@ class GeoNodeExecParams {
GValueMap<StringRef> &output_values_;
const PersistentDataHandleMap &handle_map_;
const Object *self_object_;
+ Depsgraph *depsgraph_;
public:
GeoNodeExecParams(const bNode &node,
GValueMap<StringRef> &input_values,
GValueMap<StringRef> &output_values,
const PersistentDataHandleMap &handle_map,
- const Object *self_object)
+ const Object *self_object,
+ Depsgraph *depsgraph)
: node_(node),
input_values_(input_values),
output_values_(output_values),
handle_map_(handle_map),
- self_object_(self_object)
+ self_object_(self_object),
+ depsgraph_(depsgraph)
{
}
@@ -163,6 +170,11 @@ class GeoNodeExecParams {
return self_object_;
}
+ Depsgraph *depsgraph() const
+ {
+ return depsgraph_;
+ }
+
/**
* Creates a read-only attribute based on node inputs. The method automatically detects which
* input with the given name is available.
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index e91b385a87e..cc2f6a294f2 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -289,6 +289,8 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_VECTOR_MATH, def_geo_attribute_vector_m
DefNode(GeometryNode, GEO_NODE_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_to_vector, "ALIGN_ROTATION_TO_VECTOR", AlignRotationToVector, "Align Rotation to Vector", "")
DefNode(GeometryNode, GEO_NODE_POINT_SCALE, def_geo_point_scale, "POINT_SCALE", PointScale, "Point Scale", "")
DefNode(GeometryNode, GEO_NODE_POINT_TRANSLATE, def_geo_point_translate, "POINT_TRANSLATE", PointTranslate, "Point Translate", "")
+DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE, def_geo_attribute_sample_texture, "ATTRIBUTE_SAMPLE_TEXTURE", AttributeSampleTexture, "Attribute Sample Texture", "")
+DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "")
/* undefine macros */
#undef DefNode
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index 53af6073793..daaccf4450b 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -54,6 +54,8 @@ static int attribute_data_type_complexity(const CustomDataType data_type)
return 1;
case CD_PROP_FLOAT:
return 2;
+ case CD_PROP_FLOAT2:
+ return 3;
case CD_PROP_FLOAT3:
return 4;
case CD_PROP_COLOR:
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
index 20a2b2127c2..194b062021d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
@@ -51,7 +51,7 @@ static bNodeSocketTemplate geo_node_attribute_compare_out[] = {
static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare),
- "attribute mix node");
+ __func__);
data->operation = NODE_FLOAT_COMPARE_GREATER_THAN;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
index f8ec9124db3..f3fc45fc1be 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
@@ -34,6 +34,8 @@ static bNodeSocketTemplate geo_node_attribute_math_in[] = {
{SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
{SOCK_STRING, N_("B")},
{SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
+ {SOCK_STRING, N_("C")},
+ {SOCK_FLOAT, N_("C"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
{SOCK_STRING, N_("Result")},
{-1, ""},
};
@@ -51,45 +53,132 @@ static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node)
data->operation = NODE_MATH_ADD;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
+ data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
}
+static bool operation_use_input_c(const NodeMathOperation operation)
+{
+ return ELEM(operation,
+ NODE_MATH_MULTIPLY_ADD,
+ NODE_MATH_SMOOTH_MIN,
+ NODE_MATH_SMOOTH_MAX,
+ NODE_MATH_WRAP,
+ NODE_MATH_COMPARE);
+}
+
+static bool operation_use_input_b(const NodeMathOperation operation)
+{
+ switch (operation) {
+ case NODE_MATH_ADD:
+ case NODE_MATH_SUBTRACT:
+ case NODE_MATH_MULTIPLY:
+ case NODE_MATH_DIVIDE:
+ case NODE_MATH_POWER:
+ case NODE_MATH_LOGARITHM:
+ case NODE_MATH_MINIMUM:
+ case NODE_MATH_MAXIMUM:
+ case NODE_MATH_LESS_THAN:
+ case NODE_MATH_GREATER_THAN:
+ case NODE_MATH_MODULO:
+ case NODE_MATH_ARCTAN2:
+ case NODE_MATH_SNAP:
+ case NODE_MATH_WRAP:
+ case NODE_MATH_COMPARE:
+ case NODE_MATH_MULTIPLY_ADD:
+ case NODE_MATH_PINGPONG:
+ case NODE_MATH_SMOOTH_MIN:
+ case NODE_MATH_SMOOTH_MAX:
+ return true;
+ case NODE_MATH_SINE:
+ case NODE_MATH_COSINE:
+ case NODE_MATH_TANGENT:
+ case NODE_MATH_ARCSINE:
+ case NODE_MATH_ARCCOSINE:
+ case NODE_MATH_ARCTANGENT:
+ case NODE_MATH_ROUND:
+ case NODE_MATH_ABSOLUTE:
+ case NODE_MATH_FLOOR:
+ case NODE_MATH_CEIL:
+ case NODE_MATH_FRACTION:
+ case NODE_MATH_SQRT:
+ case NODE_MATH_INV_SQRT:
+ case NODE_MATH_SIGN:
+ case NODE_MATH_EXPONENT:
+ case NODE_MATH_RADIANS:
+ case NODE_MATH_DEGREES:
+ case NODE_MATH_SINH:
+ case NODE_MATH_COSH:
+ case NODE_MATH_TANH:
+ case NODE_MATH_TRUNC:
+ return false;
+ }
+ BLI_assert(false);
+ return false;
+}
+
namespace blender::nodes {
static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage;
+ NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage;
+ NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage.operation);
update_attribute_input_socket_availabilities(
- *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
+ *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a);
update_attribute_input_socket_availabilities(
- *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b);
+ *node,
+ "B",
+ (GeometryNodeAttributeInputMode)node_storage.input_type_b,
+ operation_use_input_b(operation));
+ update_attribute_input_socket_availabilities(
+ *node,
+ "C",
+ (GeometryNodeAttributeInputMode)node_storage.input_type_c,
+ operation_use_input_c(operation));
}
-static void do_math_operation(const FloatReadAttribute &input_a,
- const FloatReadAttribute &input_b,
- FloatWriteAttribute result,
- const int operation)
+static void do_math_operation(Span<float> span_a,
+ Span<float> span_b,
+ Span<float> span_c,
+ MutableSpan<float> span_result,
+ const NodeMathOperation operation)
{
- const int size = input_a.size();
-
- Span<float> span_a = input_a.get_span();
- Span<float> span_b = input_b.get_span();
- MutableSpan<float> span_result = result.get_span_for_write_only();
+ bool success = try_dispatch_float_math_fl_fl_fl_to_fl(
+ operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
+ for (const int i : IndexRange(span_result.size())) {
+ span_result[i] = math_function(span_a[i], span_b[i], span_c[i]);
+ }
+ });
+ BLI_assert(success);
+ UNUSED_VARS_NDEBUG(success);
+}
+static void do_math_operation(Span<float> span_a,
+ Span<float> span_b,
+ MutableSpan<float> span_result,
+ const NodeMathOperation operation)
+{
bool success = try_dispatch_float_math_fl_fl_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- for (const int i : IndexRange(size)) {
- const float in1 = span_a[i];
- const float in2 = span_b[i];
- const float out = math_function(in1, in2);
- span_result[i] = out;
+ for (const int i : IndexRange(span_result.size())) {
+ span_result[i] = math_function(span_a[i], span_b[i]);
}
});
+ BLI_assert(success);
+ UNUSED_VARS_NDEBUG(success);
+}
- result.apply_span();
-
- /* The operation is not supported by this node currently. */
+static void do_math_operation(Span<float> span_input,
+ MutableSpan<float> span_result,
+ const NodeMathOperation operation)
+{
+ bool success = try_dispatch_float_math_fl_to_fl(
+ operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
+ for (const int i : IndexRange(span_result.size())) {
+ span_result[i] = math_function(span_input[i]);
+ }
+ });
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
@@ -98,7 +187,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
{
const bNode &node = params.node();
const NodeAttributeMath *node_storage = (const NodeAttributeMath *)node.storage;
- const int operation = node_storage->operation;
+ const NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage->operation);
/* The result type of this node is always float. */
const CustomDataType result_type = CD_PROP_FLOAT;
@@ -115,15 +204,44 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
ReadAttributePtr attribute_a = params.get_input_attribute(
"A", component, result_domain, result_type, nullptr);
- ReadAttributePtr attribute_b = params.get_input_attribute(
- "B", component, result_domain, result_type, nullptr);
- if (!attribute_a || !attribute_b) {
- /* Attribute wasn't found. */
+ if (!attribute_a) {
return;
}
- do_math_operation(*attribute_a, *attribute_b, *attribute_result, operation);
- attribute_result.save();
+ /* Note that passing the data with `get_span<float>()` works
+ * because the attributes were accessed with #CD_PROP_FLOAT. */
+ if (operation_use_input_b(operation)) {
+ ReadAttributePtr attribute_b = params.get_input_attribute(
+ "B", component, result_domain, result_type, nullptr);
+ if (!attribute_b) {
+ return;
+ }
+ if (operation_use_input_c(operation)) {
+ ReadAttributePtr attribute_c = params.get_input_attribute(
+ "C", component, result_domain, result_type, nullptr);
+ if (!attribute_c) {
+ return;
+ }
+ do_math_operation(attribute_a->get_span<float>(),
+ attribute_b->get_span<float>(),
+ attribute_c->get_span<float>(),
+ attribute_result->get_span_for_write_only<float>(),
+ operation);
+ }
+ else {
+ do_math_operation(attribute_a->get_span<float>(),
+ attribute_b->get_span<float>(),
+ attribute_result->get_span_for_write_only<float>(),
+ operation);
+ }
+ }
+ else {
+ do_math_operation(attribute_a->get_span<float>(),
+ attribute_result->get_span_for_write_only<float>(),
+ operation);
+ }
+
+ attribute_result.apply_span_and_save();
}
static void geo_node_attribute_math_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
index 0e7bb25e659..3ee7df7fe72 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
@@ -50,8 +50,7 @@ static void geo_node_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode
bNodeSocket *sock_min_float = sock_max_vector->next;
bNodeSocket *sock_max_float = sock_min_float->next;
- const int data_type = node->custom1;
-
+ const CustomDataType data_type = static_cast<CustomDataType>(node->custom1);
nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3);
nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3);
nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT);
@@ -86,8 +85,11 @@ static void randomize_attribute_bool(BooleanWriteAttribute attribute,
attribute.apply_span();
}
-static void randomize_attribute_float(
- FloatWriteAttribute attribute, float min, float max, Span<uint32_t> hashes, const int seed)
+static void randomize_attribute_float(FloatWriteAttribute attribute,
+ const float min,
+ const float max,
+ Span<uint32_t> hashes,
+ const int seed)
{
MutableSpan<float> attribute_span = attribute.get_span();
for (const int i : IndexRange(attribute.size())) {
@@ -97,8 +99,11 @@ static void randomize_attribute_float(
attribute.apply_span();
}
-static void randomize_attribute_float3(
- Float3WriteAttribute attribute, float3 min, float3 max, Span<uint32_t> hashes, const int seed)
+static void randomize_attribute_float3(Float3WriteAttribute attribute,
+ const float3 min,
+ const float3 max,
+ Span<uint32_t> hashes,
+ const int seed)
{
MutableSpan<float3> attribute_span = attribute.get_span();
for (const int i : IndexRange(attribute.size())) {
@@ -129,8 +134,7 @@ Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &compo
}
else {
/* If there is no "id" attribute for per-point variation, just create it here. */
- RandomNumberGenerator rng;
- rng.seed(0);
+ RandomNumberGenerator rng(0);
for (const int i : hashes.index_range()) {
hashes[i] = rng.get_uint32();
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
new file mode 100644
index 00000000000..66495bfa53b
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
@@ -0,0 +1,107 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_compiler_attrs.h"
+
+#include "DNA_texture_types.h"
+
+#include "BKE_texture.h"
+
+#include "RE_texture.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_attribute_sample_texture_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_STRING, N_("Mapping")},
+ {SOCK_STRING, N_("Result")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_attribute_sample_texture_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+static void execute_on_component(GeometryComponent &component, const GeoNodeExecParams &params)
+{
+ const bNode &node = params.node();
+ Tex *texture = reinterpret_cast<Tex *>(node.id);
+ const std::string result_attribute_name = params.get_input<std::string>("Result");
+
+ if (texture == nullptr) {
+ return;
+ }
+
+ const std::string mapping_name = params.get_input<std::string>("Mapping");
+ if (!component.attribute_exists(mapping_name)) {
+ return;
+ }
+
+ OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
+ result_attribute_name, ATTR_DOMAIN_POINT, CD_PROP_COLOR);
+ if (!attribute_out) {
+ return;
+ }
+
+ Float3ReadAttribute mapping_attribute = component.attribute_get_for_read<float3>(
+ mapping_name, ATTR_DOMAIN_POINT, {0, 0, 0});
+
+ MutableSpan<Color4f> colors = attribute_out->get_span<Color4f>();
+ for (const int i : IndexRange(mapping_attribute.size())) {
+ TexResult texture_result = {0};
+ const float3 position = mapping_attribute[i];
+ /* For legacy reasons we have to map [0, 1] to [-1, 1] to support uv mappings. */
+ const float3 remapped_position = position * 2.0f - float3(1.0f);
+ BKE_texture_get_value(nullptr, texture, remapped_position, &texture_result, false);
+ colors[i] = {texture_result.tr, texture_result.tg, texture_result.tb, texture_result.ta};
+ }
+ attribute_out.apply_span_and_save();
+}
+
+static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ if (geometry_set.has<MeshComponent>()) {
+ execute_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
+ }
+ if (geometry_set.has<PointCloudComponent>()) {
+ execute_on_component(geometry_set.get_component_for_write<PointCloudComponent>(), params);
+ }
+
+ params.set_output("Geometry", geometry_set);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_sample_texture()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype,
+ GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE,
+ "Attribute Sample Texture",
+ NODE_CLASS_ATTRIBUTE,
+ 0);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_socket_templates(
+ &ntype, geo_node_attribute_sample_texture_in, geo_node_attribute_sample_texture_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_attribute_sample_texture_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index 42402e23fa5..384094b6d8c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -138,17 +138,17 @@ static void determine_final_data_type_and_domain(Span<const GeometryComponent *>
CustomDataType *r_type,
AttributeDomain *r_domain)
{
+ Vector<CustomDataType> data_types;
for (const GeometryComponent *component : components) {
ReadAttributePtr attribute = component->attribute_try_get_for_read(attribute_name);
if (attribute) {
- /* TODO: Use data type with most information. */
- *r_type = bke::cpp_type_to_custom_data_type(attribute->cpp_type());
+ data_types.append(attribute->custom_data_type());
/* TODO: Use highest priority domain. */
*r_domain = attribute->domain();
- return;
}
}
- BLI_assert(false);
+
+ *r_type = attribute_data_type_highest_complexity(data_types);
}
static void fill_new_attribute(Span<const GeometryComponent *> src_components,
@@ -243,6 +243,14 @@ static void join_components(Span<const InstancesComponent *> src_components, Geo
}
}
+static void join_components(Span<const VolumeComponent *> src_components, GeometrySet &result)
+{
+ /* Not yet supported. Joining volume grids with the same name requires resampling of at least one
+ * of the grids. The cell size of the resulting volume has to be determined somehow. */
+ VolumeComponent &dst_component = result.get_component_for_write<VolumeComponent>();
+ UNUSED_VARS(src_components, dst_component);
+}
+
template<typename Component>
static void join_component_type(Span<const GeometrySet *> src_geometry_sets, GeometrySet &result)
{
@@ -275,6 +283,7 @@ static void geo_node_join_geometry_exec(GeoNodeExecParams params)
join_component_type<MeshComponent>(src_geometry_sets, geometry_set_result);
join_component_type<PointCloudComponent>(src_geometry_sets, geometry_set_result);
join_component_type<InstancesComponent>(src_geometry_sets, geometry_set_result);
+ join_component_type<VolumeComponent>(src_geometry_sets, geometry_set_result);
params.set_output("Geometry", std::move(geometry_set_result));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
index ab5e4f8964a..d713c191d5d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -19,6 +19,7 @@
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
+#include "BKE_volume.h"
#include "BLI_math_matrix.h"
@@ -86,6 +87,18 @@ static void geo_node_object_info_exec(GeoNodeExecParams params)
mesh_component.copy_vertex_group_names_from_object(*object);
}
}
+ if (object->type == OB_VOLUME) {
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+
+ if (transform_space_relative) {
+ instances.add_instance(object, transform);
+ }
+ else {
+ float unit_transform[4][4];
+ unit_m4(unit_transform);
+ instances.add_instance(object, unit_transform);
+ }
+ }
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
index 2f1aa276532..eaf13b94eb9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
@@ -26,6 +26,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
+#include "BKE_attribute_math.hh"
#include "BKE_bvhutils.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
@@ -217,13 +218,141 @@ BLI_NOINLINE static void eliminate_points_based_on_mask(Span<bool> elimination_m
}
}
-BLI_NOINLINE static void compute_remaining_point_data(const Mesh &mesh,
- Span<float3> bary_coords,
- Span<int> looptri_indices,
- MutableSpan<float3> r_normals,
- MutableSpan<int> r_ids,
- MutableSpan<float3> r_rotations)
+template<typename T>
+BLI_NOINLINE static void interpolate_attribute_point(const Mesh &mesh,
+ const Span<float3> bary_coords,
+ const Span<int> looptri_indices,
+ const Span<T> data_in,
+ MutableSpan<T> data_out)
{
+ BLI_assert(data_in.size() == mesh.totvert);
+ Span<MLoopTri> looptris = get_mesh_looptris(mesh);
+
+ for (const int i : bary_coords.index_range()) {
+ const int looptri_index = looptri_indices[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+ const float3 &bary_coord = bary_coords[i];
+
+ const int v0_index = mesh.mloop[looptri.tri[0]].v;
+ const int v1_index = mesh.mloop[looptri.tri[1]].v;
+ const int v2_index = mesh.mloop[looptri.tri[2]].v;
+
+ const T &v0 = data_in[v0_index];
+ const T &v1 = data_in[v1_index];
+ const T &v2 = data_in[v2_index];
+
+ const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
+ data_out[i] = interpolated_value;
+ }
+}
+
+template<typename T>
+BLI_NOINLINE static void interpolate_attribute_corner(const Mesh &mesh,
+ const Span<float3> bary_coords,
+ const Span<int> looptri_indices,
+ const Span<T> data_in,
+ MutableSpan<T> data_out)
+{
+ BLI_assert(data_in.size() == mesh.totloop);
+ Span<MLoopTri> looptris = get_mesh_looptris(mesh);
+
+ for (const int i : bary_coords.index_range()) {
+ const int looptri_index = looptri_indices[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+ const float3 &bary_coord = bary_coords[i];
+
+ const int loop_index_0 = looptri.tri[0];
+ const int loop_index_1 = looptri.tri[1];
+ const int loop_index_2 = looptri.tri[2];
+
+ const T &v0 = data_in[loop_index_0];
+ const T &v1 = data_in[loop_index_1];
+ const T &v2 = data_in[loop_index_2];
+
+ const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
+ data_out[i] = interpolated_value;
+ }
+}
+
+BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
+ Span<float3> bary_coords,
+ Span<int> looptri_indices,
+ const StringRef attribute_name,
+ const ReadAttribute &attribute_in,
+ GeometryComponent &component)
+{
+ const CustomDataType data_type = attribute_in.custom_data_type();
+ const AttributeDomain domain = attribute_in.domain();
+ if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
+ /* Not supported currently. */
+ return;
+ }
+
+ OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
+ attribute_name, ATTR_DOMAIN_POINT, data_type);
+ if (!attribute_out) {
+ return;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+
+ Span data_in = attribute_in.get_span<T>();
+ MutableSpan data_out = attribute_out->get_span_for_write_only<T>();
+
+ switch (domain) {
+ case ATTR_DOMAIN_POINT: {
+ interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, data_in, data_out);
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ interpolate_attribute_corner<T>(mesh, bary_coords, looptri_indices, data_in, data_out);
+ break;
+ }
+ default: {
+ BLI_assert(false);
+ break;
+ }
+ }
+ });
+ attribute_out.apply_span_and_save();
+}
+
+BLI_NOINLINE static void interpolate_existing_attributes(const MeshComponent &mesh_component,
+ GeometryComponent &component,
+ Span<float3> bary_coords,
+ Span<int> looptri_indices)
+{
+ const Mesh &mesh = *mesh_component.get_for_read();
+
+ Set<std::string> attribute_names = mesh_component.attribute_names();
+ for (StringRefNull attribute_name : attribute_names) {
+ if (ELEM(attribute_name, "position", "normal", "id")) {
+ continue;
+ }
+
+ ReadAttributePtr attribute_in = mesh_component.attribute_try_get_for_read(attribute_name);
+ interpolate_attribute(
+ mesh, bary_coords, looptri_indices, attribute_name, *attribute_in, component);
+ }
+}
+
+BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh,
+ GeometryComponent &component,
+ Span<float3> bary_coords,
+ Span<int> looptri_indices)
+{
+ OutputAttributePtr id_attribute = component.attribute_try_get_for_output(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ OutputAttributePtr normal_attribute = component.attribute_try_get_for_output(
+ "normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
+ "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+
+ MutableSpan<int> ids = id_attribute->get_span_for_write_only<int>();
+ MutableSpan<float3> normals = normal_attribute->get_span_for_write_only<float3>();
+ MutableSpan<float3> rotations = rotation_attribute->get_span_for_write_only<float3>();
+
Span<MLoopTri> looptris = get_mesh_looptris(mesh);
for (const int i : bary_coords.index_range()) {
const int looptri_index = looptri_indices[i];
@@ -237,10 +366,24 @@ BLI_NOINLINE static void compute_remaining_point_data(const Mesh &mesh,
const float3 v1_pos = mesh.mvert[v1_index].co;
const float3 v2_pos = mesh.mvert[v2_index].co;
- r_ids[i] = (int)(bary_coord.hash()) + looptri_index;
- normal_tri_v3(r_normals[i], v0_pos, v1_pos, v2_pos);
- r_rotations[i] = normal_to_euler_rotation(r_normals[i]);
+ ids[i] = (int)(bary_coord.hash()) + looptri_index;
+ normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos);
+ rotations[i] = normal_to_euler_rotation(normals[i]);
}
+
+ id_attribute.apply_span_and_save();
+ normal_attribute.apply_span_and_save();
+ rotation_attribute.apply_span_and_save();
+}
+
+BLI_NOINLINE static void add_remaining_point_attributes(const MeshComponent &mesh_component,
+ GeometryComponent &component,
+ Span<float3> bary_coords,
+ Span<int> looptri_indices)
+{
+ interpolate_existing_attributes(mesh_component, component, bary_coords, looptri_indices);
+ compute_special_attributes(
+ *mesh_component.get_for_read(), component, bary_coords, looptri_indices);
}
static void sample_mesh_surface_with_minimum_distance(const Mesh &mesh,
@@ -315,11 +458,6 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
break;
}
const int tot_points = positions.size();
- Array<float3> normals(tot_points);
- Array<int> stable_ids(tot_points);
- Array<float3> rotations(tot_points);
- compute_remaining_point_data(
- *mesh_in, bary_coords, looptri_indices, normals, stable_ids, rotations);
PointCloud *pointcloud = BKE_pointcloud_new_nomain(tot_points);
memcpy(pointcloud->co, positions.data(), sizeof(float3) * tot_points);
@@ -332,29 +470,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
geometry_set_out.get_component_for_write<PointCloudComponent>();
point_component.replace(pointcloud);
- {
- OutputAttributePtr stable_id_attribute = point_component.attribute_try_get_for_output(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
- MutableSpan<int> stable_ids_span = stable_id_attribute->get_span<int>();
- stable_ids_span.copy_from(stable_ids);
- stable_id_attribute.apply_span_and_save();
- }
-
- {
- OutputAttributePtr normals_attribute = point_component.attribute_try_get_for_output(
- "normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
- MutableSpan<float3> normals_span = normals_attribute->get_span<float3>();
- normals_span.copy_from(normals);
- normals_attribute.apply_span_and_save();
- }
-
- {
- OutputAttributePtr rotations_attribute = point_component.attribute_try_get_for_output(
- "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
- MutableSpan<float3> rotations_span = rotations_attribute->get_span<float3>();
- rotations_span.copy_from(rotations);
- rotations_attribute.apply_span_and_save();
- }
+ add_remaining_point_attributes(mesh_component, point_component, bary_coords, looptri_indices);
params.set_output("Geometry", std::move(geometry_set_out));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
index a96dc710427..3bd8c355124 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
@@ -47,8 +47,10 @@ static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node)
bNodeSocket *collection_socket = object_socket->next;
bNodeSocket *seed_socket = collection_socket->next;
- GeometryNodePointInstanceType type = (GeometryNodePointInstanceType)node->custom1;
- const bool use_whole_collection = node->custom2 == 0;
+ NodeGeometryPointInstance *node_storage = (NodeGeometryPointInstance *)node->storage;
+ GeometryNodePointInstanceType type = (GeometryNodePointInstanceType)node_storage->instance_type;
+ const bool use_whole_collection = (node_storage->flag &
+ GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION) != 0;
nodeSetSocketAvailability(object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT);
nodeSetSocketAvailability(collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION);
@@ -79,6 +81,8 @@ static void get_instanced_data__collection(
MutableSpan<std::optional<InstancedData>> r_instances_data)
{
const bNode &node = params.node();
+ NodeGeometryPointInstance *node_storage = (NodeGeometryPointInstance *)node.storage;
+
bke::PersistentCollectionHandle collection_handle =
params.get_input<bke::PersistentCollectionHandle>("Collection");
Collection *collection = params.handle_map().lookup(collection_handle);
@@ -86,7 +90,8 @@ static void get_instanced_data__collection(
return;
}
- const bool use_whole_collection = node.custom2 == 0;
+ const bool use_whole_collection = (node_storage->flag &
+ GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION) != 0;
if (use_whole_collection) {
InstancedData instance;
instance.type = INSTANCE_DATA_TYPE_COLLECTION;
@@ -128,8 +133,9 @@ static Array<std::optional<InstancedData>> get_instanced_data(const GeoNodeExecP
const int amount)
{
const bNode &node = params.node();
- const GeometryNodePointInstanceType type = (GeometryNodePointInstanceType)node.custom1;
-
+ NodeGeometryPointInstance *node_storage = (NodeGeometryPointInstance *)node.storage;
+ const GeometryNodePointInstanceType type = (GeometryNodePointInstanceType)
+ node_storage->instance_type;
Array<std::optional<InstancedData>> instances_data(amount);
switch (type) {
@@ -189,6 +195,16 @@ static void geo_node_point_instance_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set_out));
}
+
+static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN(
+ sizeof(NodeGeometryPointInstance), __func__);
+ data->instance_type = GEO_NODE_POINT_INSTANCE_TYPE_OBJECT;
+ data->flag |= GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION;
+ node->storage = data;
+}
+
} // namespace blender::nodes
void register_node_type_geo_point_instance()
@@ -197,6 +213,9 @@ void register_node_type_geo_point_instance()
geo_node_type_base(&ntype, GEO_NODE_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(&ntype, geo_node_point_instance_in, geo_node_point_instance_out);
+ node_type_init(&ntype, blender::nodes::geo_node_point_instance_init);
+ node_type_storage(
+ &ntype, "NodeGeometryPointInstance", node_free_standard_storage, node_copy_standard_storage);
node_type_update(&ntype, blender::nodes::geo_node_point_instance_update);
ntype.geometry_node_execute = blender::nodes::geo_node_point_instance_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
new file mode 100644
index 00000000000..b90ef2034a8
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -0,0 +1,259 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+# include <openvdb/tools/LevelSetUtil.h>
+# include <openvdb/tools/ParticlesToLevelSet.h>
+#endif
+
+#include "node_geometry_util.hh"
+
+#include "BKE_lib_id.h"
+#include "BKE_volume.h"
+
+static bNodeSocketTemplate geo_node_points_to_volume_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_FLOAT, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
+ {SOCK_FLOAT, N_("Voxel Size"), 0.3f, 0.0f, 0.0f, 0.0f, 0.01f, FLT_MAX},
+ {SOCK_FLOAT, N_("Voxel Amount"), 64.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
+ {SOCK_STRING, N_("Radius")},
+ {SOCK_FLOAT, N_("Radius"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_point_translate_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+#ifdef WITH_OPENVDB
+namespace {
+/* Implements the interface required by #openvdb::tools::ParticlesToLevelSet. */
+struct ParticleList {
+ using PosType = openvdb::Vec3R;
+
+ Span<float3> positions;
+ Span<float> radii;
+
+ size_t size() const
+ {
+ return (size_t)positions.size();
+ }
+
+ void getPos(size_t n, openvdb::Vec3R &xyz) const
+ {
+ xyz = &positions[n].x;
+ }
+
+ void getPosRad(size_t n, openvdb::Vec3R &xyz, openvdb::Real &radius) const
+ {
+ xyz = &positions[n].x;
+ radius = radii[n];
+ }
+};
+} // namespace
+
+static openvdb::FloatGrid::Ptr generate_volume_from_points(const Span<float3> positions,
+ const Span<float> radii,
+ const float density)
+{
+ /* Create a new grid that will be filled. #ParticlesToLevelSet requires the background value to
+ * be positive. It will be set to zero later on. */
+ openvdb::FloatGrid::Ptr new_grid = openvdb::FloatGrid::create(1.0f);
+
+ /* Create a narrow-band level set grid based on the positions and radii. */
+ openvdb::tools::ParticlesToLevelSet op{*new_grid};
+ /* Don't ignore particles based on their radius. */
+ op.setRmin(0.0f);
+ op.setRmax(FLT_MAX);
+ ParticleList particles{positions, radii};
+ op.rasterizeSpheres(particles);
+ op.finalize();
+
+ /* Convert the level set to a fog volume. This also sets the background value to zero. Inside the
+ * fog there will be a density of 1. */
+ openvdb::tools::sdfToFogVolume(*new_grid);
+
+ /* Take the desired density into account. */
+ openvdb::tools::foreach (new_grid->beginValueOn(),
+ [&](const openvdb::FloatGrid::ValueOnIter &iter) {
+ iter.modifyValue([&](float &value) { value *= density; });
+ });
+ return new_grid;
+}
+
+static float compute_voxel_size(const GeoNodeExecParams &params,
+ Span<float3> positions,
+ const float radius)
+{
+ const NodeGeometryPointsToVolume &storage =
+ *(const NodeGeometryPointsToVolume *)params.node().storage;
+
+ if (storage.resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE) {
+ return params.get_input<float>("Voxel Size");
+ }
+
+ if (positions.is_empty()) {
+ return 0.0f;
+ }
+
+ float3 min, max;
+ INIT_MINMAX(min, max);
+ minmax_v3v3_v3_array(min, max, (float(*)[3])positions.data(), positions.size());
+
+ const float voxel_amount = params.get_input<float>("Voxel Amount");
+ if (voxel_amount <= 1) {
+ return 0.0f;
+ }
+
+ /* The voxel size adapts to the final size of the volume. */
+ const float diagonal = float3::distance(min, max);
+ const float extended_diagonal = diagonal + 2.0f * radius;
+ const float voxel_size = extended_diagonal / voxel_amount;
+ return voxel_size;
+}
+
+static void gather_point_data_from_component(const GeoNodeExecParams &params,
+ const GeometryComponent &component,
+ Vector<float3> &r_positions,
+ Vector<float> &r_radii)
+{
+ Float3ReadAttribute positions = component.attribute_get_for_read<float3>(
+ "position", ATTR_DOMAIN_POINT, {0, 0, 0});
+ FloatReadAttribute radii = params.get_input_attribute<float>(
+ "Radius", component, ATTR_DOMAIN_POINT, 0.0f);
+
+ r_positions.extend(positions.get_span());
+ r_radii.extend(radii.get_span());
+}
+
+static void convert_to_grid_index_space(const float voxel_size,
+ MutableSpan<float3> positions,
+ MutableSpan<float> radii)
+{
+ const float voxel_size_inv = 1.0f / voxel_size;
+ for (const int i : positions.index_range()) {
+ positions[i] *= voxel_size_inv;
+ /* Better align generated grid with source points. */
+ positions[i] -= float3(0.5f);
+ radii[i] *= voxel_size_inv;
+ }
+}
+
+static void initialize_volume_component_from_points(const GeometrySet &geometry_set_in,
+ GeometrySet &geometry_set_out,
+ const GeoNodeExecParams &params)
+{
+ Vector<float3> positions;
+ Vector<float> radii;
+
+ if (geometry_set_in.has<MeshComponent>()) {
+ gather_point_data_from_component(
+ params, *geometry_set_in.get_component_for_read<MeshComponent>(), positions, radii);
+ }
+ if (geometry_set_in.has<PointCloudComponent>()) {
+ gather_point_data_from_component(
+ params, *geometry_set_in.get_component_for_read<PointCloudComponent>(), positions, radii);
+ }
+
+ const float max_radius = *std::max_element(radii.begin(), radii.end());
+ const float voxel_size = compute_voxel_size(params, positions, max_radius);
+ if (voxel_size == 0.0f || positions.is_empty()) {
+ return;
+ }
+
+ Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
+ BKE_volume_init_grids(volume);
+
+ VolumeGrid *c_density_grid = BKE_volume_grid_add(volume, "density", VOLUME_GRID_FLOAT);
+ openvdb::FloatGrid::Ptr density_grid = openvdb::gridPtrCast<openvdb::FloatGrid>(
+ BKE_volume_grid_openvdb_for_write(volume, c_density_grid, false));
+
+ const float density = params.get_input<float>("Density");
+ convert_to_grid_index_space(voxel_size, positions, radii);
+ openvdb::FloatGrid::Ptr new_grid = generate_volume_from_points(positions, radii, density);
+ /* This merge is cheap, because the #density_grid is empty. */
+ density_grid->merge(*new_grid);
+ density_grid->transform().postScale(voxel_size);
+
+ VolumeComponent &volume_component = geometry_set_out.get_component_for_write<VolumeComponent>();
+ volume_component.replace(volume);
+}
+#endif
+
+static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set_out;
+
+#ifdef WITH_OPENVDB
+ initialize_volume_component_from_points(geometry_set_in, geometry_set_out, params);
+#endif
+
+ params.set_output("Geometry", std::move(geometry_set_out));
+}
+
+static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
+ sizeof(NodeGeometryPointsToVolume), __func__);
+ data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
+ data->input_type_radius = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
+ node->storage = data;
+
+ bNodeSocket *radius_attribute_socket = nodeFindSocket(node, SOCK_IN, "Radius");
+ bNodeSocketValueString *radius_attribute_socket_value =
+ (bNodeSocketValueString *)radius_attribute_socket->default_value;
+ STRNCPY(radius_attribute_socket_value->value, "radius");
+}
+
+static void geo_node_points_to_volume_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage;
+ bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
+ bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
+ nodeSetSocketAvailability(voxel_amount_socket,
+ data->resolution_mode ==
+ GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT);
+ nodeSetSocketAvailability(
+ voxel_size_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE);
+
+ update_attribute_input_socket_availabilities(
+ *node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_points_to_volume()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_points_to_volume_in, geo_node_point_translate_out);
+ node_type_storage(&ntype,
+ "NodeGeometryPointsToVolume",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ node_type_size(&ntype, 170, 120, 700);
+ node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init);
+ node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update);
+ ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 1fcd1063993..539a7551be9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -14,11 +14,19 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+#endif
+
#include "BLI_math_matrix.h"
#include "DNA_pointcloud_types.h"
+#include "DNA_volume_types.h"
#include "BKE_mesh.h"
+#include "BKE_volume.h"
+
+#include "DEG_depsgraph_query.h"
#include "node_geometry_util.hh"
@@ -109,6 +117,43 @@ static void transform_instances(InstancesComponent &instances,
}
}
+static void transform_volume(Volume *volume,
+ const float3 translation,
+ const float3 rotation,
+ const float3 scale,
+ GeoNodeExecParams &params)
+{
+#ifdef WITH_OPENVDB
+ /* Scaling an axis to zero is not supported for volumes. */
+ const float3 limited_scale = {
+ (scale.x == 0.0f) ? FLT_EPSILON : scale.x,
+ (scale.y == 0.0f) ? FLT_EPSILON : scale.y,
+ (scale.z == 0.0f) ? FLT_EPSILON : scale.z,
+ };
+
+ Main *bmain = DEG_get_bmain(params.depsgraph());
+ BKE_volume_load(volume, bmain);
+
+ float matrix[4][4];
+ loc_eul_size_to_mat4(matrix, translation, rotation, limited_scale);
+
+ openvdb::Mat4s vdb_matrix;
+ memcpy(vdb_matrix.asPointer(), matrix, sizeof(float[4][4]));
+ openvdb::Mat4d vdb_matrix_d{vdb_matrix};
+
+ const int num_grids = BKE_volume_num_grids(volume);
+ for (const int i : IndexRange(num_grids)) {
+ VolumeGrid *volume_grid = BKE_volume_grid_get(volume, i);
+
+ openvdb::GridBase::Ptr grid = BKE_volume_grid_openvdb_for_write(volume, volume_grid, false);
+ openvdb::math::Transform &grid_transform = grid->transform();
+ grid_transform.postMult(vdb_matrix_d);
+ }
+#else
+ UNUSED_VARS(volume, translation, rotation, scale, params);
+#endif
+}
+
static void geo_node_transform_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -131,6 +176,11 @@ static void geo_node_transform_exec(GeoNodeExecParams params)
transform_instances(instances, translation, rotation, scale);
}
+ if (geometry_set.has_volume()) {
+ Volume *volume = geometry_set.get_volume_for_write();
+ transform_volume(volume, translation, rotation, scale, params);
+ }
+
params.set_output("Geometry", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc
index 2e4196af156..c2391667e86 100644
--- a/source/blender/nodes/intern/node_tree_multi_function.cc
+++ b/source/blender/nodes/intern/node_tree_multi_function.cc
@@ -19,6 +19,7 @@
#include "FN_multi_function_network_evaluation.hh"
#include "BLI_color.hh"
+#include "BLI_float2.hh"
#include "BLI_float3.hh"
namespace blender::nodes {
@@ -191,27 +192,58 @@ static void add_implicit_conversion(DataTypeConversions &conversions,
static DataTypeConversions create_implicit_conversions()
{
DataTypeConversions conversions;
- add_implicit_conversion<float, int32_t>(conversions);
+ add_implicit_conversion<float, float2>(conversions);
add_implicit_conversion<float, float3>(conversions);
- add_implicit_conversion<int32_t, float>(conversions);
+ add_implicit_conversion<float, int32_t>(conversions);
add_implicit_conversion<float, bool>(conversions);
- add_implicit_conversion<bool, float>(conversions);
- add_implicit_conversion<float3, float>(
- conversions, "Vector Length", [](float3 a) { return a.length(); });
- add_implicit_conversion<int32_t, float3>(
- conversions, "int32 to float3", [](int32_t a) { return float3((float)a); });
- add_implicit_conversion<float3, Color4f>(
- conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); });
- add_implicit_conversion<Color4f, float3>(
- conversions, "Color4f to float3", [](Color4f a) { return float3(a.r, a.g, a.b); });
add_implicit_conversion<float, Color4f>(
conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); });
- add_implicit_conversion<Color4f, float>(
- conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); });
+
+ add_implicit_conversion<float2, float3>(
+ conversions, "float2 to float3", [](float2 a) { return float3(a.x, a.y, 0.0f); });
+ add_implicit_conversion<float2, float>(
+ conversions, "float2 to float", [](float2 a) { return a.length(); });
+ add_implicit_conversion<float2, int32_t>(
+ conversions, "float2 to int32_t", [](float2 a) { return (int32_t)a.length(); });
+ add_implicit_conversion<float2, bool>(
+ conversions, "float2 to bool", [](float2 a) { return a.length_squared() == 0.0f; });
+ add_implicit_conversion<float2, Color4f>(
+ conversions, "float2 to Color4f", [](float2 a) { return Color4f(a.x, a.y, 0.0f, 1.0f); });
+
add_implicit_conversion<float3, bool>(
conversions, "float3 to boolean", [](float3 a) { return a.length_squared() == 0.0f; });
+ add_implicit_conversion<float3, float>(
+ conversions, "Vector Length", [](float3 a) { return a.length(); });
+ add_implicit_conversion<float3, int32_t>(
+ conversions, "float3 to int32_t", [](float3 a) { return (int)a.length(); });
+ add_implicit_conversion<float3, float2>(conversions);
+ add_implicit_conversion<float3, Color4f>(
+ conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); });
+
+ add_implicit_conversion<int32_t, bool>(conversions);
+ add_implicit_conversion<int32_t, float>(conversions);
+ add_implicit_conversion<int32_t, float2>(
+ conversions, "int32 to float2", [](int32_t a) { return float2((float)a); });
+ add_implicit_conversion<int32_t, float3>(
+ conversions, "int32 to float3", [](int32_t a) { return float3((float)a); });
+
+ add_implicit_conversion<bool, float>(conversions);
+ add_implicit_conversion<bool, int32_t>(conversions);
+ add_implicit_conversion<bool, float2>(
+ conversions, "boolean to float2", [](bool a) { return (a) ? float2(1.0f) : float2(0.0f); });
add_implicit_conversion<bool, float3>(
conversions, "boolean to float3", [](bool a) { return (a) ? float3(1.0f) : float3(0.0f); });
+ add_implicit_conversion<bool, Color4f>(conversions, "boolean to Color4f", [](bool a) {
+ return (a) ? Color4f(1.0f, 1.0f, 1.0f, 1.0f) : Color4f(0.0f, 0.0f, 0.0f, 1.0f);
+ });
+
+ add_implicit_conversion<Color4f, float>(
+ conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); });
+ add_implicit_conversion<Color4f, float2>(
+ conversions, "Color4f to float2", [](Color4f a) { return float2(a.r, a.g); });
+ add_implicit_conversion<Color4f, float3>(
+ conversions, "Color4f to float3", [](Color4f a) { return float3(a.r, a.g, a.b); });
+
return conversions;
}
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index 38122c45ef1..22c7a394906 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -1079,7 +1079,12 @@ PyDoc_STRVAR(
" :arg cage: Get the mesh as a deformed cage.\n"
" :type cage: boolean\n"
" :arg face_normals: Calculate face normals.\n"
- " :type face_normals: boolean\n");
+ " :type face_normals: boolean\n"
+ "\n"
+ " .. deprecated:: 2.93\n"
+ "\n"
+ " The deform parameter is deprecated, assumed to be True, and will be removed in version "
+ "3.0.\n");
static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw)
{
static const char *kwlist[] = {"object", "depsgraph", "deform", "cage", "face_normals", NULL};
@@ -1120,45 +1125,36 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
return NULL;
}
+ if (use_deform == false) {
+ PyErr_WarnEx(PyExc_FutureWarning,
+ "from_object(...): the deform parameter is deprecated, assumed to be True, and "
+ "will be removed in version 3.0",
+ 1);
+ }
+
const bool use_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
scene_eval = DEG_get_evaluated_scene(depsgraph);
ob_eval = DEG_get_evaluated_object(depsgraph, ob);
bool need_free = false;
/* Write the display mesh into the dummy mesh */
- if (use_deform) {
- if (use_render) {
- if (use_cage) {
- PyErr_SetString(PyExc_ValueError,
- "from_object(...): cage arg is unsupported when dependency graph "
- "evaluation mode is RENDER");
- return NULL;
- }
-
- me_eval = BKE_mesh_new_from_object(depsgraph, ob_eval, true);
- need_free = true;
- }
- else {
- if (use_cage) {
- me_eval = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &data_masks);
- }
- else {
- me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &data_masks);
- }
- }
- }
- else {
- /* !use_deform */
+ if (use_render) {
if (use_cage) {
PyErr_SetString(PyExc_ValueError,
- "from_object(...): cage arg is unsupported when deform=False");
+ "from_object(...): cage arg is unsupported when dependency graph "
+ "evaluation mode is RENDER");
return NULL;
}
- if (use_render) {
- me_eval = mesh_create_eval_no_deform_render(depsgraph, scene_eval, ob, &data_masks);
+
+ me_eval = BKE_mesh_new_from_object(depsgraph, ob_eval, true);
+ need_free = true;
+ }
+ else {
+ if (use_cage) {
+ me_eval = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &data_masks);
}
else {
- me_eval = mesh_create_eval_no_deform(depsgraph, scene_eval, ob, &data_masks);
+ me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &data_masks);
}
}
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index 526b96f8584..1a174549d66 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -570,9 +570,6 @@ PyDoc_STRVAR(
" ``GL_ARB_texture_gather``, ``GL_ARB_texture_cube_map_array``\n"
" and ``GL_ARB_shader_draw_parameters``.\n"
"\n"
- " To debug shaders, use the ``--debug-gpu-shaders`` command line option\n"
- " to see full GLSL shader compilation and linking errors.\n"
- "\n"
" For drawing user interface elements and gizmos, use\n"
" ``fragOutput = blender_srgb_to_framebuffer_space(fragOutput)``\n"
" to transform the output sRGB colors to the frame-buffer color-space.\n"
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 02ab001dbf6..c7e195b586d 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -424,11 +424,6 @@ static PyGetSetDef bpy_app_getsets[] = {
bpy_app_debug_set,
bpy_app_debug_doc,
(void *)G_DEBUG_SIMDATA},
- {"debug_gpumem",
- bpy_app_debug_get,
- bpy_app_debug_set,
- bpy_app_debug_doc,
- (void *)G_DEBUG_GPU_MEM},
{"debug_io", bpy_app_debug_get, bpy_app_debug_set, bpy_app_debug_doc, (void *)G_DEBUG_IO},
{"use_event_simulate",
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 64e992bd76f..c4789407e4e 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -341,12 +341,20 @@ void BPY_python_start(bContext *C, int argc, const char **argv)
}
}
- /* Without this the `sys.stdout` may be set to 'ascii'
- * (it is on my system at least), where printing unicode values will raise
- * an error, this is highly annoying, another stumbling block for developers,
- * so use a more relaxed error handler and enforce utf-8 since the rest of
- * Blender is utf-8 too - campbell */
- Py_SetStandardStreamEncoding("utf-8", "surrogateescape");
+ /* Force `utf-8` on all platforms, since this is what's used for Blender's internal strings,
+ * providing consistent encoding behavior across all Blender installations.
+ *
+ * This also uses the `surrogateescape` error handler ensures any unexpected bytes are escaped
+ * instead of raising an error.
+ *
+ * Without this `sys.getfilesystemencoding()` and `sys.stdout` for example may be set to ASCII
+ * or some other encoding - where printing some `utf-8` values will raise an error.
+ *
+ * This can cause scripts to fail entirely on some systems.
+ *
+ * This assignment is the equivalent of enabling the `PYTHONUTF8` environment variable.
+ * See `PEP-540` for details on exactly what this changes. */
+ Py_UTF8Mode = 1;
/* Suppress error messages when calculating the module search path.
* While harmless, it's noisy. */
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index a2125a5dff9..2242cecab20 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -8737,15 +8737,17 @@ void pyrna_free_types(void)
RNA_PROP_END;
}
-/* Note! MemLeak XXX
+/**
+ * \warning memory leak!
*
* There is currently a bug where moving the registration of a Python class does
- * not properly manage reference-counts from the Python class. As the srna owns
+ * not properly manage reference-counts from the Python class. As the `srna` owns
* the Python class this should not be so tricky, but changing the references as
* you'd expect when changing ownership crashes blender on exit so I had to comment out
- * the decref. This is not so bad because the leak only happens when re-registering (hold F8)
+ * the #Py_DECREF. This is not so bad because the leak only happens when re-registering
+ * (continuously running `SCRIPT_OT_reload`).
* - Should still be fixed - Campbell
- * */
+ */
PyDoc_STRVAR(pyrna_register_class_doc,
".. method:: register_class(cls)\n"
"\n"
diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h
index 1af40ac760b..c31a41f66d5 100644
--- a/source/blender/render/RE_engine.h
+++ b/source/blender/render/RE_engine.h
@@ -64,6 +64,7 @@ extern "C" {
#define RE_USE_SPHERICAL_STEREO 128
#define RE_USE_STEREO_VIEWPORT 256
#define RE_USE_GPU_CONTEXT 512
+#define RE_USE_CUSTOM_FREESTYLE 1024
/* RenderEngine.flag */
#define RE_ENGINE_ANIMATION 1
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index 3e73ac77fc6..c0b87f4246a 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -252,8 +252,6 @@ void RE_ChangeModeFlag(struct Render *re, int flag, bool clear);
struct Object *RE_GetCamera(struct Render *re); /* return camera override if set */
void RE_SetOverrideCamera(struct Render *re, struct Object *cam_ob);
void RE_SetCamera(struct Render *re, struct Object *cam_ob);
-void RE_SetWindow(struct Render *re, const rctf *viewplane, float clip_start, float clip_end);
-void RE_SetOrtho(struct Render *re, const rctf *viewplane, float clip_start, float clip_end);
/* get current view and window transform */
void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect);
diff --git a/source/blender/render/intern/initrender.c b/source/blender/render/intern/initrender.c
index fb7f7270c13..80f6badb924 100644
--- a/source/blender/render/intern/initrender.c
+++ b/source/blender/render/intern/initrender.c
@@ -172,26 +172,11 @@ struct Object *RE_GetCamera(Render *re)
return BKE_camera_multiview_render(re->scene, camera, re->viewname);
}
-static void re_camera_params_get(Render *re, CameraParams *params)
-{
- copy_m4_m4(re->winmat, params->winmat);
-
- re->clip_start = params->clip_start;
- re->clip_end = params->clip_end;
-
- re->viewplane = params->viewplane;
-}
-
void RE_SetOverrideCamera(Render *re, Object *cam_ob)
{
re->camera_override = cam_ob;
}
-static void re_camera_params_stereo3d(Render *re, CameraParams *params, Object *cam_ob)
-{
- BKE_camera_multiview_params(&re->r, params, cam_ob, re->viewname);
-}
-
/* call this after InitState() */
/* per render, there's one persistent viewplane. Parts will set their own viewplanes */
void RE_SetCamera(Render *re, Object *cam_ob)
@@ -201,14 +186,17 @@ void RE_SetCamera(Render *re, Object *cam_ob)
/* setup parameters */
BKE_camera_params_init(&params);
BKE_camera_params_from_object(&params, cam_ob);
- re_camera_params_stereo3d(re, &params, cam_ob);
+ BKE_camera_multiview_params(&re->r, &params, cam_ob, re->viewname);
/* compute matrix, viewplane, .. */
BKE_camera_params_compute_viewplane(&params, re->winx, re->winy, re->r.xasp, re->r.yasp);
BKE_camera_params_compute_matrix(&params);
/* extract results */
- re_camera_params_get(re, &params);
+ copy_m4_m4(re->winmat, params.winmat);
+ re->clip_start = params.clip_start;
+ re->clip_end = params.clip_end;
+ re->viewplane = params.viewplane;
}
void RE_GetCameraWindow(struct Render *re, struct Object *camera, float r_winmat[4][4])
@@ -241,6 +229,19 @@ void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_modelmat
BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, r_modelmat);
}
+void RE_GetViewPlane(Render *re, rctf *r_viewplane, rcti *r_disprect)
+{
+ *r_viewplane = re->viewplane;
+
+ /* make disprect zero when no border render, is needed to detect changes in 3d view render */
+ if (re->r.mode & R_BORDER) {
+ *r_disprect = re->disprect;
+ }
+ else {
+ BLI_rcti_init(r_disprect, 0, 0, 0, 0);
+ }
+}
+
/* ~~~~~~~~~~~~~~~~ part (tile) calculus ~~~~~~~~~~~~~~~~~~~~~~ */
void RE_parts_free(Render *re)
diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c
index a4f68419c67..1859886f563 100644
--- a/source/blender/render/intern/multires_bake.c
+++ b/source/blender/render/intern/multires_bake.c
@@ -768,7 +768,7 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima)
if (ss_lvl > 0) {
smd.levels = smd.renderLevels = ss_lvl;
- smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
+ smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
smd.quality = 3;
height_data->ssdm = subsurf_make_derived_from_derived(
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index 4628a5a132b..8567835f55c 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -983,53 +983,6 @@ void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_
BLI_duplicatelist(&re->r.views, &rd->views);
}
-void RE_SetWindow(Render *re, const rctf *viewplane, float clip_start, float clip_end)
-{
- /* re->ok flag? */
-
- re->viewplane = *viewplane;
- re->clip_start = clip_start;
- re->clip_end = clip_end;
-
- perspective_m4(re->winmat,
- re->viewplane.xmin,
- re->viewplane.xmax,
- re->viewplane.ymin,
- re->viewplane.ymax,
- re->clip_start,
- re->clip_end);
-}
-
-void RE_SetOrtho(Render *re, const rctf *viewplane, float clip_start, float clip_end)
-{
- /* re->ok flag? */
-
- re->viewplane = *viewplane;
- re->clip_start = clip_start;
- re->clip_end = clip_end;
-
- orthographic_m4(re->winmat,
- re->viewplane.xmin,
- re->viewplane.xmax,
- re->viewplane.ymin,
- re->viewplane.ymax,
- re->clip_start,
- re->clip_end);
-}
-
-void RE_GetViewPlane(Render *re, rctf *r_viewplane, rcti *r_disprect)
-{
- *r_viewplane = re->viewplane;
-
- /* make disprect zero when no border render, is needed to detect changes in 3d view render */
- if (re->r.mode & R_BORDER) {
- *r_disprect = re->disprect;
- }
- else {
- BLI_rcti_init(r_disprect, 0, 0, 0, 0);
- }
-}
-
/* image and movie output has to move to either imbuf or kernel */
void RE_display_init_cb(Render *re, void *handle, void (*f)(void *handle, RenderResult *rr))
{
@@ -2054,13 +2007,38 @@ void RE_RenderFrame(Render *re,
G.is_rendering = false;
}
+static void change_renderdata_engine(Render *re, const char *new_engine)
+{
+ if (!STREQ(re->r.engine, new_engine)) {
+ if (re->engine) {
+ RE_engine_free(re->engine);
+ re->engine = NULL;
+ }
+ BLI_strncpy(re->r.engine, new_engine, sizeof(re->r.engine));
+ }
+}
+
#ifdef WITH_FREESTYLE
+static bool use_eevee_for_freestyle_render(Render *re)
+{
+ RenderEngineType *type = RE_engines_find(re->r.engine);
+ return !(type->flag & RE_USE_CUSTOM_FREESTYLE);
+}
+
void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, int render)
{
re->result_ok = 0;
if (render_init_from_main(re, &scene->r, bmain, scene, NULL, NULL, 0, 0)) {
if (render) {
+ char scene_engine[32];
+ BLI_strncpy(scene_engine, re->r.engine, sizeof(scene_engine));
+ if (use_eevee_for_freestyle_render(re)) {
+ change_renderdata_engine(re, RE_engine_id_BLENDER_EEVEE);
+ }
+
do_render_3d(re);
+
+ change_renderdata_engine(re, scene_engine);
}
}
re->result_ok = 1;
diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c
index 344b5af26aa..299ebffe8a8 100644
--- a/source/blender/sequencer/intern/image_cache.c
+++ b/source/blender/sequencer/intern/image_cache.c
@@ -824,16 +824,59 @@ static void seq_cache_valfree(void *val)
BLI_mempool_free(item->cache_owner->items_pool, item);
}
-static void seq_cache_put_ex(SeqCache *cache, SeqCacheKey *key, ImBuf *ibuf)
+static int get_stored_types_flag(Scene *scene, SeqCacheKey *key)
{
+ int flag;
+ if (key->seq->cache_flag & SEQ_CACHE_OVERRIDE) {
+ flag = key->seq->cache_flag;
+ }
+ else {
+ flag = scene->ed->cache_flag;
+ }
+
+ /* SEQ_CACHE_STORE_FINAL_OUT can not be overridden by strip cache */
+ flag |= (scene->ed->cache_flag & SEQ_CACHE_STORE_FINAL_OUT);
+
+ return flag;
+}
+
+static void seq_cache_put_ex(Scene *scene, SeqCacheKey *key, ImBuf *ibuf)
+{
+ SeqCache *cache = seq_cache_get_from_scene(scene);
SeqCacheItem *item;
item = BLI_mempool_alloc(cache->items_pool);
item->cache_owner = cache;
item->ibuf = ibuf;
+ const int stored_types_flag = get_stored_types_flag(scene, key);
+
+ /* Item stored for later use. */
+ if (stored_types_flag & key->type) {
+ key->is_temp_cache = false;
+ key->link_prev = cache->last_key;
+ }
+
+ /* Store pointer to last cached key. */
+ SeqCacheKey *temp_last_key = cache->last_key;
+
if (BLI_ghash_reinsert(cache->hash, key, item, seq_cache_keyfree, seq_cache_valfree)) {
IMB_refImBuf(ibuf);
- cache->last_key = key;
+
+ if (!key->is_temp_cache) {
+ cache->last_key = key;
+ }
+ }
+
+ /* Set last_key's reference to this key so we can look up chain backwards.
+ * Item is already put in cache, so cache->last_key points to current key.
+ */
+ if (!key->is_temp_cache && temp_last_key) {
+ temp_last_key->link_next = cache->last_key;
+ }
+
+ /* Reset linking. */
+ if (key->type == SEQ_CACHE_STORE_FINAL_OUT) {
+ cache->last_key = NULL;
}
}
@@ -1095,6 +1138,35 @@ static void seq_cache_create(Main *bmain, Scene *scene)
BLI_mutex_unlock(&cache_create_lock);
}
+static void seq_cache_populate_key(SeqCacheKey *key,
+ const SeqRenderData *context,
+ Sequence *seq,
+ const float timeline_frame,
+ const int type)
+{
+ key->cache_owner = seq_cache_get_from_scene(context->scene);
+ key->seq = seq;
+ key->context = *context;
+ key->frame_index = seq_cache_timeline_frame_to_frame_index(seq, timeline_frame, type);
+ key->timeline_frame = timeline_frame;
+ key->type = type;
+ key->link_prev = NULL;
+ key->link_next = NULL;
+ key->is_temp_cache = true;
+ key->task_id = context->task_id;
+}
+
+static SeqCacheKey *seq_cache_allocate_key(SeqCache *cache,
+ const SeqRenderData *context,
+ Sequence *seq,
+ const float timeline_frame,
+ const int type)
+{
+ SeqCacheKey *key = BLI_mempool_alloc(cache->keys_pool);
+ seq_cache_populate_key(key, context, seq, timeline_frame, type);
+ return key;
+}
+
/* ***************************** API ****************************** */
void seq_cache_free_temp_cache(Scene *scene, short id, int timeline_frame)
@@ -1243,8 +1315,7 @@ void seq_cache_cleanup_sequence(Scene *scene,
struct ImBuf *seq_cache_get(const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- int type,
- bool skip_disk_cache)
+ int type)
{
if (context->skip_cache || context->is_proxy_render || !seq) {
@@ -1274,11 +1345,7 @@ struct ImBuf *seq_cache_get(const SeqRenderData *context,
/* Try RAM cache: */
if (cache && seq) {
- key.seq = seq;
- key.context = *context;
- key.frame_index = seq_cache_timeline_frame_to_frame_index(seq, timeline_frame, type);
- key.type = type;
-
+ seq_cache_populate_key(&key, context, seq, timeline_frame, type);
ibuf = seq_cache_get_ex(cache, &key);
}
seq_cache_unlock(scene);
@@ -1288,7 +1355,7 @@ struct ImBuf *seq_cache_get(const SeqRenderData *context,
}
/* Try disk cache: */
- if (!skip_disk_cache && seq_disk_cache_is_enabled(context->bmain)) {
+ if (seq_disk_cache_is_enabled(context->bmain)) {
if (cache->disk_cache == NULL) {
seq_disk_cache_create(context->bmain, context->scene);
}
@@ -1296,25 +1363,23 @@ struct ImBuf *seq_cache_get(const SeqRenderData *context,
BLI_mutex_lock(&cache->disk_cache->read_write_mutex);
ibuf = seq_disk_cache_read_file(cache->disk_cache, &key);
BLI_mutex_unlock(&cache->disk_cache->read_write_mutex);
- if (ibuf) {
- if (key.type == SEQ_CACHE_STORE_FINAL_OUT) {
- seq_cache_put_if_possible(context, seq, timeline_frame, type, ibuf, true);
- }
- else {
- seq_cache_put(context, seq, timeline_frame, type, ibuf, true);
- }
+
+ if (ibuf == NULL) {
+ return NULL;
+ }
+
+ /* Store read image in RAM. Only recycle item for final type. */
+ if (key.type != SEQ_CACHE_STORE_FINAL_OUT || seq_cache_recycle_item(scene)) {
+ SeqCacheKey *new_key = seq_cache_allocate_key(cache, context, seq, timeline_frame, type);
+ seq_cache_put_ex(scene, new_key, ibuf);
}
}
return ibuf;
}
-bool seq_cache_put_if_possible(const SeqRenderData *context,
- Sequence *seq,
- float timeline_frame,
- int type,
- ImBuf *ibuf,
- bool skip_disk_cache)
+bool seq_cache_put_if_possible(
+ const SeqRenderData *context, Sequence *seq, float timeline_frame, int type, ImBuf *ibuf)
{
Scene *scene = context->scene;
@@ -1329,7 +1394,7 @@ bool seq_cache_put_if_possible(const SeqRenderData *context,
}
if (seq_cache_recycle_item(scene)) {
- seq_cache_put(context, seq, timeline_frame, type, ibuf, skip_disk_cache);
+ seq_cache_put(context, seq, timeline_frame, type, ibuf);
return true;
}
@@ -1338,12 +1403,8 @@ bool seq_cache_put_if_possible(const SeqRenderData *context,
return false;
}
-void seq_cache_put(const SeqRenderData *context,
- Sequence *seq,
- float timeline_frame,
- int type,
- ImBuf *i,
- bool skip_disk_cache)
+void seq_cache_put(
+ const SeqRenderData *context, Sequence *seq, float timeline_frame, int type, ImBuf *i)
{
if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) {
return;
@@ -1359,7 +1420,7 @@ void seq_cache_put(const SeqRenderData *context,
}
/* Prevent reinserting, it breaks cache key linking. */
- ImBuf *test = seq_cache_get(context, seq, timeline_frame, type, true);
+ ImBuf *test = seq_cache_get(context, seq, timeline_frame, type);
if (test) {
IMB_freeImBuf(test);
return;
@@ -1370,63 +1431,12 @@ void seq_cache_put(const SeqRenderData *context,
}
seq_cache_lock(scene);
-
SeqCache *cache = seq_cache_get_from_scene(scene);
- int flag;
-
- if (seq->cache_flag & SEQ_CACHE_OVERRIDE) {
- flag = seq->cache_flag;
- /* Final_out is invalid in context of sequence override. */
- flag -= seq->cache_flag & SEQ_CACHE_STORE_FINAL_OUT;
- /* If global setting is enabled however, use it. */
- flag |= scene->ed->cache_flag & SEQ_CACHE_STORE_FINAL_OUT;
- }
- else {
- flag = scene->ed->cache_flag;
- }
-
- SeqCacheKey *key;
- key = BLI_mempool_alloc(cache->keys_pool);
- key->cache_owner = cache;
- key->seq = seq;
- key->context = *context;
- key->frame_index = seq_cache_timeline_frame_to_frame_index(seq, timeline_frame, type);
- key->timeline_frame = timeline_frame;
- key->type = type;
- key->link_prev = NULL;
- key->link_next = NULL;
- key->is_temp_cache = true;
- key->task_id = context->task_id;
-
- /* Item stored for later use */
- if (flag & type) {
- key->is_temp_cache = false;
- key->link_prev = cache->last_key;
- }
-
- SeqCacheKey *temp_last_key = cache->last_key;
- seq_cache_put_ex(cache, key, i);
-
- /* Restore pointer to previous item as this one will be freed when stack is rendered. */
- if (key->is_temp_cache) {
- cache->last_key = temp_last_key;
- }
-
- /* Set last_key's reference to this key so we can look up chain backwards.
- * Item is already put in cache, so cache->last_key points to current key.
- */
- if (flag & type && temp_last_key) {
- temp_last_key->link_next = cache->last_key;
- }
-
- /* Reset linking. */
- if (key->type == SEQ_CACHE_STORE_FINAL_OUT) {
- cache->last_key = NULL;
- }
-
+ SeqCacheKey *key = seq_cache_allocate_key(cache, context, seq, timeline_frame, type);
+ seq_cache_put_ex(scene, key, i);
seq_cache_unlock(scene);
- if (!key->is_temp_cache && !skip_disk_cache) {
+ if (!key->is_temp_cache) {
if (seq_disk_cache_is_enabled(context->bmain)) {
if (cache->disk_cache == NULL) {
seq_disk_cache_create(context->bmain, context->scene);
diff --git a/source/blender/sequencer/intern/image_cache.h b/source/blender/sequencer/intern/image_cache.h
index 41e8c4d1d48..63c559caee9 100644
--- a/source/blender/sequencer/intern/image_cache.h
+++ b/source/blender/sequencer/intern/image_cache.h
@@ -40,20 +40,17 @@ struct Sequence;
struct ImBuf *seq_cache_get(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
- int type,
- bool skip_disk_cache);
+ int type);
void seq_cache_put(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
int type,
- struct ImBuf *i,
- bool skip_disk_cache);
+ struct ImBuf *i);
bool seq_cache_put_if_possible(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
int type,
- struct ImBuf *nval,
- bool skip_disk_cache);
+ struct ImBuf *nval);
bool seq_cache_recycle_item(struct Scene *scene);
void seq_cache_free_temp_cache(struct Scene *scene, short id, int timeline_frame);
void seq_cache_destruct(struct Scene *scene);
diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c
index b0e9e3c5003..4317fa3a850 100644
--- a/source/blender/sequencer/intern/prefetch.c
+++ b/source/blender/sequencer/intern/prefetch.c
@@ -379,28 +379,28 @@ static bool seq_prefetch_do_skip_frame(PrefetchJob *pfjob, ListBase *seqbase)
if (seq_arr[i]->type == SEQ_TYPE_SCENE && (seq_arr[i]->flag & SEQ_SCENE_STRIPS) == 0) {
int cached_types = 0;
- ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_FINAL_OUT, false);
+ ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_FINAL_OUT);
if (ibuf != NULL) {
cached_types |= SEQ_CACHE_STORE_FINAL_OUT;
IMB_freeImBuf(ibuf);
ibuf = NULL;
}
- ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_COMPOSITE, false);
+ ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_COMPOSITE);
if (ibuf != NULL) {
cached_types |= SEQ_CACHE_STORE_COMPOSITE;
IMB_freeImBuf(ibuf);
ibuf = NULL;
}
- ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_PREPROCESSED, false);
+ ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_PREPROCESSED);
if (ibuf != NULL) {
cached_types |= SEQ_CACHE_STORE_PREPROCESSED;
IMB_freeImBuf(ibuf);
ibuf = NULL;
}
- ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_RAW, false);
+ ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_RAW);
if (ibuf != NULL) {
cached_types |= SEQ_CACHE_STORE_RAW;
IMB_freeImBuf(ibuf);
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index 0ab2a67e560..b564ecd3f36 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -762,14 +762,14 @@ static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context,
/* Proxies and effect strips are not stored in cache. */
if (!is_proxy_image && (seq->type & SEQ_TYPE_EFFECT) == 0) {
- seq_cache_put(context, seq, timeline_frame, SEQ_CACHE_STORE_RAW, ibuf, false);
+ seq_cache_put(context, seq, timeline_frame, SEQ_CACHE_STORE_RAW, ibuf);
}
if (use_preprocess) {
ibuf = input_preprocess(context, seq, timeline_frame, ibuf, is_proxy_image);
}
- seq_cache_put(context, seq, timeline_frame, SEQ_CACHE_STORE_PREPROCESSED, ibuf, false);
+ seq_cache_put(context, seq, timeline_frame, SEQ_CACHE_STORE_PREPROCESSED, ibuf);
return ibuf;
}
@@ -1637,8 +1637,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
}
if (view_id != context->view_id) {
- seq_cache_put(
- &localcontext, seq, timeline_frame, SEQ_CACHE_STORE_RAW, ibufs_arr[view_id], false);
+ seq_cache_put(&localcontext, seq, timeline_frame, SEQ_CACHE_STORE_RAW, ibufs_arr[view_id]);
}
RE_ReleaseResultImage(re);
@@ -1813,14 +1812,14 @@ ImBuf *seq_render_strip(const SeqRenderData *context,
bool use_preprocess = false;
bool is_proxy_image = false;
- ibuf = seq_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_PREPROCESSED, false);
+ ibuf = seq_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_PREPROCESSED);
if (ibuf != NULL) {
return ibuf;
}
/* Proxies are not stored in cache. */
if (!SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(context->preview_render_size))) {
- ibuf = seq_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_RAW, false);
+ ibuf = seq_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_RAW);
}
if (ibuf == NULL) {
@@ -1927,7 +1926,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
int early_out;
Sequence *seq = seq_arr[i];
- out = seq_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_COMPOSITE, false);
+ out = seq_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_COMPOSITE);
if (out) {
break;
@@ -1956,8 +1955,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
out = seq_render_strip_stack_apply_effect(context, seq, timeline_frame, ibuf1, ibuf2);
- seq_cache_put(
- context, seq_arr[i], timeline_frame, SEQ_CACHE_STORE_COMPOSITE, out, false);
+ seq_cache_put(context, seq_arr[i], timeline_frame, SEQ_CACHE_STORE_COMPOSITE, out);
IMB_freeImBuf(ibuf1);
IMB_freeImBuf(ibuf2);
@@ -1983,7 +1981,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
IMB_freeImBuf(ibuf2);
}
- seq_cache_put(context, seq_arr[i], timeline_frame, SEQ_CACHE_STORE_COMPOSITE, out, false);
+ seq_cache_put(context, seq_arr[i], timeline_frame, SEQ_CACHE_STORE_COMPOSITE, out);
}
return out;
@@ -2022,8 +2020,7 @@ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame,
count = seq_get_shown_sequences(seqbasep, timeline_frame, chanshown, seq_arr);
if (count) {
- out = seq_cache_get(
- context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT, false);
+ out = seq_cache_get(context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT);
}
seq_cache_free_temp_cache(context->scene, context->task_id, timeline_frame);
@@ -2033,12 +2030,11 @@ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame,
out = seq_render_strip_stack(context, &state, seqbasep, timeline_frame, chanshown);
if (context->is_prefetch_render) {
- seq_cache_put(
- context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT, out, false);
+ seq_cache_put(context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT, out);
}
else {
seq_cache_put_if_possible(
- context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT, out, false);
+ context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT, out);
}
BLI_mutex_unlock(&seq_render_mutex);
}
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 540896664da..69177f39c04 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -685,6 +685,7 @@ ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid);
void WM_drag_add_local_ID(struct wmDrag *drag, struct ID *id, struct ID *from_parent);
struct ID *WM_drag_get_local_ID(const struct wmDrag *drag, short idcode);
struct ID *WM_drag_get_local_ID_from_event(const struct wmEvent *event, short idcode);
+bool WM_drag_is_ID_type(const struct wmDrag *drag, int idcode);
struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode);
struct ID *WM_drag_get_local_ID_or_import_from_asset(const struct wmDrag *drag, int idcode);
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index 70ddae4d724..cf1a7628267 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -301,7 +301,7 @@ void WM_gizmomap_draw(struct wmGizmoMap *gzmap,
void WM_gizmomap_add_handlers(struct ARegion *region, struct wmGizmoMap *gzmap);
bool WM_gizmomap_select_all(struct bContext *C, struct wmGizmoMap *gzmap, const int action);
bool WM_gizmomap_cursor_set(const struct wmGizmoMap *gzmap, struct wmWindow *win);
-void WM_gizmomap_message_subscribe(struct bContext *C,
+void WM_gizmomap_message_subscribe(const struct bContext *C,
struct wmGizmoMap *gzmap,
struct ARegion *region,
struct wmMsgBus *mbus);
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
index 8f84c02be12..fd7f9c2de7c 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
@@ -371,6 +371,14 @@ typedef struct wmGizmoType {
*/
wmGizmoFnMatrixBasisGet matrix_basis_get;
+ /**
+ * Returns screen-space bounding box in the window space
+ * (compatible with #wmEvent.x #wmEvent.y).
+ *
+ * Used for tool-tip placement (otherwise the cursor location is used).
+ */
+ wmGizmoFnScreenBoundsGet screen_bounds_get;
+
/** Activate a gizmo state when the user clicks on it. */
wmGizmoFnInvoke invoke;
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index 479768c3536..12c6eb46c12 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -1156,7 +1156,7 @@ ListBase *wm_gizmomap_groups_get(wmGizmoMap *gzmap)
return &gzmap->groups;
}
-void WM_gizmomap_message_subscribe(bContext *C,
+void WM_gizmomap_message_subscribe(const bContext *C,
wmGizmoMap *gzmap,
ARegion *region,
struct wmMsgBus *mbus)
diff --git a/source/blender/windowmanager/gizmo/wm_gizmo_fn.h b/source/blender/windowmanager/gizmo/wm_gizmo_fn.h
index 418e848e35b..84e6308223f 100644
--- a/source/blender/windowmanager/gizmo/wm_gizmo_fn.h
+++ b/source/blender/windowmanager/gizmo/wm_gizmo_fn.h
@@ -62,6 +62,9 @@ typedef void (*wmGizmoFnMatrixBasisGet)(const struct wmGizmo *, float[4][4]);
typedef int (*wmGizmoFnInvoke)(struct bContext *, struct wmGizmo *, const struct wmEvent *);
typedef void (*wmGizmoFnExit)(struct bContext *, struct wmGizmo *, const bool);
typedef int (*wmGizmoFnCursorGet)(struct wmGizmo *);
+typedef void (*wmGizmoFnScreenBoundsGet)(struct bContext *,
+ struct wmGizmo *,
+ rcti *r_bounding_box);
typedef void (*wmGizmoFnSelectRefresh)(struct wmGizmo *);
typedef void (*wmGizmoFnFree)(struct wmGizmo *);
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index a10284e9740..549b59e9e1d 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -279,6 +279,8 @@ IDTypeInfo IDType_ID_WM = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
+
+ .lib_override_apply_post = NULL,
};
#define MAX_OP_REGISTERED 32
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index d50516dfab2..e32552063af 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -246,8 +246,7 @@ void WM_cursor_wait(bool val)
void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
{
/* Only grab cursor when not running debug.
- * It helps not to get a stuck WM when hitting a breakpoint
- * */
+ * It helps not to get a stuck WM when hitting a break-point. */
GHOST_TGrabCursorMode mode = GHOST_kGrabNormal;
GHOST_TAxisFlag mode_axis = GHOST_kAxisX | GHOST_kGrabAxisY;
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 08f60fef0d2..6fdcbab889c 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -225,7 +225,8 @@ static const char *dropbox_active(bContext *C,
if (handler->dropboxes) {
LISTBASE_FOREACH (wmDropBox *, drop, handler->dropboxes) {
const char *tooltip = NULL;
- if (drop->poll(C, drag, event, &tooltip)) {
+ if (drop->poll(C, drag, event, &tooltip) &&
+ WM_operator_poll_context(C, drop->ot, drop->opcontext)) {
/* XXX Doing translation here might not be ideal, but later we have no more
* access to ot (and hence op context)... */
return (tooltip) ? tooltip : WM_operatortype_name(drop->ot, drop->ptr);
@@ -353,6 +354,14 @@ ID *WM_drag_get_local_ID_from_event(const wmEvent *event, short idcode)
return WM_drag_get_local_ID(lb->first, idcode);
}
+/**
+ * Check if the drag data is either a local ID or an external ID asset of type \a idcode.
+ */
+bool WM_drag_is_ID_type(const wmDrag *drag, int idcode)
+{
+ return WM_drag_get_local_ID(drag, idcode) || WM_drag_get_asset_data(drag, idcode);
+}
+
wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode)
{
if (drag->type != WM_DRAG_ASSET) {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 859336d0338..17f4713ff96 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -543,13 +543,33 @@ void wm_event_do_notifiers(bContext *C)
ED_screen_do_listen(C, note);
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
- ED_region_do_listen(win, NULL, region, note, scene);
+ wmRegionListenerParams region_params = {
+ .window = win,
+ .area = NULL,
+ .region = region,
+ .scene = scene,
+ .notifier = note,
+ };
+ ED_region_do_listen(&region_params);
}
ED_screen_areas_iter (win, screen, area) {
- ED_area_do_listen(win, area, note, scene);
+ wmSpaceTypeListenerParams area_params = {
+ .window = win,
+ .area = area,
+ .notifier = note,
+ .scene = scene,
+ };
+ ED_area_do_listen(&area_params);
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- ED_region_do_listen(win, area, region, note, scene);
+ wmRegionListenerParams region_params = {
+ .window = win,
+ .area = area,
+ .region = region,
+ .scene = scene,
+ .notifier = note,
+ };
+ ED_region_do_listen(&region_params);
}
}
}
@@ -2788,8 +2808,10 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
LISTBASE_FOREACH (wmDrag *, drag, lb) {
const char *tooltip = NULL;
if (drop->poll(C, drag, event, &tooltip)) {
- /* Optionally copy drag information to operator properties. */
- if (drop->copy) {
+ /* Optionally copy drag information to operator properties. Don't call it if the
+ * operator fails anyway, it might do more than just set properties (e.g.
+ * typically import an asset). */
+ if (drop->copy && WM_operator_poll_context(C, drop->ot, drop->opcontext)) {
drop->copy(drag, drop);
}
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 8dfe26fbf79..aeab1ee6fca 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -284,15 +284,15 @@ void WM_operator_properties_select_action_simple(wmOperatorType *ot,
*/
void WM_operator_properties_select_random(wmOperatorType *ot)
{
- RNA_def_float_percentage(ot->srna,
- "percent",
- 50.0f,
- 0.0f,
- 100.0f,
- "Percent",
- "Percentage of objects to select randomly",
- 0.0f,
- 100.0f);
+ RNA_def_float_factor(ot->srna,
+ "ratio",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Ratio",
+ "Portion of items to select randomly",
+ 0.f,
+ 1.0f);
RNA_def_int(ot->srna,
"seed",
0,
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index 4c4fd2b1a8e..0e57a92b685 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -424,9 +424,8 @@ static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event)
wm_event_free_handler(&handler->head);
}
- /* if operator is blocking, grab cursor
- * This may end up grabbing twice, but we don't care.
- * */
+ /* If operator is blocking, grab cursor.
+ * This may end up grabbing twice, but we don't care. */
if (op->opm->type->flag & OPTYPE_BLOCKING) {
int bounds[4] = {-1, -1, -1, -1};
int wrap = WM_CURSOR_WRAP_NONE;
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 6836cbec18c..b75a6a624d5 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -988,9 +988,9 @@ static const char arg_handle_debug_mode_generic_set_doc_depsgraph_no_threads[] =
static const char arg_handle_debug_mode_generic_set_doc_depsgraph_pretty[] =
"\n\t"
"Enable colors for dependency graph debug messages.";
-static const char arg_handle_debug_mode_generic_set_doc_gpumem[] =
+static const char arg_handle_debug_mode_generic_set_doc_gpu_force_workarounds[] =
"\n\t"
- "Enable GPU memory stats in status bar.";
+ "Enable workarounds for typical GPU issues and disable all GPU extensions.";
static int arg_handle_debug_mode_generic_set(int UNUSED(argc),
const char **UNUSED(argv),
@@ -2170,18 +2170,8 @@ void main_args_setup(bContext *C, bArgs *ba)
(void *)G_DEBUG_DEPSGRAPH_UUID);
BLI_args_add(ba,
NULL,
- "--debug-gpumem",
- CB_EX(arg_handle_debug_mode_generic_set, gpumem),
- (void *)G_DEBUG_GPU_MEM);
- BLI_args_add(ba,
- NULL,
- "--debug-gpu-shaders",
- CB_EX(arg_handle_debug_mode_generic_set, gpumem),
- (void *)G_DEBUG_GPU_SHADERS);
- BLI_args_add(ba,
- NULL,
"--debug-gpu-force-workarounds",
- CB_EX(arg_handle_debug_mode_generic_set, gpumem),
+ CB_EX(arg_handle_debug_mode_generic_set, gpu_force_workarounds),
(void *)G_DEBUG_GPU_FORCE_WORKAROUNDS);
BLI_args_add(ba, NULL, "--debug-exit-on-error", CB(arg_handle_debug_exit_on_error), NULL);